いくつかのプログラムで使用してきたが、3年以上たってバグを発見したので、メモしておく。
自作json_encode()は原形をほぼとどめていないが、
phpのマニュアルの中の02-May-2007 01:55のUser Contributed Notesで
Yi-Ren Chen at NCTU CSIEさんが書いたphp_json_encode()を改造して作ったものだ。
json作成のロジックで、数字だったらそのまま使い、文字ならばクォートして使用する
ような部分があるが、ここで数字の判定を
if (is_numeric($val)) return $val;と記述していたが、これに
$data = array('id'=>'011')のような入力を食わせると、
{"id":011}が出力されてしまう。これはブラウザのjavascriptに8進数として処理され
{id:9}と解釈される。
とりあえず
if (is_int($val)||is_float($val)) return $val;のように記述し、
{id:"011"}と受け取られるようになったことを確認したが、過去作ったシステムが、
異常動作しないかひやひやものだ。
Yi-Ren Chenさんのコードを元にjson_encode相当関数を作った世界中の人たちも
大丈夫だったのかなあと心配してみる。
修正済みコード
http://sourceforge.jp/projects/extwiki/svn/view/trunk/plugin/json_encode.php?view=markup&revision=107&root=extwiki
<?php // $Id: json_encode.php 3 2010-10-02 14:56:27Z mashiki $ /** * json_encode: use this for early version(<5.2) of php * which support "multibyte" but doesn't support "json_encode". * * Modified by mashiki 2008,2009,2011 * * Original written by Yi-Ren Chen at NCTU CSIE as php_json_encode() * User Contributed Notes 02-May-2007 01:55 in PHP online manual */ function json_encode($val) { if (is_int($val)||is_float($val)) return $val; if (is_bool($val)) return $val?'true':'false'; if (is_array($val)) { $len = count($val); for($ii=0; $ii<$len && isset($val[$ii]); ++$ii) {} $temp = array(); if($len==$ii) { for($i=0;$i<$len;$i++) { $temp[] = sprintf("%s", json_encode($val[$i])); } return '['. implode(",",$temp) .']'; } else { foreach($val as $key => $item) { $temp[] = sprintf("%s:%s", json_encode($key), json_encode($item)); } return '{'. implode(",", $temp) .'}'; } } // else string static $from = array('\\', "\n", "\r", '"'); static $to = array('\\\\','\\n','\\r','\\"'); static $cmap = array(0x80, 0xFFFF, 0, 0xFFFF); return '"'. preg_replace_callback( '/([0-9]+);/', create_function('$match','return sprintf("\\u%04x", $match[1]);'), mb_encode_numericentity(str_replace($from, $to, $val), $cmap, 'UTF-8') ) . '"'; } ?>
0 件のコメント:
コメントを投稿