PHPで文字列を短いハッシュ値に変える方法
データベースに長い文字列を保存するとき、主キー(データを区別する背番号)として使える短い文字列も用意できると便利です。
PHPの場合、どんな方法が使えるか?調べてみました。
CRC32を使う方法
MD5を使う方法
Hashidsライブラリーを使う方法
CRC32を使うと、長い文字列が8文字に変換されます。
MD5を使うと、長い文字列が32文字に変換されます。
さらに、16進数を64進数に変換すればもう少し文字数が少なくなります。
hashidsというライブラリーは便利そうでしたが、可逆的な圧縮は必要ないので、ややオーバースペックに感じられました。(今回は不要?)
CRC32の問題点
文字列が8文字と短いのが魅力的でしたが、調べてみるとちょっと問題点もありそうでした。
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方式は不採用ということにしておきます。
採用案
上記の方法を参考にすると、
- 文字列をMD5で32文字(16進数)に変換する。
- 16進数を、さらに36進数や64進数に変換して短くする。
という方法が手軽で便利そうです。
この方法で短くした文字列(ハッシュ値)は、セキュリティーの強度がMD5と同じなので低いはずです。
- 外部に漏れても問題ないデータ(文字列)の短縮に使う。
- パスワードのハッシュ化などには使わない。
上記のような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)を採用した方が良い場合もありそうです。
参考サイト
その他、参考になったサイトをメモ。
可逆的な圧縮が必要な場合は、どうしたらいいか?
いろんな圧縮方式がありますね!
上記の図を参考にすると、PHPにはZIP圧縮の関数などが用意されてるので、それらを利用すれば手軽かな。
「CRC32」は、どういう仕組みなのか?
→ぶっちゃけ、特殊な割り算と。
何かいい方法をご存知でしたら教えてください。よろしくお願いします。m(__)m