Мне нужно, чтобы URL-адрес кодировал только путь к каталогу и имя файла URL с помощью PHP.
Поэтому я хочу кодировать что-то вроде http://example.com/file name
и привести его к http://example.com/file%20name
.
Конечно, если я делаю urlencode('http://example.com/file name');
то я получаю http%3A%2F%2Fexample.com%2Ffile+name
.
Очевидным (для меня, в любом случае) решением является использование parse_url()
для разделения URL-адреса на схему, хост и т. Д., А затем просто urlencode()
части, которые нуждаются в ней, как путь. Затем я http_build_url()
URL-адрес с помощью http_build_url()
.
Есть ли более элегантное решение? Или это в основном способ пойти?
@deceze определенно заставил меня спуститься по правильному пути, так что держите его ответ. Но вот что именно сработало:
$encoded_url = preg_replace_callback('#://([^/]+)/([^?]+)#', function ($match) { return '://' . $match[1] . '/' . join('/', array_map('rawurlencode', explode('/', $match[2]))); }, $unencoded_url);
Следует отметить несколько вещей:
http_build_url требует установки PECL, поэтому, если вы распространяете свой код другим (как и я в этом случае), вы можете его избежать и придерживаться регр-синтаксического анализа, как я это сделал (крадусь от ответа @ deceze – снова, идите повышайте эту вещь).
urlencode()
– это не путь! Вам нужен rawurlencode()
для пути, чтобы пробелы были закодированы как %20
а не +
. Кодирование пробелов как +
отлично подходит для строк запроса, но не так горячо для путей.
Это не будет работать для URL-адресов, для которых требуется имя пользователя / пароль. Для моего случая использования я не думаю, что меня это волнует, поэтому я не волнуюсь. Но если ваш вариант использования отличается в этом отношении, вам нужно позаботиться об этом.
Как вы говорите, что-то в этом направлении должно это сделать:
$parts = parse_url($url); if (!empty($parts['path'])) { $parts['path'] = join('/', array_map('rawurlencode', explode('/', $parts['path']))); } $url = http_build_url($parts);
Или возможно:
$url = preg_replace_callback('#https?://.+/([^?]+)#', function ($match) { return join('/', array_map('rawurlencode', explode('/', $match[1]))); }, $url);
(Regex не полностью протестирован)
function encode_uri($url){ $exp = "{[^0-9a-z_.!~*'();,/?:@&=+$#%\[\]-]}i"; return preg_replace_callback($exp, function($m){ return sprintf('%%%02X',ord($m[0])); }, $url); }
Я думаю, что эта функция в порядке:
function newUrlEncode ($url) { return str_replace(array('%3A', '%2F'), '/', urlencode($url)); }
Гораздо проще:
$encoded = implode("/", array_map("rawurlencode", explode("/", $path)));