Спасаясь от побега Персонажей - PullRequest
9 голосов
/ 20 мая 2010

Я пытаюсь имитировать json_encode флаги битовой маски, реализованные в PHP 5.3.0, вот строка, которую я имею:

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

Doing json_encode($s, JSON_HEX_APOS | JSON_HEX_QUOT) выводит следующее:

"O\\\u0027Rei\\\u0022lly"

И в настоящее время я делаю это в версиях PHP старше, чем 5.3.0:

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: </strong>

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));
}

Ответы [ 6 ]

13 голосов
/ 27 мая 2010

PHP строка

'O\'Rei"lly'

это просто способ PHP получить буквальное значение

O'Rei"lly

в строку, которую можно использовать. Вызов addslashes для этой строки меняет ее на буквально следующие 11 символов

O\'Rei\"lly

т.е.. strlen(addslashes('O\'Rei"lly')) == 11

Это значение, которое отправляется на json_escape.

В JSON обратная косая черта является escape-символом, поэтому ее необходимо экранировать, т. Е.

\ будет \\

Также одиночные и двойные кавычки могут вызвать проблемы. Таким образом, преобразование их в эквивалент Unicode одним способом, чтобы избежать проблем. Поэтому более поздние версии PHP json_encode меняются

' будет \u0027

и

" будет \u0022

Таким образом, применяя эти три правила к

O\'Rei\"lly

дает нам

O\\\u0027Rei\\\u0022lly

Затем эта строка переносится в двойные кавычки, чтобы сделать ее строкой JSON. Ваши выражения замены включают в себя передние косые черты. Либо случайно, либо умышленно это означает, что начальная и конечная двойная кавычка, возвращаемая json_encode, не подлежит экранированию, чего не должно быть.

Так в более ранних версиях PHP

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

будет печатать

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

и мы хотим изменить ' на \u0027 и мы хотим изменить \" на \u0022, потому что \ в \" просто для вставки " в строку, потому что она начинается и заканчивается двойными кавычками.

Так вот почему мы получаем

"O\\\u0027Rei\\\u0022lly"
2 голосов
/ 27 мая 2010

Когда вы кодируете строку для json, некоторые вещи необходимо экранировать независимо от параметров. Как уже отмечали другие, это включает '\', поэтому любой обратный слеш, проходящий через json_encode, будет удвоен. Так как вы сначала запускаете свою строку через addlashes, который также добавляет обратные слеши в кавычки, вы добавляете много дополнительных обратных слешей. Следующая функция будет эмулировать, как json_encode будет кодировать строку. Если в строку уже добавлены обратные слеши, они будут удвоены.

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;
}
2 голосов
/ 27 мая 2010

Если я правильно понимаю, вы просто хотите знать, почему вам нужно использовать

'\\\u0027' и не только '\\u0027'

Вы избегаете косой черты и значения Unicode для символа. При этом вы говорите json, что он должен поместить туда апостроф, но ему нужен обратный слеш и u, чтобы знать, что шестнадцатеричный код символа Юникод следующий.

Поскольку вы экранируете эту строку:

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

первый обратный слеш фактически избегает обратного слеша перед апострофом. Затем следующая косая черта используется для экранирования от обратной косой черты, используемой json для идентификации символа как символа Юникода.

Если бы вы применяли алгоритм к О'Рейли вместо О'Рейли, то этого было бы достаточно.

Надеюсь, вы найдете это полезным. Я оставляю вам только эту ссылку, чтобы вы могли больше узнать о том, как устроен json, поскольку очевидно, что вы уже понимаете PHP:

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

2 голосов
/ 20 мая 2010

Он избегает обратной косой черты, а также цитаты. Трудно иметь дело с побегами, как вы это делаете, поскольку это быстро превращается в игры с обратным слешем. : - /

1 голос
/ 20 мая 2010

Поскольку вы собираетесь json_encode строку \', вам придется сначала кодировать \, а затем '. Таким образом, у вас будет \\ и \u0027. Объединяя эти результаты \\\u0027.

0 голосов
/ 23 мая 2010

\, сгенерированный 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").

Вывод: вы дважды избегаете кавычек, что, скорее всего, не то, что вам нужно. json_encode уже экранирует все, что нужно, чтобы любой синтаксический анализатор JavaScript возвращал исходную структуру данных. В вашем случае это строка, которую вы получили после вызова 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>
...