2011-11-01 7 views
11

Ho bisogno di codificare l'URL solo il percorso della directory e il nome del file di un URL utilizzando PHP.urlencode solo i nomi di directory e file di un URL

Quindi voglio codificare qualcosa come http://example.com/file name e ottenerlo in http://example.com/file%20name.

Ovviamente, se lo faccio urlencode('http://example.com/file name');, il risultato è http%3A%2F%2Fexample.com%2Ffile+name.

L'ovvio (per me, comunque) la soluzione è quella di utilizzare parse_url() di dividere l'URL nella schema, accoglienza, ecc e poi basta urlencode() le parti che ne hanno bisogno come il percorso. Quindi, vorrei riassemblare l'URL utilizzando http_build_url().

Esiste una soluzione più elegante? O è fondamentalmente la strada da percorrere?

+0

che sembra la soluzione più robusta per me. – Herbert

+0

Per documentazione: urlencode è per la parte di query di un URL. rawurlencode per il percorso, ma assicurati di escludere le barre. –

risposta

15

@deceze sicuramente mi ha fatto andare lungo la strada giusta, quindi vai a invitare la sua risposta. Ma qui è esattamente ciò che ha funzionato:

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

Ci sono alcune cose da notare:

  • http_build_url richiede un PECL installare, quindi se si sta distribuendo il codice per gli altri (come sono in questo caso) si potrebbe desiderare di evitarlo e attenersi al parsing di exp exp come ho fatto qui (rubando pesantemente dalla risposta di @ deceze - di nuovo, andare in suvoce di quella cosa).

  • urlencode() non è la strada da percorrere! È necessario rawurlencode() per il percorso in modo che gli spazi vengano codificati come %20 e non +. Gli spazi di codifica come + vanno bene per le stringhe di query, ma non così tanto per i percorsi.

  • Questo non funzionerà per gli URL che richiedono un nome utente/password codificati. Per il mio caso d'uso, non penso che mi interessi per quelli, quindi non sono preoccupato. Ma se il tuo caso d'uso è diverso a tale riguardo, dovrai occupartene.

+0

Giusto, ho dimenticato di ricomporre l'intero URL. Immagino che si possa cambiare la regex per fare look-behind non catturanti, quindi estrae e modifica solo il percorso. +1 comunque. :) – deceze

14

Come dici tu, qualcosa in questo senso dovrebbe farlo:

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

O forse:

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

(Regex non completamente testato però)

+0

+1 per rendersi conto che le barre nel percorso rovinano tutto se non ricevono una gestione speciale come hai fatto tu. – Trott

+0

Bello. La regexp ha bisogno di qualche ritocco, ma mi ha messo sulla giusta strada. – Trott

+0

Sostituire 'urlencode' con' rawurlencode'. – kayue

-1

penso che questa funzione ok:

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

Questo funziona per l'esempio nella domanda, ma non è robusto. Ad esempio, restituisce il risultato errato se una porta è specificata nell'URL. – Trott

-1

molto più semplice:

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

per favore spiega la tua risposta in quanto è una vecchia domanda, si consiglia di dirci in che modo la tua risposta è diversa da altre già fornite. Grazie. –

+0

Questa risposta non è corretta. Codificherà il colon che segue lo schema. Dato l'input 'http://example.com/file name', produce' http% 3A // example.com/file% 20name'. Il risultato corretto è '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); 
} 
Problemi correlati