在php中有一种方法可以从字符串中提供唯一的哈希值,但哈希值是仅由数字组成的吗?
示例:
return md5(234); // returns 098f6bcd4621d373cade4e832627b4f6
但我需要
return numhash(234); // returns 00978902923102372190
(20 numbers only)
这里的问题是我希望哈希很短。
修改 好的,让我来解释这里的背景故事。 我有一个网站,每个注册人都有一个ID,我也需要一个ID供该人使用和交换(因此不能太长),到目前为止ID编号为00001,00002,00003等。 ..
要修复第1点和第2点,我需要“隐藏”该数字,同时保持其唯一性。
基于https://stackoverflow.com/a/23679870/175071
代码的数字哈希函数/**
* Return a number only hash
* https://stackoverflow.com/a/23679870/175071
* @param $str
* @param null $len
* @return number
*/
public function numHash($str, $len=null)
{
$binhash = md5($str, true);
$numhash = unpack('N2', $binhash);
$hash = $numhash[1] . $numhash[2];
if($len && is_int($len)) {
$hash = substr($hash, 0, $len);
}
return $hash;
}
// Usage
numHash(234, 20); // always returns 6814430791721596451
答案 0 :(得分:62)
PHP中的MD5或SHA1哈希返回十六进制数,因此您需要做的就是转换碱基。 PHP有一个可以为您执行此操作的功能:
$bignum = hexdec( md5("test") );
或
$bignum = hexdec( sha1("test") );
由于您需要有限大小的数字,因此您可以使用模块化部门将其放在您想要的范围内。
$smallnum = $bignum % [put your upper bound here]
修改强>
正如Artefacto在评论中所指出的那样,使用这种方法会导致数字超出PHP中Integer的最大大小,并且模块化除法后的结果将始终为0.但是,采用包含散列的子字符串前16个字符没有这个问题。用于计算初始大数的修订版本:
$bignum = hexdec( substr(sha1("test"), 0, 15) );
答案 1 :(得分: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
。
答案 2 :(得分:10)
有一些好的答案,但对我来说这些方法看起来很傻
他们首先强制php创建一个十六进制数,然后在BigInteger中将其转换回来(hexdec
),然后将其剪切为多个字母......这是很多工作!
相反,为什么不
将哈希读取为二进制文件:
$binhash = md5('[input value]', true);
然后使用
$numhash = unpack('N2', $binhash); //- or 'V2' for little endian
将其转换为两个INT
s($numhash
是一个包含两个元素的数组)。现在,您只需使用AND
操作即可减少数字中的位数。 e.g:
$result = $numhash[1] & 0x000FFFFF; //- to get numbers between 0 and 1048575
但要注意碰撞!减少数量意味着增加两个不同[输入值]具有相同输出的概率。
我认为更好的方法是使用" ID-Crypting"具有Bijectiv功能。所以不会发生碰撞!对于最简单的类型,只需使用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
e.g。
$id = unnumcrypt($_GET('userid'));
... do something with the ID ...
echo '<a href="do.php?userid='. numcrypt($id) . '"> go </a>';
当然这不安全,但是如果没有人知道用于加密的方法,那么没有安全原因那么这种方式更快且碰撞安全。
答案 3 :(得分:7)
切断哈希的问题是冲突,以避免尝试:
return hexdec(crc32("Hello World"));
crc32()
:
生成32位长度的循环冗余校验和多项式 str。这通常用于验证数据的完整性 传播。
给我们一个32位的整数,32位安装为负,或64位为正。此整数可以像数据库中的ID一样存储。这没有碰撞问题,因为一旦用hexdec()
函数将其转换为十进制,它就适合32位变量。
答案 4 :(得分:1)
首先,md5基本上是受到了损害,所以除了非关键的哈希之外你不应该使用它。
PHP5具有hash()
功能,请参阅http://www.php.net/manual/en/function.hash.php。
将最后一个参数设置为true将为您提供一串二进制数据。或者,您可以将生成的十六进制哈希值拆分为2个字符的片段并将它们单独转换为整数,但我希望它会慢得多。
答案 5 :(得分:0)
试试hashid
它将数字哈希到您可以定义的格式。格式包括字符数和包含的字符数
例如:
$ hashids-&GT;编码(1);
将返回&#34; 28630&#34;取决于你的格式,
答案 6 :(得分:0)
只需在下面使用我的手动哈希方法:
将数字(例如6位数字)除以质数3,5,7。
并获取小数点后第6个值作为要使用的ID。在实际创建ID之前,请检查唯一性,如果存在冲突,请将最后一位数字增加+1,直到没有冲突。
例如。 123456给你771428
123457给您780952
123458给您790476。