php:数字只哈希?

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. 这揭示了我不想透露的应用信息.

要修复第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)

PHP手册hexdec

由于您需要有限大小的数字,因此您可以使用模块化除法将其放在您想要的范围内.

$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)

  • 应该补充一点,md5/sha1哈希太长,不适合php整数.调用hexdec时,您将丢失字节数.事实上,我担心因此服用模数会造成麻烦. (5认同)
  • @YuriKolovsky - 虽然很自然,使用较小的数字会增加哈希冲突的风险.由您来决定避免碰撞的重要性. (2认同)

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)

当然这不安全,但是如果没有人知道用于加密的方法,那么没有安全原因那么这种方式更快且碰撞安全.


Rey*_*dro 7

切断哈希的问题是冲突,以避免它尝试:

return  hexdec(crc32("Hello World"));
Run Code Online (Sandbox Code Playgroud)

crc32():

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

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