Как url-кодировать только символы не ASCII URL в PHP, но оставлять зарезервированные символы не закодированными?
у меня есть URL, который выглядит так (Обратите внимание на "" символы):
http://tinklarastis.omnitel.lt/kokius-aptarnavimo-kanalus-klientui-siulo-„omnitel“-1494 
Я получаю его от SimplePie parser, если это имеет значение. Теперь, если вы попытаетесь перейти к этому конкретному URL-адресу в своем браузере и скопировать его из адресной строки, вы получите URL-адрес, который имеет символы, отличные от ASCII процентов закодированных:
http://tinklarastis.omnitel.lt/kokius-aptarnavimo-kanalus-klientui-siulo-%E2%80%9Eomnitel%E2%80%9C-1494
Я пытаюсь понять, как я могу имитировать одно и то же преобразование в PHP. Я не могу просто использовать urlencode() или urlrawencode() как они кодируют оба символа не ASCII и зарезервированные символы, в то время как в моем случае зарезервированные символы (/?& и т. д.) должны оставаться такими, какие они есть.
до сих пор я видел только решений которые включают разделение URL-адреса на части между зарезервированными символами, а затем с помощью urlencode(), но это кажется мне хакерским, и я надеюсь, что есть более элегантное решение. Я пробовал различные варианты iconv(), mb_convert_encoding(), но пока безуспешно.
5 ответов
после исследования немного, я пришел к выводу, что нет никакого способа сделать красиво в PHP (однако, другие языки, такие как python / perl, похоже, имеют функции именно для этого случая использования). Это функция, которую я придумал (обеспечивает кодирование фрагмента пути URL-адреса):
function url_path_encode($url) {
    $path = parse_url($url, PHP_URL_PATH);
    if (strpos($path,'%') !== false) return $url; //avoid double encoding
    else {
        $encoded_path = array_map('urlencode', explode('/', $path));
        return str_replace($path, implode('/', $encoded_path), $url);
    }   
}
У меня есть простой однострочный, который я использую для кодирования на месте только на символах, отличных от ASCII, используя preg_match_callback:
preg_replace_callback('/[^\x20-\x7f]/', function($match) { return urlencode($match[0]);     }, $url);
Я думаю, что это сделает то, что вы хотите.
<?php
$string = 'http://tinklarastis.omnitel.lt/kokius-aptarnavimo-kanalus-klientui-siulo-„omnitel“-1494/?foo=bar&fizz=buzz';
var_dump(filter_var($string, FILTER_SANITIZE_STRING, FILTER_FLAG_ENCODE_HIGH));
Это поможет вам:
$ php test.php
string(140) "http://tinklarastis.omnitel.lt/kokius-aptarnavimo-kanalus-klientui-siulo-„omnitel“-1494/?foo=bar&fizz=buzz"
эта функция может помочь:
function sanitizeUrl($url)
{
    $chars = '$-_.+!*\'(),{}|\^~[]`<>#%";/?:@&=';
    $pattern = '~[^a-z0-9' . preg_quote($chars, '~') . ']+~iu';
    $callback = create_function('$matches', 'return urlencode($matches[0]);');
    return preg_replace_callback($pattern, $callback, $url);
}
function cyrillicaToUrlencode($text){
return $line = preg_replace_callback('/([а-яё])/ui',
                            function ($matches) {
                                return urlencode($matches[0]);
                            }, 
                            $text); 
}
echo cyrillicaToUrlencode("https://test.com/Москваёtext1Воронежtext2Москваёtext3yМоскваё___-Москваё");
