<rmcreative>

RSS

urldecode и кодировки

9 июля 2011

Сегодня неожиданно много времени провёл за изучением одного из репортов в трекере Yii. Первопричина оказалась совсем не той и крылась, как это часто бывает, в несоблюдении стандартов. Вообще тонкости две:

  1. PHP-шный urldecode работает напрямую с октетами (теми, что %AB), так что интерпретация строки зависит от кодировки скрипта. В случае Yii это UTF-8.

  2. Хоть RFC 3986 в районе 16-ой страницы и говорит нам, что «data should first be encoded as octets according to the UTF-8 character encoding», но всё-же достаточно большое количество ПО использует другие кодировки. Чаще всего это ISO-8859-1.

То есть после декодирования мы можем получить либо UTF-8, либо что-то ещё. Это ещё скорее всего будет ISO-8859-1.

Ну и решение — свой urldecode:

/**
 * Improved variant of urldecode.
 * Properly decodes both UTF-8 and ISO-8859-1 encoded URIs.
 *
 * @param string $str encoded string
 * @return string decoded string
 */
private function urldecode($str)
{
    $str = urldecode($str);
 
    // is it UTF-8?
    // http://w3.org/International/questions/qa-forms-utf-8.html
    if(preg_match('%^(?:
       [\x09\x0A\x0D\x20-\x7E]            # ASCII
     | [\xC2-\xDF][\x80-\xBF]             # non-overlong 2-byte
     | \xE0[\xA0-\xBF][\x80-\xBF]         # excluding overlongs
     | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}  # straight 3-byte
     | \xED[\x80-\x9F][\x80-\xBF]         # excluding surrogates
     | \xF0[\x90-\xBF][\x80-\xBF]{2}      # planes 1-3
     | [\xF1-\xF3][\x80-\xBF]{3}          # planes 4-15
     | \xF4[\x80-\x8F][\x80-\xBF]{2}      # plane 16
    )*$%xs', $str))
    {
        return $str;
    }
    else
    {
        return utf8_encode($str);
    }
}

Комментарии RSS

  1. №4941
    Максим
    Максим 09.07.2011, 12:40:36

    2Sam, случаем не это имеется в виду ? http://www.php.net/manual/ru/function.urldecode.php#101401

  2. №4945
    Sam
    Sam 09.07.2011, 23:11:54

    Да, оно самое. Там даже решение почти 1 в 1.

  3. №5711
    Amal
    Amal 25.12.2011, 21:02:49

    У этой регулярки есть одна плохая особенность - в некоторых случаях при ее применении php вылетает с segmentation fault. Столкнулся с этим недавно. Использовал для проверки кодировки страниц перед парсингом и на страницах гугла начала вылетать такая ошибка. Пришлось отказаться от проверки регуляркой.

  1. Почта опубликована не будет.

  2. Можно использовать синтаксис Markdown или HTML.

  3. Введите ответ в поле. Щёлкните, чтобы получить другую задачу.