Проблема с %uXXXX

Rin

*
utf8_unescape_request()
Корректирует глобальные массивы $_GET, $_POST, $_COOKIE, $_REQUEST
декодируя значения в юникоде, закодированные через функцию javascript escape() ~ "%uxxxx"
 

SelenIT

IT-лунатик :)
Автор оригинала: phprus
SelenIT
А если в строке уже есть последовательности &#...; ?
В заэскейпленной строке их быть не может. Если они в исходной строке, то они заэскейпятся в %26%23... и без проблем расшифруются (по краней мере, по моим тестам).
 

Gas

может по одной?
изначально ж была задача перекодировать результат работы js-функции escape, а 2 и 3 примеры явно закодированы не с её помощью.
 

WP

^_^
js-функция может использовать и %XX

Задача - обеспечить универсальную обработку всех вариантов.

-~{}~ 18.10.07 18:14:

Rin
Тот сайт не работает, не мог бы ты запостить сюда эту функцию?
 

Gas

может по одной?
WP
2-ой и 3-ий варианты решаются банальным urldecode.
Может проверять на наличие %uXXXX в строке, если есть - натравливать вариант SelenIT'а, иначе просто urldecode. Хотя тогда можно ещё предусмотреть и вариант с &#XXXX;
 

phprus

Moderator
Команда форума
WP
А мой второй вариант с двумя регулярками не работает?
 

SelenIT

IT-лунатик :)
По-моему, универсальное решение тут так же невозможно, как универсальный перевод слова "Gift" (без указания того, нужно ли переводить его с английского или с немецкого). Если наличие в строке %uXXXX; еще однозначно указывает на escape'нутый Unicode, то что скрывается за %C3%BD - два escape'нутых символа Ã и ½ либо один URL-закодированный символ ý - можно наверняка знать, лишь зная происхождение строки. Можно, конечно, проверять, идут ли эти такие последовательности всегда парами, подходящими под структуру UTF-8, и т.д., но все равно остается вероятность ошибки... да и нужно ли?

WP, для какой задачи требуется эта раскодировка?
 

WP

^_^
phprus
Не выполняет второй и третий пункты теста.
SelenIT
> ...бо один URL-закодированный символ ý - можно наверняка знать, лишь зная происхождение строки.
Дык такие последовательности надо просто превращать в байты, без изменения.

Сейчас так:
PHP:
function _urldecode_correct($s) {return stripos($s,'%u') === FALSE?$s:preg_replace('~%(u[a-f\d]{4}|[a-f\d]{2})~ie','urlencode(html_entity_decode("&#".hexdec("$1").";",ENT_NOQUOTES,"utf-8"))',$s);}
function _parse_str($s,&$array) {parse_str(_urldecode_correct($s),$array);}
_parse_str($_SERVER['QUERY_STRING'],$_GET);
if (isset($GLOBALS['HTTP_RAW_POST_DATA'])) {_parse_str($GLOBALS['HTTP_RAW_POST_DATA'],$_POST);}
А задачу я уже описывал - обеспечить обработку %uXXXX наряду с %XX, кодировка - UTF-8.
 

SelenIT

IT-лунатик :)
WP
>Дык такие последовательности надо просто превращать в байты, без изменения.

В том-то и дело, что это только если строка закодирована urlencode. Если "превратить в байт без изменения" последовательность %FD из escape'нутой строки (первый пример), ничего путного не выйдет. Ее нужно интерпретировать как код символа, аналогично %uXXXX...
 

Rin

*
>Тот сайт не работает, не мог бы ты запостить сюда эту функцию?

Лучше подождать, когда сайт заработает, там используется триада зависимых функций:
utf8_unescape_request.php -> utf8_unescape_recursive.php -> utf8_unescape.php

Если ваш сайт в utf8, то utf8_unescape_request()
скорректирует глобальные массивы $_GET, $_POST, $_COOKIE, $_REQUEST, декодируя значения в юникоде, закодированные через функцию javascript escape() ~ "%uxxxx".

-~{}~ 19.10.07 11:05:

Было бы здорово, если бы для PHP сделали специальную опцию типа utf8_unescape_request = {1,0}.
 

Wicked

Новичок
Rin
Я так понял, что там происходит рекурсивная обработка. Отсюда вопрос: а есть ли защита от слишком глубокой рекурсии?

Ситуация почти в точности как тут:
http://www.php-security.org/MOPB/MOPB-02-2007.html

-~{}~ 19.10.07 14:20:

Если наличие в строке %uXXXX; еще однозначно указывает на escape'нутый Unicode, то что скрывается за %C3%BD - два escape'нутых символа Ã и ½ либо один URL-закодированный символ ý - можно наверняка знать, лишь зная происхождение строки.
Не думаю, что это важно при превращении %XX в байты, которых у нас так и так получается 2 штуки. Это скорее вопрос, в какой кодировке мы ожидаем эти данные. Так что я приравниваю этот вопрос к такому: $str = "\xC3\xBD" - в какой кодировке строка?
 

SelenIT

IT-лунатик :)
Wicked
>при превращении %XX в байты, которых у нас так и так получается 2 штуки

В том-то и загвоздка: в случае escape'нутой Javascript'ом строки каждая %XX дает 2 байта (целый символ utf-8), а в случае urlencode - 1 байт (полсимвола). Так что дело не в кодировке, а именно в алгоритме кодирования - посимвольном либо побайтном...
 

Wicked

Новичок
Не думаю, что это важно при превращении %XX в байты, которых у нас так и так получается 2 штуки.
Оговорился.
Хотел сказать что-то типа: "Не думаю, что это важно при превращении каждого из двух %XX в 1 байт, которых у нас в сумме получается 2 штуки."

Т.е. я считаю, что нам не важно, из чего была получена строка "\xC3\xBD" - из %C3%BD или из %uC3BD.
Если мы знаем, что в это поле будут передавать UTF-8, то и будем воспринимать строку "\xC3\xBD" в кодировке утф-8, т.е. получим символ ý.

ПС: представиь на секудну, что ты PHP'шным скриптом, а не JSом передаешь данные куда-то. Соотв-но, утфный символ ý ("\xC3\xBD") уйдет в запросе как %C3%BD. Вполне себе нормальная ситуация.
 

SelenIT

IT-лунатик :)
Wicked
Если бы javascript, зараза, и посылал этот злосчастный "ý" как %uC3BD, а не %FD - я бы не суетился :) Но %uC3BD - это аж иероглиф 쎽, к сожалению...

Итак, по просьбам трудящихся...
PHP:
function unpervert_escaped_utf8_string($s)
{
	if (preg_match('~(%u[a-f\d]{4}|%[c-f][a-f\d](?!%[89a-f][a-f\d]))~is',$s,$m)) {
		return html_entity_decode(preg_replace('~%(u[a-f\d]{4}|[a-f\d]{2})~ise','"&#".hexdec("$1").";"',$s),ENT_NOQUOTES,"utf-8");
	}
	elseif (strpos($s,'%20')!==FALSE)
		return rawurldecode($s);
	else return urldecode($s);
}
Тест от WP проходит. Чего еще я не учел?

Ага, вот чего не учел. Заэскейпленная из-под Javascript'a последовательность ×½ (маловероятно, но вдруг какой-нибудь математик захочет выпендриться...) будет прочитана как неизвестный символ с побайтным представлением %D7%BD. Надо еще подумать...
 

Gas

может по одной?
бегло потестил, у меня всё ok, в мемориз.
под php4 вылазит баг, но это уже мелочи.
 
Сверху