php:数字只哈希?

时间:2010-07-31 19:15:23

标签: php hash md5 numbers short

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

示例:

return md5(234); // returns 098f6bcd4621d373cade4e832627b4f6

但我需要

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

这里的问题是我希望哈希很短。

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

  1. 这使得一些人看起来更重要
  2. 这显示了我不想透露的应用信息。
  3. 要修复第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
    

7 个答案:

答案 0 :(得分:62)

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中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。