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をパースする方法は知らない