前文
どういうわけか、私の会社は、PHPで書かれたフォーラムをJavaで書かれた従業員管理システムと統合することにしました。 この場合の統合とは、システム内のデータを変更した場合に、フォーラムで従業員のアカウントを更新することです。 そして、彼らはこのビジネスを私(PHPの部分)と私の同僚のIvan(Javaの部分)に委託しました。 小さなWeb APIを作成し、システム内の従業員データが変更された場合にAPIにアクセスし、フォーラムの従業員アカウントを更新する関数を作成します。 タスクは小さく、すべてを書き、デバッグするのに約3日かかります。 もちろん、コーディングを台無しにしたくありませんでした-姓、役職、勤務先電話、その他の従業員データには秘密はありません。 しかし、どういうわけか他の誰かがAPIを呼び出して従業員データを変更できるという事実から身を守ることが必要でした。 マジックフレーズを使用してメッセージに署名することが決定されました。 魔法のフレーズとして、MD5(ログイン+位置+塩)を取ることに決めました。塩は特定の定数文字列です。 これをすべて実装し、テストを開始しました。PHPの一部の従業員について計算されたMD5は、Javaで記述されたシステムの同じ従業員について計算されたものと一致しませんでした。 両側のデータはUTF8でした。 そして、私は問題が何であるかを理解することにしました。
問題の声明
指定: MD5ハッシュを取得する必要があるUTF8エンコード文字列。
必要: JavaとPHPを使用して計算されたMD5ハッシュが異なる理由を判断します。
決定プロセス
マニュアルから古典的な行を取ります-「Hello world!」 UTF8エンコーディングで、PHPとJavaでハッシュを比較します。
PHPスクリプトを作成しています
まあ、すべてが簡単です。 UTF8エンコーディングでファイルを作成し(これにはメモ帳++を使用しました)、次のコードを書き込みます。
<?php header( "Content-Type: text/html; charset=UTF-8" ); $utf8string = ", !" ; echo '<pre>' .$utf8string. '</pre>' ; echo '<pre>' .md5($utf8string). '</pre>' ; ?> * This source code was highlighted with Source Code Highlighter .
<?php header( "Content-Type: text/html; charset=UTF-8" ); $utf8string = ", !" ; echo '<pre>' .$utf8string. '</pre>' ; echo '<pre>' .md5($utf8string). '</pre>' ; ?> * This source code was highlighted with Source Code Highlighter .
<?php header( "Content-Type: text/html; charset=UTF-8" ); $utf8string = ", !" ; echo '<pre>' .$utf8string. '</pre>' ; echo '<pre>' .md5($utf8string). '</pre>' ; ?> * This source code was highlighted with Source Code Highlighter .
<?php header( "Content-Type: text/html; charset=UTF-8" ); $utf8string = ", !" ; echo '<pre>' .$utf8string. '</pre>' ; echo '<pre>' .md5($utf8string). '</pre>' ; ?> * This source code was highlighted with Source Code Highlighter .
<?php header( "Content-Type: text/html; charset=UTF-8" ); $utf8string = ", !" ; echo '<pre>' .$utf8string. '</pre>' ; echo '<pre>' .md5($utf8string). '</pre>' ; ?> * This source code was highlighted with Source Code Highlighter .
<?php header( "Content-Type: text/html; charset=UTF-8" ); $utf8string = ", !" ; echo '<pre>' .$utf8string. '</pre>' ; echo '<pre>' .md5($utf8string). '</pre>' ; ?> * This source code was highlighted with Source Code Highlighter .
<?php header( "Content-Type: text/html; charset=UTF-8" ); $utf8string = ", !" ; echo '<pre>' .$utf8string. '</pre>' ; echo '<pre>' .md5($utf8string). '</pre>' ; ?> * This source code was highlighted with Source Code Highlighter .
<?php header( "Content-Type: text/html; charset=UTF-8" ); $utf8string = ", !" ; echo '<pre>' .$utf8string. '</pre>' ; echo '<pre>' .md5($utf8string). '</pre>' ; ?> * This source code was highlighted with Source Code Highlighter .
ヘッダー行( "Content-Type:text / html; charset = UTF-8"); ブラウザでエンコーディングを切り替えないようにするために追加しました(デフォルトでは、ApacheのデンバーエンコーディングからのApacheは、当然win1251です)。
ブラウザーで何が起こったのかを確認します。
こんにちは世界!
c446a2994f35689482651b7c7ba8b56c
Javaコンソールプログラムの作成
同様に、UTF8エンコーディングでファイルを作成し、次のコードを記述します。
- パブリック クラス Md5Tester {
- public static void main( String [] args)throws java.io.UnsupportedEncodingException、java.security.NoSuchAlgorithmException {
- java.io.PrintStream sysout = new java.io.PrintStream(System。out、 true 、 "UTF-8" );
- 文字列 utf8_string = "Hello world!" ;
- sysout.println(utf8_string);
- java.security.MessageDigest md5 = java.security.MessageDigest.getInstance( "MD5" );
- バイト [] md5_byte_array = md5.digest(utf8_string.getBytes());
- 文字列 md5_string = 新しい 文字列 (md5_byte_array);
- sysout.println(md5_string);
- }
- }
*このソースコードは、 ソースコードハイライターで強調表示されました。
開始します(IntelliJ IDEAで行いました):
C:\ Sun \ SDK \ jdk \ bin \ java -Didea.launcher.port = 7552 "-Didea.launcher.bin.path = C:\ Program Files(x86)\ JetBrains \ IntelliJ IDEA 8.1.3 \ bin" - Dfile.encoding = UTF-8 ...
こんにちは世界!
F O5h e| { l
(起動ラインで
-Dfile.encoding = UTF-8の後に
来るものはすべて、例を詰まらせないようにドロップしました)。
ご覧のとおり、md5ハッシュはコンソールに表示されますが、16進形式では表示されません。 最初のアイデアは、BigIntegerを使用して16進数の文字列を取得することです。
- ...
- java.math.BigInteger md5_biginteger = new java.math.BigInteger(1、md5_byte_array);
- sysout.println(md5_biginteger.toString(16));
*このソースコードは、 ソースコードハイライターで強調表示されました。
結果:
こんにちは世界!
c446a2994f35689482651b7c7ba8b56c
欲しいものを手に入れたようです。 ただし、急いで他の行のハッシュを比較しないでください。 ハッシュの先頭に0が含まれる行を取得します: "rbablord5" 私たちはチェックします:
rbablord5
9736a8436e10bf1991927f2ffc76c12
一方、正しいハッシュが好きです:
0 9736a8436e10bf1991927f2ffc76c12。 注目すべきは、このようなエラーは非常に一般的であり、かつてはMySQLでも発生したことでした(トラッカー
bugs.mysql.com/bug.php?id=27623でバグレポートを見つけました)。 それから、私は明らかに車輪を再発明していることを知り、少し歩いて、
commons.apache.org / codecライブラリを見つけました。 接続することで、次のように書くことができます。
- 文字列 md5_string = DigestUtils.md5Hex(utf8_string);
*このソースコードは、 ソースコードハイライターで強調表示されました。
そして、目的の結果を取得します。 1つのmd5関数のためにプロジェクトに追加のライブラリを接続したくない場合(ライブラリにはまだ多くの有用な情報があります
。commons.apache.org/ codec / api-release / index.htmlを参照)、encodeHex関数をスパイできます。
- private static final char [] DIGITS_LOWER = { '0' 、 '1' 、 '2' 、 '3' 、 '4' 、 '5' 、 '6' 、 '7' 、 '8' 、 '9' 、 ' a ' 、 ' b ' 、 ' c ' 、 ' d ' 、 ' e ' 、 ' f ' };
- private static final char [] DIGITS_UPPER = { '0' 、 '1' 、 '2' 、 '3' 、 '4' 、 '5' 、 '6' 、 '7' 、 '8' 、 '9' 、 ' A ' 、 ' B ' 、 ' C ' 、 ' D ' 、 ' E ' 、 ' F ' };
- protected static String encodeHex( byte [] data、 char [] toDigits){
- int l = data.length;
- char [] out = new char [l << 1];
- // 2つの文字が16進値を形成します。
- for ( int i = 0、j = 0; i <l; i ++){
- out [j ++] = toDigits [(0xF0&data [i])>>> 4];
- out [j ++] = toDigits [0x0F&data [i]];
- }
- 新しい文字列を返す ( out );
- }
*このソースコードは、 ソースコードハイライターで強調表示されました。
おわりに
異なるテクノロジー/プログラミング言語を使用して2つのシステム間でデータ交換を編成する場合、注意してください。同じアルゴリズムを実装する関数が入力および出力データ形式に完全に一致するという事実に依存しないでください。 ほとんどの場合、フォーマットをドッキングする努力をする必要があります。 しかし、自転車を発明する必要はありません(私のように)、両方のシステムが非常に一般的であれば、このタスクはあなたの前に誰かによって既に解決されています。
PS Iは、残念ながら、以前にJavaシステムで使用されていたコードを失いました。 BigIntegerを備えた自転車と、あまり明確ではない(とにかく)チェックのある自転車があったことを覚えています。