9

json_encodePHP 5.3.0で実装されたビットマスクフラグを模倣しようとしています。これが私が持っている文字列です:

$s = addslashes('O\'Rei"lly'); // O\'Rei\"lly

実行json_encode($s, JSON_HEX_APOS | JSON_HEX_QUOT)すると、次のように出力されます。

"O\\\u0027Rei\\\u0022lly"

そして、私は現在、5.3.0より前のPHPバージョンでこれを行っています:

str_replace(array('\\"', "\\'"), array('\\u0022', '\\\u0027'), json_encode($s))
or
str_replace(array('\\"', '\\\''), array('\\u0022', '\\\u0027'), json_encode($s))

同じ結果を正しく出力します。

"O\\\u0027Rei\\\u0022lly"

なぜ一重引用符(または[周囲の引用符を除く])をだけでなく置き換える必要があるのか'\\\''"\\'"'\\\u0027''\\u0027'​​理解できません。


PHP<5.3への移植で問題が発生しているコードは次のとおりです。

if (get_magic_quotes_gpc() && version_compare(PHP_VERSION, '6.0.0', '<'))
{
    /* JSON_HEX_APOS and JSON_HEX_QUOT are availiable */
    if (version_compare(PHP_VERSION, '5.3.0', '>=') === true)
    {
        $_GET = json_encode($_GET, JSON_HEX_APOS | JSON_HEX_QUOT);
        $_POST = json_encode($_POST, JSON_HEX_APOS | JSON_HEX_QUOT);
        $_COOKIE = json_encode($_COOKIE, JSON_HEX_APOS | JSON_HEX_QUOT);
        $_REQUEST = json_encode($_REQUEST, JSON_HEX_APOS | JSON_HEX_QUOT);
    }

    /* mimic the behaviour of JSON_HEX_APOS and JSON_HEX_QUOT */
    else if (extension_loaded('json') === true)
    {
        $_GET = str_replace(array(), array('\\u0022', '\\u0027'), json_encode($_GET));
        $_POST = str_replace(array(), array('\\u0022', '\\u0027'), json_encode($_POST));
        $_COOKIE = str_replace(array(), array('\\u0022', '\\u0027'), json_encode($_COOKIE));
        $_REQUEST = str_replace(array(), array('\\u0022', '\\u0027'), json_encode($_REQUEST));
    }

    $_GET = json_decode(stripslashes($_GET));
    $_POST = json_decode(stripslashes($_POST));
    $_COOKIE = json_decode(stripslashes($_COOKIE));
    $_REQUEST = json_decode(stripslashes($_REQUEST));
}
4

6 に答える 6

14

PHP文字列

'O\'Rei"lly'

リテラル値を取得するPHPの方法です

O'Rei"lly

使用できる文字列に。その文字列を呼び出すaddslashesと、文字通り次の11文字に変更されます

O\'Rei\"lly

すなわちstrlen(addslashes('O\'Rei"lly')) == 11

これはに送信される値ですjson_escape

JSONでは、バックスラッシュはエスケープ文字であるため、エスケープする必要があります。

\ することが\\

また、一重引用符と二重引用符は問題を引き起こす可能性があります。したがって、問題を回避するために、それらを1つの方法で同等のUnicodeに変換します。したがって、PHPのjson_encodeの変更のその後のバージョン

' することが \u0027

" することが \u0022

したがって、これらの3つのルールをに適用する

O\'Rei\"lly

私たちに

O\\\u0027Rei\\\u0022lly

次に、この文字列を二重引用符で囲んでJSON文字列にします。置換式には、先頭のスラッシュが含まれます。偶然または故意に、これは、によって返される先頭と末尾の二重引用符json_encodeがエスケープの対象にならないことを意味します。

したがって、以前のバージョンのPHPでは

$s = addslashes('O\'Rei"lly');
print json_encode($s);

印刷します

"O\\'Rei\\\"lly"

そして、'beに変更し\u0027 たいのですが、inは文字列に入るだけなので、文字列は二重引用符で始まり、二重引用符で終わるため、 \"beに変更したいと思います。\u0022\\""

だから私たちは

"O\\\u0027Rei\\\u0022lly"
于 2010-05-26T22:51:07.147 に答える
2

引用符だけでなくバックスラッシュもエスケープしています。ここで行っているように、エスケープされたエスケープを処理するのは困難です。これは、すぐにバックスラッシュカウントゲームに変わるためです。:-/

于 2010-05-20T04:01:19.050 に答える
2

私が正しく理解しているなら、あなたはあなたがなぜ使う必要があるのか​​知りたいだけです

'\\\u0027'だけでなく'\\u0027'

スラッシュと文字のUnicode値をエスケープしています。これで、jsonにアポストロフィを配置する必要があることを伝えていますが、Unicodeの16進文字コードが次にあることを知るにはバックスラッシュとuが必要です。

この文字列をエスケープしているので:

$s = addslashes('O\'Rei"lly'); // O\'Rei\"lly

最初のバックスラッシュは、実際にはアポストロフィの前にバックスラッシュをエスケープしています。次に、次のスラッシュを使用して、jsonが文字をUnicode文字として識別するために使用する円記号をエスケープします。

O \'Rei \ "llyではなくO'Reillyにアルゴリズムを適用する場合は、後者で十分です。

これがお役に立てば幸いです。このリンクだけを残しておくと、jsonの構築方法について詳しく読むことができます。これは、PHPをすでに理解していることは明らかだからです。

http://www.json.org/fatfree.html

于 2010-05-26T21:08:45.667 に答える
2

jsonの文字列をエンコードする場合、オプションに関係なく、いくつかのことをエスケープする必要があります。他の人が指摘しているように、これには「\」が含まれているため、json_encodeを介して実行されるバックスラッシュは2倍になります。最初に文字列をaddslashesで実行しているため、引用符にバックスラッシュも追加されているため、多くの余分なバックスラッシュを追加しています。次の関数は、json_encodeが文字列をエンコードする方法をエミュレートします。文字列にすでに円記号が追加されている場合、それらは2倍になります。

function json_encode_string( $encode , $options ) {
    $escape = '\\\0..\37';
    $needle = array();
    $replace = array();

    if ( $options & JSON_HEX_APOS ) {
        $needle[] = "'";
        $replace[] = '\u0027';
    } else {
        $escape .= "'";
    }

    if ( $options & JSON_HEX_QUOT ) {
        $needle[] = '"';
        $replace[] = '\u0022';
    } else {
        $escape .= '"';
    }

    if ( $options & JSON_HEX_AMP ) {
        $needle[] = '&';
        $replace[] = '\u0026';
    }

    if ( $options & JSON_HEX_TAG ) {
        $needle[] = '<';
        $needle[] = '>';
        $replace[] = '\u003C';
        $replace[] = '\u003E';
    }

    $encode = addcslashes( $encode , $escape );
    $encode = str_replace( $needle , $replace , $encode );

    return $encode;
}
于 2010-05-27T18:11:06.570 に答える
1

json_encode文字列に移動するので、\'最初にエンコードしてから、をエンコードする必要があります。だからあなたはとを持っているでしょう。これらの結果を連結します。\'\\\u0027\\\u0027

于 2010-05-20T06:45:22.933 に答える
0

\によって生成され、によって再addslashes()エスケープされjson_encode()ます。あなたはおそらくこれを言うつもりでしDoing json_encode($s, JSON_HEX_APOS | JSON_HEX_QUOT) outputs the followingたが、あなたは$str代わりに使用しました$s、それは皆を混乱させました。

"O\\\u0027Rei\\\u0022lly"JavaScriptで文字列を評価すると、次のようになりますが、それはあなたが望んでいることではない"O\'rei\"lly"と確信しています。評価するときは、おそらくすべての制御コードを削除する必要があります。さあ、これをファイルに入れてください:。alert("O\\\u0027Rei\\\u0022lly")

結論:引用符を2回エスケープしていますが、これはおそらく必要なものではありません。json_encodeJavaScriptパーサーが元のデータ構造を返すように、必要なものはすべてすでにエスケープされています。あなたの場合、それはへの呼び出しの後に取得した文字列ですaddslashes


証拠:

<?php $out = json_encode(array(10, "h'ello", addslashes("h'ello re-escaped"))); ?>
<script type="text/javascript">
  var out = <?php echo $out; ?>;
  alert(out[0]);
  alert(out[1]);
  alert(out[2]);
</script>
于 2010-05-23T18:19:23.067 に答える