2010-07-31 51 views
28

在PHP中有一种方法可以从字符串中提供唯一的哈希,但哈希是由数字组成的?php:数字只是哈希?

例如:

return md5(234); // returns 098f6bcd4621d373cade4e832627b4f6 

,但我需要

return numhash(234); // returns 00978902923102372190 
(20 numbers only) 

这里的问题是,我想散列短。

编辑: 好的,让我解释一下这里的背景故事。 我有一个网站,每个注册人都有一个身份证,我也需要一个身份证供这个人使用和交换(因此它不能太长),到目前为止ID号是00001,00002,00003等...

  1. 这使得一些人看起来更重要
  2. 这表明我不想透露申请信息。

要确定点1和2,我需要“隐藏”数字,同时保持唯一性。

回答

56

PHP中的MD5或SHA1哈希会返回一个十六进制数字,因此您只需转换基数即可。 PHP有一个功能,可以为你做这个:

$bignum = hexdec(md5("test")); 

$bignum = hexdec(sha1("test")); 

PHP Manual for hexdec

既然你要在有限的尺寸号码,然后你可以用模块化的分工把它放在一个你想要的范围。

$smallnum = $bignum % [put your upper bound here] 

编辑

正如在评论中指出的Artefacto,使用这种方法会导致超出PHP的整数的最大尺寸的数量,并经过模块化分工的结果将始终为0 。然而,包含前16个字符的散列的子字符串没有这个问题。用于计算初始大数字的修改版本:

$bignum = hexdec(substr(sha1("test"), 0, 15)); 
+0

如果我将“测试”变量限制为一组有限的数字,该怎么办? 会有减少散列大小的方法吗? – 2010-07-31 19:27:55

+0

@YuriKolovsky - 最终的散列大小将取决于您在第二步中用于模块化分区的任何上限。例如,如果你想让你的哈希长度都是5位数,那么你可以使用'$ smallnum = $ bignum%99999'。无论放入初始MD5或SHA1哈希值如何,这都可以工作。 – derekerdmann 2010-07-31 19:33:18

+0

@derekerdmann这看起来就像我需要的东西:D – 2010-07-31 19:35:06

1

首先,md5基本上是妥协的,所以你不应该用它来做任何事情,除非非关键哈希。 PHP5具有hash()功能,请参阅http://www.php.net/manual/en/function.hash.php

将最后一个参数设置为true将为您提供一串二进制数据。或者,您可以将生成的十六进制散列分成2个字符片段并将它们分别转换为整数,但我认为这会比较慢。

+1

速度不是一个问题,我唯一的问题是,数字散列是独特的,不可笑的长。 – 2010-07-31 19:25:21

14

您可以试试crc32()。请参阅文档:http://php.net/manual/en/function.crc32.php

$checksum = crc32("The quick brown fox jumped over the lazy dog."); 
printf("%u\n", $checksum); // prints 2191738434 

随着中说,crc应该用来validate the integrity of data

3

有一些很好的答案,但对我来说这些方法似乎很愚蠢。
他们首先强制php创建一个十六进制数字,然后在BigInteger中将其转换回来(hexdec),然后将其减少为多个字母......这是很多工作!

相反何不

阅读散列作为二进制:

$binhash = md5('[input value]', true); 

然后使用

$numhash = unpack('N2', $binhash); //- or 'V2' for little endian 

施放此为两个INT S($numhash是两个元件的阵列)。现在只需使用AND操作即可减少数字中的位数。例如:

$result = $numhash[1] & 0x000FFFFF; //- to get numbers between 0 and 1048575 

但是要警告碰撞!减少数字意味着增加具有相同输出的两个不同[输入值]的概率。

我认为更好的方法是使用带有Bijectiv函数的“ID-Crypting”。所以不会发生碰撞!对于最简单的一种只需使用一个Affine_cipher

实施例与最大输入值范围从0到25:

function numcrypt($a) 
{ 
    return ($a * 15) % 26; 
} 

function unnumcrypt($a) 
{ 
    return ($a * 7) % 26; 
} 

输出:

numcrypt(1) : 15 
numcrypt(2) : 4 
numcrypt(3) : 19 

unnumcrypt(15) : 1 
unnumcrypt(4) : 2 
unnumcrypt(19) : 3 

例如

$id = unnumcrypt($_GET('userid')); 

... do something with the ID ... 

echo '<a href="do.php?userid='. numcrypt($id) . '"> go </a>'; 
当然

这是不是安全的,但如果没有人知道使用您的加密方法则没有安全原因,那么这种方式速度更快,安全碰撞。

+0

我不明白如何使用你的第二个解决方案来获得一个数字散列,你能详细说明一下吗? – 2014-05-15 15:06:59

+0

它不是一个散列,但你可以使用例如河豚将您的身份证盖上一个独特的“随机”号码。用户则无法计算“ID + 1”。最后你可以使用它作为代理方法:内部你的APP使用“ID:1,2,3,...”,但是你提供了加密号码给你的用户。许多大方都这样做:例如google-cookies是加密的ID – Thomas 2014-05-15 15:20:52

+0

你如何反转(或打包())'unpack('N2',...)'数组? – Xeoncross 2015-12-28 17:45:05

5

的切断散列的问题是碰撞,以避免它尝试:

return hexdec(crc32("Hello World")); 

crc32()

生成32位的循环冗余校验和多项式长度的 海峡。这通常用于验证正在传输的数据的完整性 。

这给了我们一个32位的整数,在32位安装中为负数,或者在64位中为正数。这个整数可以像数据库中的ID一样存储。这没有碰撞问题,因为它适合32位变量,一旦你用hexdec()函数将它转换成十进制数。

0

尝试hashid
它将数字散列成您可以定义的格式。格式包括多少个字符,以及包含什么字符。
例如:
$ hashids-> encode(1);
将返回“28630”取决于你的格式,