PHPでjson_encode/json_decodeする例
Webサイトを運営していると、運営サイト上のデータを取得して、ローカルで処理したいケースがあります。
そんなときに便利なPHPのjson_encodeとjson_decodeの話。
事例
例えば、登録型のリンク集を運営している場合。
- 運営サイト(レンタルサーバー)の登録フォームで、訪問者がサイト情報を登録
- サーバー上ではChromeが起動できないため、ローカルのWindows PCでChromeを起動してスクリーンショットを撮る
2番目のChromeでスクリーンショットを、というのは「コマンドラインでWebサイトのスクリーンショットを撮る簡単な方法」で紹介したHeadless Chromeのことです。
このケースの場合、サーバー上でHeadless Chromeを動かせないので、ローカルで実行するわけですね。
サーバーが共有のレンタルサーバーではなく、VPSだったりする場合は自前でNode.jsやpuppeteerを入れてHeadless Chromeが動くようにしても良いのですけれど、まぁ今回はレンタルサーバーを想定ということで。
サンプルコード
サーバー側がCentOS等で動いている一般的なレンタルサーバー、ローカル側はWindows PCで動いている運営管理用のWebサーバーとします。双方がWebサーバーなので、要するにサーバー間の通信ですね。
通信方法は色々あって、それこそソケット通信をしても良いし、流行り(?)のXMLでやりとりしても良いし、レガシーなCSVでやりとりするのもアリでしょう。
でも今回はJSONを使います。なぜならJSONが一番らくちんでコードが見やすいと信じているから!
サーバー側でJSONを生成する例
サーバー上のDBにはsiteというテーブルがあって、serial型のseqとURLが入った列があるという想定です。
<?php
//変数初期化
$site_array = array();
//PDO設定
$pdo_dsn = 'mysql:host=localhost;dbname=test;charset=utf8;';
$pdo_user = 'root';
$pdo_pass = '********';
$pdo_option = array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
PDO::ATTR_STRINGIFY_FETCHES => false
);
//データベース接続
$pdo = new PDO($pdo_dsn, $pdo_user, $pdo_pass, $pdo_option);
//SQL発行
$query = "SELECT seq,url FROM site ORDER BY seq DESC LIMIT 10";
$stmt = $pdo->query($query);
while ($row = $stmt->fetch()) {
$filename = './cache/site_'.$row['seq'].'.png';
if (!file_exists($filename)) {
$site_array[] = $row;
}
}
echo json_encode($site_array, JSON_UNESCAPED_UNICODE);
?>
siteテーブルを最大10件読み込み、ひとつひとつキャッシュ用のPNGがあるかないかチェックしています。キャッシュがなければSSを撮る必要があるため、$site_array配列に情報を格納、という流れ。
CSVだったら、seqとURLを並べて出力するところですが、CSVって区切り記号に気を使うじゃないですか。
あまり見ませんけど、URLにカンマを使うことも出来ますし。
なので、あえてカンマ以外の区切り記号を使ってCSVを使っている例も見かけますけど、ともかく、区切り記号に気を使わなければいけないのは事実ですよね。
一方で、JSONなら連想配列をまとめてシリアライズしてくれるのが素敵。
json_encode関数のオプションでJSON_UNESCAPED_UNICODEを指定していますが、これはマルチバイトのUnicode文字をそのままの形式で出力する、という意味です。デフォルトでは\uXXXXみたいにエスケープされてサイズが大きくなってしまうので、どうせ受け取り側もUTF-8で処理するとわかっているのならあえてエスケープする必要もないだろう、と。
ローカル側でJSONを受け取る例
<?php
//サイト一覧を取得
$json = file_get_contents('https://example.com/site_json.php');
$site_array = json_decode($json, true);
foreach ($site_array as $site) {
$filename = 'site_'.$site['seq'].'.png';
//chromeでSSを取得
$command = '"C:/Program Files (x86)/Google/Chrome/Application/chrome.exe" --headless --disable-gpu --screenshot='.$filename.' '.$site['url'].' 2>&1';
$output = null;
$ret = false;
exec($command, $output, $ret);
//実際はこのへんでSSのサムネイルを作成する処理を書いたりする
}
?>
先程書いたサーバー側の処理は https://example.com/site_json.php に保存されていると仮定しています。
file_get_contentsでJSONを読み込み、json_decodeで連想配列に戻すだけなので簡単らくちんですね。
json_decodeの2番目の引数に true と指定しているのは「連想配列にしてね」という意味です。これがないとただの配列になってしまうため、seqやurl等の添字が使えません。
あと、サンプルなので$filenameには相対パスを入れていますが、実際は絶対パス指定したほうが良いでしょう。Chromeから見てのパスになるので。
まとめ
ここまでで、下記の処理が完了しました。
- 運営サーバーで登録されたサイト情報の一覧を取得
- 最近登録された一覧からそれぞれのサイトのスクリーンショットを取得
あとは出来上がったPNGをアップロードして完了ですね。
アップロードする処理のサンプルも需要あるかなぁ。
うちのブログでは下記のとおりDLする処理ばかり紹介してた気がしますね。
これの逆をするだけなので、あまり必要ない気もしますが、アップロード処理についてはまた機会があれば書こうと思います。