ppBlogバージョン1.7.7から採用している機能のひとつに、コメント通知のメールからダイレクトでログイン出来てコメント返信できるというのがあります。その際に、リンクのURLに付加する文字列が今いちランダムになっていないので、ちょっとアルゴリズムの見直しをしてみました。時限性を持たせるために、UNIXのタイムスタンプから生成したハッシュをリンクのURLに付加しているのですが、タイムスタンプをチェックしたいので、復元可能なものであることが必要です(一方向で良ければ、sha1関数 を使えば良いけどニーズに合わない)。
単純に、UNIXのタイムスタンプをppBlogで用意している暗号化関数my_encrypt()に通すと、タイムスタンプの性質上、最後数桁しか変化せず、それに対応して生成されたハッシュも下数桁しか変化しません。まぁ、これはmy_encrypt()の性能の問題なんですが、この部分はそんな高性能でなくてよいし、過去の資産との互換性も考えると my_encrypt()はいじりたくないです。
$unix_time1 = 1234560000; // 10桁のUNIXタイムスタンプ $unix_time2 = 1234567890; // 上と下4桁が違うだけ echo my_encrypt($unix_time1); // 結果は、VwoLV1MOAwhVBg echo my_encrypt($unix_time2); // 結果は、VwoLV1MOBABcBg
こんな感じでえらく似通った文字列になる なので、このタイムスタンプを逆順にして更に基数変換すればよいかなと。逆順にすれば、大きく数値が変動します。そこで、文字列を逆順にする関数はないかstr_reverseという関数名で探してみましたがなさそうです。なので、
$unix_time_reverse = join("", array_reverse(preg_split("//", time())));
という力技で暫くローカルのテスト環境で動かしていたんですが、いやきっとあるはずだと、もう一度マニュアルを探してみたらありました。
$unix_time_reverse = strrev(time());
strrev という名前でしたか・・・。
実は、単に逆順にしただけでは、my_encrypt()のアルゴリズムからしてそう大きな変化は望めないので、更に base_convert() 関数を利用して10進数から2進数に変換します。decbin でも行けるかなと思ったんですが、扱える最大の数が10 進数の4294967295とのことで、これは使えない。
$unix_time_binary = base_convert(strrev(time()), 10, 2); // 10進数を2進数に変換
これで最初に挙げた例だと、
$encoded1 = my_encrypt(base_convert(strrev("1234560000"), 10, 2)); // 結果は、VwgIUlcJAglUBgEJU1RUUgdRVAk $encoded2 = my_encrypt(base_convert(strrev("1234567890"), 10, 2)); // 結果は、VwkJU1cIAglVBwEJU1VVUgZRVQgJVgIEVFcGAwhT $encoded3 = my_encrypt(base_convert(strrev("1235064688"), 10, 2)); // 別の例 // 結果は、VwgIU1YJAwhVBgAJUlRUUgZQVAgIVgMFVVYHAwhSUAdWCQ
まぁ、最初に比べるとだいぶマシかなと思います。さて、この復元ですが、逆の操作をするだけです。
$decoded = strrev(sprintf("%010s", base_convert(my_decrypt($encoded1), 2, 10))); // この場合は、1234560000 を返す
これで、元の10桁のタイムスタンプを取得できます。ひとつ注意する点は、順序を逆にした文字列を戻す際に、元のタイムスタンプによっては逆順にした文字列の先頭がゼロになる場合があるということです(上の例だと反転した0000654321は654321と解釈される)。なので、sprintf 関数を用いて、ゼロで10桁になるように埋め合わせをしておきます。
sprintf("%010s", "654321"); // この結果は、0000654321
実際の実装(?)としては、これらとsha1関数を組み合わせたりして、長い文字列を生成してます。
Comments