JavaScript勉強会

JavaScriptの学習日記

PHPで文字列を短いハッシュ値に変える方法

データベースに長い文字列を保存するとき、主キー(データを区別する背番号)として使える短い文字列も用意できると便利です。

 

PHPの場合、どんな方法が使えるか?調べてみました。

PHP 短いハッシュ - Google 検索

 

f:id:jsstudy:20180819175454p:plain

 

CRC32を使う方法

チェック用の短いハッシュを作るサンプル。 · GitHub

 

MD5を使う方法

qiita.com

 

Hashidsライブラリーを使う方法

hashids.org

 

github.com

 

CRC32を使うと、長い文字列が8文字に変換されます。

MD5を使うと、長い文字列が32文字に変換されます。

さらに、16進数を64進数に変換すればもう少し文字数が少なくなります。

hashidsというライブラリーは便利そうでしたが、可逆的な圧縮は必要ないので、ややオーバースペックに感じられました。(今回は不要?)

 

CRC32の問題点

文字列が8文字と短いのが魅力的でしたが、調べてみるとちょっと問題点もありそうでした。

巡回冗長検査 - Wikipedia

CRC-32と一般に呼ばれているIEEE 802.3のCRCは1975年に定められ、イーサネットなどの各種通信やZIPやPNGなど各所に使われている。

 

一口に「CRC32」といっても、いくつか種類があって、「CRC32」と「CRC32B」では違う方式=違う文字列が生成されます。

 

(参考)

http://php.net/manual/ja/function.crc32.php

移植性を考慮した選択肢として、より汎用的な hash() を使う方法もあります。

hash("crc32b", $str) は str_pad(dechex(crc32($str)), 8, '0', STR_PAD_LEFT) と同じ文字列を返します。

PHPのhash("crc32", $str)とhash("crc32b", $str)は違う値を返します。

 

自分がどの「CRC32」を使っているか、注意して使えば問題ないはずですが、後でウッカリ間違いが生じるかもしれないので、今回はCRC32方式は不採用ということにしておきます。

 

採用案

上記の方法を参考にすると、

  1. 文字列をMD5で32文字(16進数)に変換する。
  2. 16進数を、さらに36進数や64進数に変換して短くする。

という方法が手軽で便利そうです。

 

この方法で短くした文字列(ハッシュ値)は、セキュリティーの強度がMD5と同じなので低いはずです。

  • 外部に漏れても問題ないデータ(文字列)の短縮に使う。
  • パスワードのハッシュ化などには使わない。

 

<?php
function shortMD5 ($data) {
    return strtr(rtrim(base64_encode(pack('H*', md5($data))), '='), '+/', '-_');
};

function shortCRC32 ($data) {
    return strtr(rtrim(base64_encode(pack('H*', crc32($data))), '='), '+/', '-_');
};

$before = "Hello world!";
$shortMD5 = shortMD5($before); // hvsmnRkNLIX24EaM7KQqIA
$shortCRC32 = shortCRC32($before); // RhcHZpA
?>

 

上記のようなPHPの関数を用意して「Hello world!」(13文字)を変換すると、MD5方式だと「hvsmnRkNLIX24EaM7KQqIA」(23文字)になり、CRC32方式だと「RhcHZpA」(8文字)になりました。

元の文字列が23文字以内だと、あまり恩恵が感じられませんね?w

 

http://jsstudy.hatenablog.com/entry/How-to-convert-character-strings-to-a-short-hash-value-with-PHP」(100文字)を変換すると、MD5方式だと「TEIEovH1kI0VtyG6BkT21g」(23文字)になり、CRC32方式だと「U0IIMzA」(8文字)になりました。

まあ、これぐらいなら「短縮した!」って実感が湧きますねw

 

データの総数や元文字列の長さに応じて、MD5よりもCRC32(CRC32B)を採用した方が良い場合もありそうです。

 

参考サイト

その他、参考になったサイトをメモ。

 

可逆的な圧縮が必要な場合は、どうしたらいいか?

 

service.plan-b.co.jp

 

f:id:jsstudy:20180819164538j:plain

 

いろんな圧縮方式がありますね!

上記の図を参考にすると、PHPにはZIP圧縮の関数などが用意されてるので、それらを利用すれば手軽かな。

 

「CRC32」は、どういう仕組みなのか?

 

www.slideshare.net

 

→ぶっちゃけ、特殊な割り算と。

 

何かいい方法をご存知でしたら教えてください。よろしくお願いします。m(__)m

 

 

暗号技術入門 第3版

暗号技術入門 第3版