urlencode только каталог и имена файлов URL-адреса

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