PHP 定数名とメッセージはPHPのマニュアルによります。
json_decode() returns NULL
PHPは既定では不正なJSONに対して例外を投げません。json_decodeは単にNULLを返しますが、それは入力が"null"だった場合の正当な結果でもあるため、戻り値だけでは失敗と成功を区別できません。まずやるべきは、何が起きたのかをPHPに言わせることです。
JSONを貼り付けて、壊れている箇所を正確に確認する
入力
貼り付けたものがブラウザの外に出ることはありません。 connect-src の許可リストにより、これは約束ではなくブラウザによる保証になっています。 自分で確かめる
実際の原因
どれが答えになることが多いか、その順に並べています。
-
01 そもそもエラーメッセージがまだ手元にない
デコードの直後にjson_last_error_msg()を呼ぶか、JSON_THROW_ON_ERRORフラグを渡してJsonExceptionを投げさせてください。どちらもしていなければ、手探りでデバッグしていることになります。この問題に時間がかかる理由はそこにあります。
壊れる例
$data = json_decode($body, true); if ($data === null) { /* why? */ }動く例
$data = json_decode($body, true, 512, JSON_THROW_ON_ERROR); // or $data = json_decode($body, true); if (json_last_error() !== JSON_ERROR_NONE) { throw new RuntimeException(json_last_error_msg()); } -
02 ファイル先頭のUTF-8バイトオーダーマーク
PHPでは定番の落とし穴です。file_get_contentsはBOMをそのまま返し、json_decodeはそれを拒否します。先頭3バイトがEF BB BFなら取り除いてください。
-
03 不正なUTF-8。JSON_ERROR_UTF8になる
「Malformed UTF-8 characters, possibly incorrectly encoded」は、たいていデータがLatin-1のデータベースカラムから来たことを意味します。デコード前にmb_convert_encodingで変換してください。
-
04 JSONの前に出力された警告やnotice
レスポンスボディより前の出力は、すべてボディの中に入り込みます。本番ではdisplay_errorsをオフにし、ログに書いてください。
-
05 既定の上限より深いネスト。JSON_ERROR_DEPTHになる
json_decodeの既定の深さは512です。データが本当にそれだけ深いなら、第3引数を上げてください。
よくある質問
- JSON_ERROR系の定数にはどんなものがありますか?
- JSON_ERROR_NONE(0)、JSON_ERROR_DEPTH(1、スタックの最大の深さを超過)、JSON_ERROR_STATE_MISMATCH(2)、JSON_ERROR_CTRL_CHAR(3、予期しない制御文字)、JSON_ERROR_SYNTAX(4、構文エラー、不正なJSON)、JSON_ERROR_UTF8(5、不正なUTF-8文字)、さらにJSON_ERROR_RECURSION、JSON_ERROR_INF_OR_NAN、JSON_ERROR_UNSUPPORTED_TYPE、JSON_ERROR_INVALID_PROPERTY_NAME、JSON_ERROR_UTF16、JSON_ERROR_NON_BACKED_ENUMがあります。
- 結果としてのNULLと、失敗としてのNULLをどう区別しますか?
- json_last_error() === JSON_ERROR_NONE ならデコードは成功しており、返ってきたNULLは正真正銘の値nullです。それ以外のコードであれば失敗です。