代码之家  ›  专栏  ›  技术社区  ›  Timo Huovinen

php:仅数字散列?

  •  34
  • Timo Huovinen  · 技术社区  · 14 年前

    在php中,有没有一种方法可以从字符串中给出一个唯一的散列,但是散列仅仅是由数字组成的?

    return md5(234); // returns 098f6bcd4621d373cade4e832627b4f6
    

    但我需要

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

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

    1. 这让一些人看起来更重要
    2. 这将显示我不想显示的应用程序信息。

    要解决点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 回复  |  直到 6 年前
        1
  •  15
  •   Thomas    11 年前

    有一些很好的答案,但对我来说,这些方法似乎很愚蠢。
    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
    

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

    我认为更好的方法是使用双射函数的“ID加密”。所以不会发生碰撞!对于最简单的类型,只需使用 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>';
    

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

        2
  •  66
  •   derekerdmann    14 年前

    PHP中的MD5或SHA1散列返回一个十六进制数,所以您所需要做的就是转换基。PHP有一个函数可以为您实现这一点:

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

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

    PHP Manual for hexdec

    因为您需要一个有限大小的数字,所以可以使用模数除法将其置于您想要的范围内。

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

    正如artefactor在注释中指出的,使用这种方法将导致一个数字超出PHP中整数的最大大小,并且模除后的结果将始终为0。但是,获取包含前16个字符的哈希的子字符串不存在此问题。计算初始大数的修订版本:

    $bignum = hexdec( substr(sha1("test"), 0, 15) );
    
        3
  •  19
  •   David Titarenco    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 .

        4
  •  7
  •   Reynel Fals de Pedro    9 年前

    切掉散列的问题是冲突,要避免冲突,请尝试:

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

    这个 crc32() :

    这通常用于验证数据的完整性 正在传送。

    这给了我们一个32位的整数,32位为负,64位为正。这个整数可以像数据库中的ID一样存储。这不会有冲突的问题,因为它适合32位的变量,一旦你用 hexdec()

        5
  •  1
  •   tdammers    14 年前

    首先,md5基本上是折衷的,所以除了非关键散列之外,您不应该使用它。 PHP5具有 hash() 函数,请参见 http://www.php.net/manual/en/function.hash.php .

    将最后一个参数设置为true将得到一个二进制数据字符串。或者,您可以将生成的十六进制哈希值拆分为2个字符的片段,然后分别将它们转换为整数,但我希望这会慢得多。

        6
  •  0
  •   Irfandi D. Vendy    9 年前

    hashid .
    它将一个数字散列成您可以定义的格式。格式包括有多少个字符,包括什么字符。

    $hashids->编码(1);
    返回“28630”取决于您的格式,

        7
  •  0
  •   Ben    6 年前

    只需使用下面的手动哈希方法:

    并获取小数点后的前6个值作为要使用的ID。在实际创建ID之前检查唯一性,如果存在冲突,则将最后一位数字增加+1,直到无冲突为止。
    例如123456给你771428 123457给你780952