何が起きたか
どこぞのAPIで取ったJSONっぽい文字列をPHPのjson_decodeに入れてみたら、NULLが返ることがあった。
試したこと1
Online JSON Viewer (http://jsonviewer.stack.hu/) にJSONをそのまま入れてみる。
残念ながら正常に変換できてしまう。JSONの構文的には問題なさそう。
試したこと2
Best Online JSON Viewer (https://codebeautify.org/jsonviewer) にも入れてみる。
何かおかしいみたいだけど、矢印の部分には何もない。
Error: Parse error on line 1:
...ventory":"1","name":"\u3010T\u30DD\u30A4
-----------------------^
Expecting 'STRING', 'NUMBER', 'NULL', 'TRUE', 'FALSE', '{', '[', got 'undefined'
試したこと3
JSON整形サービス (http://www.ctrlshift.net/jsonprettyprinter/ )に入れてみた。1
Error: Invalid \escape: line 1 column 413 (char 412)
おー、ついに具体的なヒントをゲット
答え
×(算数の掛ける記号)が**\xD7**にエスケープされていると、json_decode関数はエラーになる。json_last_error_msg()で返ってくる情報はJSON_ERROR_SYNTAXで、ほぼノーヒント状態で調べるのも大変だった。
掛ける記号をPHPのjson_encodeで変換すると**\u00d7になる。しょうがないので\xD7を\u00d7**に変えてあげたらうまくいった。
$json = str_replace('\xD7', '\u00d7',$json);
追記
\xD7だけでなく\xA7なんてのも出てきて、1つ1つ退治している場合ではなかった。\xで始まる16進数2つまでなら、全部置き換えてしまう。こっちのほうが幸せになれそう。
$json = preg_replace('/\\\\x([0-9a-f][0-9a-f])/i', '\\u00$1', $json);
教訓
リンク先を見ると、\xD7はJavascript向けのエスケープでした。つまり、Javascriptで処理するために作られたJSONを横取りしてPHPで処理しようとしたから悪いんだ。APIがJavascriptで処理する前提で返しているときは、気を付けよう。
リンク
-
2018/5/22 上記サービスは追記時点でアクセスできなくなってしまいました。 ↩