Мне нужно, чтобы 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)));