いくつかのプログラムで使用してきたが、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 件のコメント:
コメントを投稿