Tim*_*nen 38 php hash md5 numbers short
在php中有一种方法可以从字符串中提供唯一的哈希值,但哈希值只是由数字组成的?
例:
return md5(234); // returns 098f6bcd4621d373cade4e832627b4f6
Run Code Online (Sandbox Code Playgroud)
但是我需要
return numhash(234); // returns 00978902923102372190
(20 numbers only)
Run Code Online (Sandbox Code Playgroud)
这里的问题是我希望哈希很短.
编辑: 好的,让我来解释这里的背景故事.我有一个网站,每个注册人都有一个ID,我也需要一个ID供该人使用和交换(因此不能太长),到目前为止ID编号为00001,00002,00003等. ..
要修复第1点和第2点,我需要"隐藏"数字,同时保持其唯一性.
数字哈希函数基于/sf/answers/1657590931/的代码
/**
* 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
Run Code Online (Sandbox Code Playgroud)
der*_*ann 62
PHP中的MD5或SHA1哈希返回十六进制数,因此您需要做的就是转换碱基.PHP有一个可以为您执行此操作的功能:
$bignum = hexdec( md5("test") );
Run Code Online (Sandbox Code Playgroud)
要么
$bignum = hexdec( sha1("test") );
Run Code Online (Sandbox Code Playgroud)
由于您需要有限大小的数字,因此您可以使用模块化除法将其放在您想要的范围内.
$smallnum = $bignum % [put your upper bound here]
Run Code Online (Sandbox Code Playgroud)
编辑
正如Artefacto在评论中所指出的那样,使用这种方法将导致数字超出PHP中Integer的最大大小,并且模块化除法后的结果将始终为0.但是,采用包含前16个的散列的子字符串字符没有这个问题.用于计算初始大数的修订版本:
$bignum = hexdec( substr(sha1("test"), 0, 15) );
Run Code Online (Sandbox Code Playgroud)
Dav*_*nco 16
你可以试试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
Run Code Online (Sandbox Code Playgroud)
据说,crc应该只用于validate the integrity of data.
Tho*_*mas 12
有一些很好的答案,但对我来说,这些方法似乎很愚蠢.
他们首先强制php创建一个十六进制数,然后hexdec在BigInteger中将其转换为back(),然后将其剪切为多个字母......这是很多工作!
相反,为什么不
将哈希值读为二进制:
$binhash = md5('[input value]', true);
Run Code Online (Sandbox Code Playgroud)
然后使用
$numhash = unpack('N2', $binhash); //- or 'V2' for little endian
Run Code Online (Sandbox Code Playgroud)
将其转换为两个INTs($numhash是两个元素的数组).现在,您只需使用AND操作即可减少数字中的位数.例如:
$result = $numhash[1] & 0x000FFFFF; //- to get numbers between 0 and 1048575
Run Code Online (Sandbox Code Playgroud)
但要注意碰撞!减少数量意味着增加具有相同输出的两个不同[输入值]的概率.
我认为更好的方法是使用具有Bijectiv功能的"ID-Crypting".所以不会发生碰撞!对于最简单的类型,只需使用Affine_cipher
最大输入值范围为0到25的示例:
function numcrypt($a)
{
return ($a * 15) % 26;
}
function unnumcrypt($a)
{
return ($a * 7) % 26;
}
Run Code Online (Sandbox Code Playgroud)
输出:
numcrypt(1) : 15
numcrypt(2) : 4
numcrypt(3) : 19
unnumcrypt(15) : 1
unnumcrypt(4) : 2
unnumcrypt(19) : 3
Run Code Online (Sandbox Code Playgroud)
例如
$id = unnumcrypt($_GET('userid'));
... do something with the ID ...
echo '<a href="do.php?userid='. numcrypt($id) . '"> go </a>';
Run Code Online (Sandbox Code Playgroud)
当然这不安全,但是如果没有人知道用于加密的方法,那么没有安全原因那么这种方式更快且碰撞安全.
切断哈希的问题是冲突,以避免它尝试:
return hexdec(crc32("Hello World"));
Run Code Online (Sandbox Code Playgroud)
的crc32():
生成str的32位长度的循环冗余校验和多项式.这通常用于验证传输数据的完整性.
这给我们一个32位的整数,32位安装的负数,或64位的正数.此整数可以像数据库中的ID一样存储.这没有碰撞问题,因为它适合32位变量,一旦你用hexdec()函数将其转换为十进制.