PHPでJSONを扱う
JSONってなに?
JSON(JavaScript Object Notation)は、テキストフォーマットの一種です。シンプルで
開発者が理解しやすい構造をしており、コンピュータにとっては高速で処理しやすいというすぐれもの。
WebAPIなどを使って引っ張ってくる形式のファイルはCSV、XML、JSONのうちどれかですが、
最近の主流はJSON。構造がJavaScriptの連想配列と似ている(というかそのまま?)ので、はじめて
見る人でも理解しやすい。
PHPでJSON処理
下記のようなjsonファイルを用意しました(test.json)。ゲームなんかで使えそうな タイプです。
{ "id" : 24, "name" : "勇者A", "status" : { "hp" : 175, "mp" : 50 }, "item" : { "money" : 25000, "sword" : [ { "name" : "錆びた剣", "atk_point" : 50 }, { "name" : "ライトセーバー", "atk_point" : 350 } ] } }
これをPHPで処理します。具体的には下のコードを参照してください。
<?php $pass = "test.json"; $json = file_get_contents($pass); if (!empty($json)) { $json = mb_convert_encoding($json, 'UTF8', 'ASCII,JIS,UTF-8,EUC-JP,SJIS-WIN'); // 連想配列として扱いたい場合は、第2引数にtrueを渡す $obj = json_decode($json); } ?> <!DOCTYPE html> <html lang="ja"> <head> <title>TestJSON</title> <meta charset="utf-8"> </head> <body> <p>ID: <?=$obj->id?></p> <p>名前: <?=$obj->name?></p> <p>HP: <?=$obj->status->hp?></p> <p>MP: <?=$obj->status->mp?></p> <p>所持金: <?=$obj->item->money?></p> <?php foreach ($obj->item->sword as $val): ?> <p>剣の名前: <?=$val->name?></p> <p>剣の攻撃力: <?=$val->atk_point?></p> <?php endforeach; ?> </body> </html>
WebAPIなんかを利用する場合は$passの部分にURLを書きます。今回はなるべくシンプルにした かったのでこのようなコードになりました。コメントアウトにもあるとおり、連想配列として扱いたい場合、 json_decode()の引数にtrueを渡してやります。 僕はオブジェクトとして扱う方が好きなので 今回は使っていません。
$ary = json_decode($json, true);
説明するまでもないですが、これでjsonの内容がすべて出力されます。
パスワードをデータベースに保存するときは、一緒に塩を入れよう
セキュアに保存する -> 漏れた場合を想定する
データベース(以下DB)にパスワードを保存するとき、そのまま
(平文で)保存してはいけません。データが漏れた場合に、パスワードが
見た瞬間わかってしまうからです。
パスワードを保存する場合、暗号化してからDBへインサートします。
実装例
手法は多種多様ですが、ここではSALTを使って暗号化
してみたいと思います。PHP + MySQLでの想定です。(ちなみにPDO)
SALTはランダムな文字列で、各ユーザごとにそれぞれ異なる
ものを用意します。
<?php /* 暗号化関数 */ function saltAngo($password, $salt) { $saltPassword = crypt($password, $salt); return $saltPassword; } /* ランダムな文字列を生成 */ function mkSalt($length = 8) { return substr(str_shuffle(str_repeat('0123456789abcdefghijklmnopqrstuvwxyz', $length)), 0, $length); }
<?php /* 上記ファイルの関数をrequire_onceなどで使えるようになっているとします。 */ $user = 'hoge'; $password = 'hogehoge'; $stmt = $pdo->prepare('INSERT INTO userdata SET user = ?, password = ?, salt = ?'); // トランザクション開始 $pdo->beginTransaction(); try { $stmt->bindValue(1, $user); $salt = mkSalt(); // ランダムな文字列作成 // パスワードはsaltAngo関数で暗号化 $password = saltAngo($password, $salt); $stmt->bindValue(2, $password); $stmt->bindValue(3, $salt); // 使ったSALTもDBへ保存 $stmt->execute(); // コミット $pdo->commit(); } catch (PDOException $e) { // エラーでロールバック $pdo->rollBack(); throw $e; }
ログイン時は、DBに保存された同じSALTを使います。同じ暗号化のロジックを使用すれば、同じ結果が
戻ってくることを利用するのです。
<?php /* 実際はちゃんと無毒化しましょう */ $user = $_POST['user']; $password = $_POST['password']; $stmt = $pdo->prepare('SELECT * FROM userdata WHERE user = ?'); $stmt->bindValue(1, $user); $stmt->execute(); $row = $stmt->fetch(PDO::FETCH_ASSOC); if (!empty($row)) { $salt = $row['salt']; $password = crypt($password, $salt); // 保存時と同じSALTで復号化 // パスワードが一致しているか if ($row['password'] === $password) { echo 'ログイン完了'; } else { echo 'ユーザ名かパスワードが違います'; } } else { echo 'そのようなユーザは登録されていません'; }
ここでは説明を簡単にするため、弱い暗号化で済ませています。実際には、もっと
強いロジックを考えましょう。
strictモードで厳格なjavaScriptを書こう
strictモードとは?
近頃見られるようになった下記のような記述。javaScriptを書く際、必須になりつつあります。
(function() { 'use strict'; // 処理 })();
jsファイルの先頭に
'use strict';
と記述することにより、strictモードを 宣言することができます。strictモード下では、厳格なjavaScriptを書くことが求められるので、必然的に バグの混入を減らすことができます。
ちなみに
(function() { })();
の部分は即時関数と呼ばれ、スコープ汚染を防ぐために用いられるものです。ここではテーマの範囲外になるので 割愛します。
効果
- 暗黙的なグローバル変数の禁止
- 代入不可なプロパティへの代入の禁止
- 削除できないプロパティの削除の禁止
- 関数の引数名の重複の禁止
- 幾つかの識別子は予約語にするため使用禁止(staticとか)
- 8進数表記の禁止
- eval 変数、arguments 変数の宣言禁止
- with 禁止
etc...って感じですね。
下の6、7、8はいいとして、1から5の効果は僕としては、かなり、ありがたいと思います。
代表効果の例
strictモードには、いくつかの効果がありますが、そのうちのもっとも基本的な効果がvar
のつけ忘れを防げることです。上記の効果のうちの1.暗黙的なグローバル変数の禁止に当たる機能
です。
(function() { 'use strict'; var x = 'hello'; // ok y = 'goodnight'; // error })();
コンソールで確認すればUncaught ReferenceError: y is not defined
と注意されているはずです。ちょっとしたことですが、javaScriptは基本ゆるい言語
なので、こういうのが案外、助けになったりします。
注意点
- IE10以下ではサポートされていない
- 先頭以外でstrictを宣言しても strict モードにならない
1はそのままの意味です。Internet Explorerは昔からjavaScriptと 相性が悪いのです。
2は下記のコードを見てもらうのが早いです。
(function() { var x = 'hello'; 'use strict'; y = 'goodnight'; // エラー吐かない // 両方の変数がコンソールに出力されてしまう! console.log(x); console.log(y); })();