WebEngine

だらだらと綴る技術系メモ

PHPでJSONを扱う

JSONってなに?

JSON(JavaScript Object Notation)は、テキストフォーマットの一種です。シンプルで 開発者が理解しやすい構造をしており、コンピュータにとっては高速で処理しやすいというすぐれもの。
WebAPIなどを使って引っ張ってくる形式のファイルはCSVXMLJSONのうちどれかですが、 最近の主流はJSON。構造がJavaScript連想配列と似ている(というかそのまま?)ので、はじめて 見る人でも理解しやすい。


PHPJSON処理

下記のような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() {
})();

の部分は即時関数と呼ばれ、スコープ汚染を防ぐために用いられるものです。ここではテーマの範囲外になるので 割愛します。


効果

  1. 暗黙的なグローバル変数の禁止
  2. 代入不可なプロパティへの代入の禁止
  3. 削除できないプロパティの削除の禁止
  4. 関数の引数名の重複の禁止
  5. 幾つかの識別子は予約語にするため使用禁止(staticとか)
  6. 8進数表記の禁止
  7. eval 変数、arguments 変数の宣言禁止
  8. 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は基本ゆるい言語 なので、こういうのが案外、助けになったりします。

注意点

  1. IE10以下ではサポートされていない
  2. 先頭以外でstrictを宣言しても strict モードにならない

1はそのままの意味です。Internet Explorerは昔からjavaScriptと 相性が悪いのです。

2は下記のコードを見てもらうのが早いです。

(function() {
  var x = 'hello';

  'use strict';
  y = 'goodnight'; // エラー吐かない

  // 両方の変数がコンソールに出力されてしまう!
  console.log(x);
  console.log(y);
})();

参考