2011-11-01 11 views
11

Necesito que la URL codifique solo la ruta del directorio y el nombre de archivo de una URL usando PHP.urlencode solo el directorio y los nombres de archivo de una URL

Así que quiero codificar algo como http://example.com/file name y hacer que resulte en http://example.com/file%20name.

Por supuesto, si hago urlencode('http://example.com/file name'); entonces termino con http%3A%2F%2Fexample.com%2Ffile+name.

La solución obvia (para mí, de todos modos) es usar parse_url() para dividir la URL en esquema, host, etc. y luego solo urlencode() las partes que lo necesitan como la ruta. Luego, volvería a armar la URL usando http_build_url().

¿Existe una solución más elegante que esa? ¿O es básicamente el camino a seguir?

+0

Esa parece ser la solución más robusta para mí. – Herbert

+0

Según la documentación: urlencode es para la parte de consulta de una URL. rawurlencode para la ruta, pero asegúrese de excluir las barras inclinadas. –

Respuesta

15

@deceze definitivamente me hizo ir en el camino correcto, así que ve a votar su respuesta. Pero aquí es exactamente lo que funcionó:

$encoded_url = preg_replace_callback('#://([^/]+)/([^?]+)#', function ($match) { 
       return '://' . $match[1] . '/' . join('/', array_map('rawurlencode', explode('/', $match[2]))); 
      }, $unencoded_url); 

Hay algunas cosas a tener en cuenta:

  • http_build_url requiere un PECL instalar por lo que si va a distribuir su código a otros (como estoy en este caso) es posible que desee evitarlo y seguir con el análisis de exp exp como lo hice aquí (robando fuertemente de la respuesta de @ deceze - otra vez, vaya a votar esa cosa).

  • urlencode() ¡No es el camino a seguir! Necesita rawurlencode() para la ruta, de modo que los espacios se codifiquen como %20 y no como +. La codificación de espacios como + está bien para las cadenas de consulta, pero no tanto para las rutas.

  • Esto no funcionará para las URL que necesitan un nombre de usuario/contraseña codificados. Para mi caso de uso, no creo que me importen, así que no estoy preocupado. Pero si su caso de uso es diferente en ese sentido, tendrá que encargarse de eso.

+0

Correcto, olvidé volver a unir la URL completa. Supongo que uno podría cambiar la expresión regular para hacer búsquedas que no capturan, por lo que solo extrae y modifica la ruta. +1 de todos modos. :) – deceze

14

Como usted dice, algo en este sentido debe hacerlo:

$parts = parse_url($url); 
if (!empty($parts['path'])) { 
    $parts['path'] = join('/', array_map('rawurlencode', explode('/', $parts['path']))); 
} 
$url = http_build_url($parts); 

O posiblemente:

$url = preg_replace_callback('#https?://.+/([^?]+)#', function ($match) { 
      return join('/', array_map('rawurlencode', explode('/', $match[1]))); 
     }, $url); 

(Regex no totalmente probado sin embargo)

+0

+1 para darse cuenta de que las barras en la ruta ensuciarán todo si no se les da un manejo especial como lo hizo usted. – Trott

+0

Agradable. La expresión regular necesita algunos ajustes, pero me puso en el camino correcto. – Trott

+0

Reemplazaría 'urlencode' con' rawurlencode'. – kayue

-1

creo que esta función bien:

function newUrlEncode ($url) { 
    return str_replace(array('%3A', '%2F'), '/', urlencode($url)); 
} 
+0

Esto funciona para el ejemplo en la pregunta, pero no es robusto. Por ejemplo, devuelve el resultado incorrecto si se especifica un puerto en la URL. – Trott

-1

mucho más sencillo:

$encoded = implode("/", array_map("rawurlencode", explode("/", $path))); 
+1

por favor explique su respuesta, ya que es una vieja pregunta, se recomienda que nos diga cómo su respuesta es diferente a las que ya se proporcionaron. Gracias. –

+0

Esta respuesta es incorrecta. Codificará los dos puntos que siguen el esquema. Dada la entrada 'http://example.com/file name', produce' http% 3A // example.com/file% 20name'. El resultado correcto es 'http: // example.com/file% 20name'. – Trott

1
function encode_uri($url){ 
    $exp = "{[^0-9a-z_.!~*'();,/?:@&=+$#%\[\]-]}i"; 
    return preg_replace_callback($exp, function($m){ 
     return sprintf('%%%02X',ord($m[0])); 
    }, $url); 
} 
Cuestiones relacionadas