PHP
JSON
PHP5.6

PHP5から7系への移行時には json_decodeの処理にご注意

PHP5.6から7.2に移行したときにけっこうな地雷を踏んだのでここに記録しておく。


対象


  • remiでphp56とphp-jsonをインストールしてる人

  • PHPアプリケーションに投げられてくるJSON文字列が、自分のコントロール範囲外の人


ハマったポイント


  • remiで入るPHPのJSON Parserは、php-pecl-jsonc(JSON-C)が使われている

  • JSON-Cは、本来エスケープされているべき文字列が、エスケープされていなくても ちゃんと処理できちゃう

  • ↑こいつらを、PHP7で入るJSON Parserでは、ちゃんとエラーにする(とても正しい)

  • クソJSONを送ってきてるクライアントがいたが、PHP5.6時代にはちゃんと処理しちゃっていたので、問題に気づかず

  • PHP7.2に移行したら、クライアントが送ってきたリクエストをエラー扱いして処理できなくなる



検証

docker環境を作って確認


確認用プログラム


  • エスケープしてないタブを含んだJSONを処理してみる


test.php

<?php

echo "PHP v". phpversion(). "\n";

if (defined('JSON_C_BUNDLED')) {
echo "JSON-C\n";
} else {
echo "Not JSON-C\n";
}

$invalidJson = '{"item":"Invalid' . "\t" . 'JSON"}';

$decodeJson = json_decode($invalidJson);
echo 'json_last_error_msg: '.json_last_error_msg()."\n";
var_dump(json_encode($decodeJson));



remi-php56 + php-json(php-pecl-jsonc)


cent7-php56/Dockerfile

FROM centos:centos7

RUN yum clean all && yum -y update
RUN yum install -y http://rpms.famillecollet.com/enterprise/remi-release-7.rpm
RUN yum clean all

### php
RUN yum -y --enablerepo=remi-php56 install \
php \
php-json



実行結果

% docker build cent7-php56 -t cent7-php56

% docker run --rm -v $(pwd):/app -w /app cent7-php56 php test.php
PHP v5.6.38
JSON-C
json_last_error_msg: No error
string(24) "{"item":"Invalid\tJSON"}"


  • 正しくないJSONをjson_decodeに喰わせてもエラーにならない


remi-php70 + php-json


cent7-php70/Dockerfile

FROM centos:centos7

RUN yum clean all && yum -y update
RUN yum install -y http://rpms.famillecollet.com/enterprise/remi-release-7.rpm
RUN yum clean all

### php
RUN yum -y --enablerepo=remi-php70 install \
php \
php-json



実行結果

% docker build cent7-php70 -t cent7-php70

% docker run --rm -v $(pwd):/app -w /app cent7-php70 php test.php
PHP v7.0.32
Not JSON-C
json_last_error_msg: Control character error, possibly incorrectly encoded
string(4) "null"


  • 正しくないJSONをjson_decodeに喰わせるとエラーになり、nullを返す


結論


  • クソJSONを投げてくるクライアントが悪いんだから、クライアント側を直させましょう

  • PHP7系で引き続きクソJSONをパースする方法は知らない


参考