2

次のようにPHP関数をまとめました。

function keyword_hash($keyword) {
  return base_convert(substr(md5($keyword), -16), 16, 10);
}

この関数の目的は、データベースに格納できる数値ハッシュ値を生成し、それを検索に使用することです (キーワード列のインデックスを作成するのではなく)。

MySQL でのこの関数に相当するものは次のとおりです。

SELECT CONV(RIGHT(MD5('some keyword'), 16), 16, 10);

MD5 文字列が同じであること、および substr() が MySQL クエリの RIGHT() から返される値と一致することを確認しました。ただし、CONV() を実行すると、base_convert() から生成された値とは異なる値が得られます。

たとえば、usingkeyword_hash("some keyword")は 10923672322315740844 の値を生成します。ただし、usingSELECT CONV(RIGHT(MD5('some keyword'), 16), 16, 10)は 10923672322315740475 を生成し、最後の 3 つの数値が異なることを示します。

ここで何が欠けていますか?それらは同じ値を生成するべきではありませんか?

4

1 に答える 1

3

のPHPマニュアルページを見てみましたbase_convert()。次の警告があります。

base_convert()は、使用される内部の「double」または「float」型に関連するプロパティが原因で、大きな数値の精度を失う可能性があります。より具体的な情報と制限については、マニュアルの浮動小数点数のセクションを参照してください 。

コメントの後半で、誰かがこの問題の解決策をすでに見つけています(@CraigSeftonに感謝します):

function str_baseconvert($str, $frombase=10, $tobase=36) { 
    $str = trim($str); 
    if (intval($frombase) != 10) { 
        $len = strlen($str); 
        $q = 0; 
        for ($i=0; $i<$len; $i++) { 
            $r = base_convert($str[$i], $frombase, 10); 
            $q = bcadd(bcmul($q, $frombase), $r); 
        } 
    } 
    else $q = $str; 

    if (intval($tobase) != 10) { 
        $s = ''; 
        while (bccomp($q, '0', 0) > 0) { 
            $r = intval(bcmod($q, $tobase)); 
            $s = base_convert($r, 10, $tobase) . $s; 
            $q = bcdiv($q, $tobase, 0); 
        } 
    } 
    else $s = $q; 

    return $s; 
}

この関数は、整数/浮動小数点数などの代わりに文字列を使用して数値を格納するため、任意精度の数学をサポートするbc 数学ライブラリを使用します。

于 2012-10-17T17:55:54.363 に答える