PHPでjson_encode/json_decodeする例

Webサイトを運営していると、運営サイト上のデータを取得して、ローカルで処理したいケースがあります。

そんなときに便利なPHPのjson_encodeとjson_decodeの話。

事例

例えば、登録型のリンク集を運営している場合。

  1. 運営サイト(レンタルサーバー)の登録フォームで、訪問者がサイト情報を登録
  2. サーバー上では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から見てのパスになるので。

まとめ

ここまでで、下記の処理が完了しました。

  1. 運営サーバーで登録されたサイト情報の一覧を取得
  2. 最近登録された一覧からそれぞれのサイトのスクリーンショットを取得

あとは出来上がったPNGをアップロードして完了ですね。

アップロードする処理のサンプルも需要あるかなぁ。

うちのブログでは下記のとおりDLする処理ばかり紹介してた気がしますね。

これの逆をするだけなので、あまり必要ない気もしますが、アップロード処理についてはまた機会があれば書こうと思います。

adsbygoogle

フォロー