Domanda

Se voglio creare un URL utilizzando una variabile ho due scelte per codificare la stringa. urlencode() e rawurlencode().

Che cosa sono esattamente le differenze e che è preferito?

È stato utile?

Soluzione

Dipenderà vostro scopo. Se l'interoperabilità con altri sistemi è importante allora sembra rawurlencode è la strada da percorrere. L'unica eccezione è sistemi legacy che prevedono la stringa di query di seguire lo stile forma di codifica degli spazi codificati come invece del + 20% (nel qual caso è necessario UrlEncode).

rawurlencode segue RFC 1738 prima di PHP 5.3.0 e RFC 3986 in seguito (vedi http://us2.php.net/manual/en/function.rawurlencode.php )

  

Restituisce una stringa in cui tutti i caratteri non alfanumerici, ad eccezione -_. ~ Sono stati sostituiti con un segno di percentuale (%) seguito da due cifre esadecimali. Questa è la codifica descritto in »RFC 3986 per proteggere caratteri letterali siano interpretate come delimitatori URL speciali, e per proteggere URL vengano mangled da mezzi di trasmissione con la conversione dei caratteri (come alcuni sistemi di posta elettronica).

Nota sulle RFC 3986 vs 1738. rawurlencode prima php 5.3 codificati tilde (~) secondo RFC 1738. Dal PHP 5.3, tuttavia, rawurlencode segue RFC 3986 che non richiede la codifica dei caratteri tilde.

urlencode codifica spazi come il segno più (non come %20 come fatto in rawurlencode) (vedi http://us2.php.net/manual/en/function.urlencode.php )

  

Restituisce una stringa in cui tutti i caratteri non alfanumerici tranne -_. sono stati sostituiti con un segno di percentuale (%) seguito da due cifre esadecimali e spazi codificati come (+) segno più. Viene codificato allo stesso modo che i dati inviati da un modulo WWW è codificato, che è allo stesso modo come nella domanda / x-www-form-urlencoded tipo di supporto. Ciò differisce dalla »RFC 3986 codifica (vedi rawurlencode ()) dal fatto che per ragioni storiche, gli spazi sono codificati come (+) segno più.

Questo corrisponde alla definizione di applicazione / x-www-form-urlencoded in RFC 1866 .

Letture aggiuntive:

Si consiglia inoltre di vedere la discussione a http://bytes.com / gruppi / php / 5624-urlencode-vs-rawurlencode .

Inoltre, RFC 2396 vale la pena dare un'occhiata. RFC 2396 definisce sintassi URI valido. La parte principale che ci interessa è da 3.4 componente di query:

  

Nel giro di un componente di query, i personaggi ";", "/", "?", ":", "@",
"&", "=", "+", ",", and "$"
sono riservati.

Come si può vedere, la + è un carattere riservato nella stringa di query e quindi avrebbe bisogno di essere codificato come da RFC 3986 (come in rawurlencode).

Altri suggerimenti

La prova è nel codice sorgente di PHP.

Ti porterò attraverso un processo rapido di come scoprire questo genere di cose per conto proprio, in futuro ogni volta che vuoi. Portare con me, ci sarà un sacco di codice sorgente C è possibile scremare sopra (lo spiego). Se si vuole rispolverare un po 'di C, un buon punto di partenza è il nostro SO wiki .

Scarica la fonte (o utilizzare http://lxr.php.net/ per sfogliare on-line) , grep tutti i file per il nome della funzione, troverete qualcosa come questo:

PHP 5.3.6 (più recente al momento della scrittura), descrive le due funzioni nel loro codice nativo C nel file url.c .

rawurlencode ()

PHP_FUNCTION(rawurlencode)
{
    char *in_str, *out_str;
    int in_str_len, out_str_len;

    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &in_str,
                              &in_str_len) == FAILURE) {
        return;
    }

    out_str = php_raw_url_encode(in_str, in_str_len, &out_str_len);
    RETURN_STRINGL(out_str, out_str_len, 0);
}

UrlEncode ()

PHP_FUNCTION(urlencode)
{
    char *in_str, *out_str;
    int in_str_len, out_str_len;

    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &in_str,
                              &in_str_len) == FAILURE) {
        return;
    }

    out_str = php_url_encode(in_str, in_str_len, &out_str_len);
    RETURN_STRINGL(out_str, out_str_len, 0);
}

Ok, allora cosa c'è di diverso qui?

Entrambi sono essenzialmente chiamare due diverse funzioni interne rispettivamente: php_raw_url_encode e php_url_encode

Quindi, andare a cercare quelle funzioni!

Vediamo php_raw_url_encode

PHPAPI char *php_raw_url_encode(char const *s, int len, int *new_length)
{
    register int x, y;
    unsigned char *str;

    str = (unsigned char *) safe_emalloc(3, len, 1);
    for (x = 0, y = 0; len--; x++, y++) {
        str[y] = (unsigned char) s[x];
#ifndef CHARSET_EBCDIC
        if ((str[y] < '0' && str[y] != '-' && str[y] != '.') ||
            (str[y] < 'A' && str[y] > '9') ||
            (str[y] > 'Z' && str[y] < 'a' && str[y] != '_') ||
            (str[y] > 'z' && str[y] != '~')) {
            str[y++] = '%';
            str[y++] = hexchars[(unsigned char) s[x] >> 4];
            str[y] = hexchars[(unsigned char) s[x] & 15];
#else /*CHARSET_EBCDIC*/
        if (!isalnum(str[y]) && strchr("_-.~", str[y]) != NULL) {
            str[y++] = '%';
            str[y++] = hexchars[os_toascii[(unsigned char) s[x]] >> 4];
            str[y] = hexchars[os_toascii[(unsigned char) s[x]] & 15];
#endif /*CHARSET_EBCDIC*/
        }
    }
    str[y] = '\0';
    if (new_length) {
        *new_length = y;
    }
    return ((char *) str);
}

E, naturalmente, php_url_encode:

PHPAPI char *php_url_encode(char const *s, int len, int *new_length)
{
    register unsigned char c;
    unsigned char *to, *start;
    unsigned char const *from, *end;

    from = (unsigned char *)s;
    end = (unsigned char *)s + len;
    start = to = (unsigned char *) safe_emalloc(3, len, 1);

    while (from < end) {
        c = *from++;

        if (c == ' ') {
            *to++ = '+';
#ifndef CHARSET_EBCDIC
        } else if ((c < '0' && c != '-' && c != '.') ||
                   (c < 'A' && c > '9') ||
                   (c > 'Z' && c < 'a' && c != '_') ||
                   (c > 'z')) {
            to[0] = '%';
            to[1] = hexchars[c >> 4];
            to[2] = hexchars[c & 15];
            to += 3;
#else /*CHARSET_EBCDIC*/
        } else if (!isalnum(c) && strchr("_-.", c) == NULL) {
            /* Allow only alphanumeric chars and '_', '-', '.'; escape the rest */
            to[0] = '%';
            to[1] = hexchars[os_toascii[c] >> 4];
            to[2] = hexchars[os_toascii[c] & 15];
            to += 3;
#endif /*CHARSET_EBCDIC*/
        } else {
            *to++ = c;
        }
    }
    *to = 0;
    if (new_length) {
        *new_length = to - start;
    }
    return (char *) start;
}

Un po 'veloce di conoscenza prima di andare avanti, EBCDIC è un altro set di caratteri , simile a ASCII, ma un concorrente totale. PHP tenta di trattare con entrambi. Ma in fondo, questo significa byte EBCDIC 0x4c byte non è il L in ASCII, in realtà è un <. Sono sicuro che si vede la confusione qui.

Entrambe queste funzioni gestire EBCDIC se il server web ha definito.

Inoltre, entrambi utilizzano un array di caratteri (si pensi tipo stringa) hexchars look-up per ottenere alcuni valori, il vettore è descritto come tale:

/* rfc1738:

   ...The characters ";",
   "/", "?", ":", "@", "=" and "&" are the characters which may be
   reserved for special meaning within a scheme...

   ...Thus, only alphanumerics, the special characters "$-_.+!*'(),", and
   reserved characters used for their reserved purposes may be used
   unencoded within a URL...

   For added safety, we only leave -_. unencoded.
 */

static unsigned char hexchars[] = "0123456789ABCDEF";

Oltre a ciò, le funzioni sono veramente diverso, e ho intenzione di spiegare loro in ASCII e EBCDIC.

Le differenze di ASCII:

UrlEncode:

  • Calcola una lunghezza di inizio / fine della stringa di input, alloca memoria
  • cammina attraverso un ciclo while, incrementi finché si raggiunge la fine della stringa
  • Grabs presente carattere
  • Se il carattere è uguale a ASCII Char 0x20 (vale a dire, uno "spazio"), aggiungere un segno + alla stringa di output.
  • Se non è uno spazio, ed è, inoltre, non alfanumerico (isalnum(c)), ed inoltre non è e _, -, o un carattere ., poi, uscita un segnale % alla posizione di matrice 0, fare una matrice guardare fino a l'array hexchars per una ricerca di matrice os_toascii (una matrice da Apache che traduce char al codice esadecimale) per la chiave di c (presente carattere), abbiamo poi spostamento a destra del 4, assegnare tale valore al carattere 1, e alla posizione 2 abbiamo assegnare lo stesso ricerca, tranne che preforma logico e per vedere se il valore è 15 (0xF), e restituire un 1 in questo caso, o 0 altrimenti. Alla fine, vi ritroverete con qualcosa di codifica.
  • Se si finisce per non è uno spazio, è alfanumerico o uno dei caratteri _-., emette esattamente quello che è.

rawurlencode:

  • Alloca memoria per la stringa
  • iterazioni sulle esso in base alla durata prevista chiamata di funzione (non calcolato in funzione con UrlEncode).

Nota: Molti programmatori hanno probabilmente mai visto un ciclo for iterare questo modo, è un po 'hacker e non la convenzione standard utilizzato con la maggior parte per-loops, prestare attenzione, assegna x e y, assegni per uscita len raggiungere 0, e incrementi sia x e y. Lo so, non è quello che ci si aspetterebbe, ma è un codice valido.

  • assegna il carattere presente ad una posizione di carattere corrispondente in str.
  • Verifica se l'attuale carattere è alfanumerico, o di uno dei caratteri _-., e se non lo è, noi facciamo quasi la stessa assegnazione come con UrlEncode dove preforme ricerche, tuttavia, incrementiamo in maniera diversa, utilizzando y++ piuttosto che to[1], questo è perché le stringhe sono in costruzione in modi diversi, ma raggiungere lo stesso obiettivo, alla fine comunque.
  • Quando il ciclo è fatto e della lunghezza di andata, in realtà termina la stringa, assegnando il byte \0.
  • Si restituisce la stringa codificata.

Differenze:

  • controlli UrlEncode per lo spazio, assegna un segno + non, rawurlencode fa.
  • UrlEncode non assegna un byte \0 alla stringa, non rawurlencode (questo può essere un punto controverso)
  • Si iterare differntly, si può essere incline a trabocco con le stringhe malformate, sono semplicemente suggerendo questo e I hanno non in realtà indagata.

Si tratta fondamentalmente iterare in modo diverso, si assegna un segno + in caso di ASCII 20.

Le differenze di EBCDIC:

UrlEncode:

  • configurazione iterazione Uguale con ASCII
  • traducendo ancora il carattere "spazio" per un segno + . Note-- Credo che questo deve essere compilato in EBCDIC o vi ritroverete con un bug? qualcuno può modificare e confermare questo?
  • Verifica se presente char è un char prima 0, con l'eccezione di essere un . o -, O inferiore A ma superiore char 9, O maggiore di Z e meno di a ma non un _. O maggiore z (sì, EBCDIC è un pò incasinato a lavorare). Se corrisponde una di queste, fare una ricerca simile come si trova nella versione ASCII (semplicemente non richiede una ricerca in os_toascii).

rawurlencode:

  • configurazione iterazione Uguale con ASCII
  • stesso controllo come descritto nella versione EBCDIC di URL Encode, con l'eccezione che, se è maggiore di z, esclude ~ dalla codifica URL.
  • Lo stesso incarico come ASCII rawurlencode
  • Ancora aggiungendo il byte \0 alla stringa prima di ritorno.

Grand Sommario

  • Entrambi usano la stessa tabella hexchars di ricerca
  • URIEncode non terminare una stringa con \ 0, crudo fa.
  • Se si lavora in EBCDIC Io suggerirei usando rawurlencode, in quanto gestisce il ~ che UrlEncode meno ( questo è un problema riportato). Vale la pena notare che ASCII e EBCDIC 0x20 sono entrambi gli spazi.
  • Si iterare in modo diverso, si può essere più veloce, si può essere incline alla memoria o una stringa exploit basati.
  • URIEncode rende uno spazio in +, rawurlencode rende uno spazio in %20 tramite ricerche di matrice.

Avviso: Non ho toccato C negli anni, e non ho guardato EBCDIC in modo davvero molto lungo. Se mi sbaglio da qualche parte, me lo faccia sapere.

implementazioni suggerite

In base a tutto questo, rawurlencode è la strada da percorrere la maggior parte del tempo. Come potete vedere nella risposta di Jonathan Fingland, bastone con esso nella maggior parte dei casi. Si tratta del sistema di moderna per i componenti di URI, dove come urlencode fa le cose nel modo vecchia scuola, dove + significava "spazio".

Se stai cercando per la conversione tra il vecchio formato e nuovi formati, essere sicuri che il codice non goof up e girare in modomething che è un segno + decodificato in uno spazio accidentalmente doppio codifica, o simili "oops" scenari attorno a questo / + problema di spazio / 20%.

Se si sta lavorando su un sistema più vecchio con il vecchio software che non preferiscono il nuovo formato, bastone con urlencode, tuttavia, credo% 20 sarà effettivamente compatibile, come sotto il vecchio standard% 20 ha funzionato, basta non fu preferito. Dare un colpo, se siete in su per suonare in giro, fateci sapere come ha funzionato per voi.

In sostanza, si dovrebbe attaccare con crudo, a meno che il vostro sistema EBCDIC davvero ti odia. La maggior parte dei programmatori non incorrere in EBCDIC su qualsiasi sistema realizzato dopo il 2000, forse anche 1990 (che sta spingendo, ma ancora probabile a mio parere).

echo rawurlencode('http://www.google.com/index.html?id=asd asd');

rendimenti

http%3A%2F%2Fwww.google.com%2Findex.html%3Fid%3Dasd%20asd

, mentre

echo urlencode('http://www.google.com/index.html?id=asd asd');

rendimenti

http%3A%2F%2Fwww.google.com%2Findex.html%3Fid%3Dasd+asd

La differenza è il asd%20asd vs asd+asd

urlencode differisce da RFC 1738 codificando spazi come + anziché %20

Una ragione pratica per scegliere uno sopra l'altro è se avete intenzione di utilizzare il risultato in un altro ambiente, per esempio JavaScript.

In PHP urlencode('test 1') rendimenti 'test+1' mentre i rendimenti rawurlencode('test 1') 'test%201' come risultato.

Ma se avete bisogno di "decodificare" questo in JavaScript utilizzando decodeURI () la funzione allora decodeURI("test+1") vi darà "test+1" mentre decodeURI("test%201") vi darà "test 1" come risultato.

In altre parole lo spazio ( " ") codificata da urlencode per più (" +") in PHP non saranno correttamente decodificato da decodeURI in JavaScript.

In tali casi il rawurlencode PHP funzione deve essere utilizzata.

Credo che gli spazi devono essere codificati come:

  • %20 quando viene utilizzato all'interno componente sentiero URL
  • + quando utilizzato all'interno di dati dei componenti stringa di query URL o di forma (vedi 17.13.4 tipi di contenuto modulo )

Il seguente esempio illustra il corretto utilizzo del rawurlencode e urlencode :

echo "http://example.com"
    . "/category/" . rawurlencode("latest songs")
    . "/search?q=" . urlencode("lady gaga");

Output:

http://example.com/category/latest%20songs/search?q=lady+gaga

Che cosa succede se si codifica di percorso e di query componenti stringa il contrario? Per il seguente esempio:

http://example.com/category/latest+songs/search?q=lady%20gaga
  • Il server web cercherà la directory latest+songs invece di latest songs
  • Il parametro di stringa di query q conterrà lady gaga

La differenza è nei valori di ritorno, cioè:

UrlEncode () :

  

Restituisce una stringa in cui tutti   caratteri non alfanumerici, ad eccezione -_.   sono stati sostituiti con una percentuale (%)   segno seguito da due cifre esadecimali e   spazi codificati come (+) segno più. esso   è codificato allo stesso modo che la   dati pubblicati da un modulo di WWW è   codificato, che è allo stesso modo come in   application / x-www-form-urlencoded   tipo di supporto. Ciò differisce dalla »   RFC 1738 codifica (vedi rawurlencode ())   in quanto per ragioni storiche, spazi   sono codificati come (+) segno più.

rawurlencode () :

  

Restituisce una stringa in cui tutti   caratteri non alfanumerici, ad eccezione -_.   sono stati sostituiti con una percentuale (%)   segno seguito da due cifre esadecimali. Questo   è la codifica descritto in »RFC   1738 per proteggere caratteri letterali   possa essere interpretato come URL speciale   delimitatori, e per proteggere gli URL   dall'essere mangled mediante trasmissione   media con la conversione dei caratteri (come   alcuni sistemi di posta elettronica).

I due sono molto simili, ma quest'ultimo (rawurlencode) sostituirà spazi con un '%' e due cifre esadecimali, che è adatto per la codifica password o simile, in cui un '+' non è per esempio:.

echo '<a href="ftp://user:', rawurlencode('foo @+%/'),
     '@ftp.example.com/x.txt">';
//Outputs <a href="ftp://user:foo%20%40%2B%25%2F@ftp.example.com/x.txt">

1. Quali sono esattamente le differenze e le

L'unica differenza è nel modo in cui vengono trattati gli spazi:

urlencode - sulla base di implementazione eredità converte gli spazi per +

rawurlencode - basata su RFC 1738 traduce gli spazi per 20%

La ragione di questa differenza è perché + è riservato e valido (in chiaro) negli URL.

2. che viene preferito?

  

Mi piacerebbe davvero vedere alcune ragioni per scegliere uno sopra l'altro ... io voglio essere in grado di sceglierne solo uno e usarlo per sempre con il minimo sforzo.

Va bene, ho una semplice strategia che seguo quando prendere queste decisioni, che voglio condividere con voi nella speranza che possa aiutare.

Credo che sia stata l'HTTP / 1.1 specifica RFC 2616 che ha chiesto di " applicazioni tolleranti "

  

Clienti DOVREBBE essere tolleranti nella analisi del Status-Line e server      tolleranti quando analizza la linea di richiesta.

Di fronte a domande come queste la strategia migliore è sempre quello di consumare il più possibile e di produrre ciò che è conforme agli standard.

Quindi il mio consiglio è di usare rawurlencode per la produzione di norme conformi RFC 1738 codifica stringhe e utilizzare urldecode per essere compatibile e accogliere tutto ciò che si può incontrare a consumare.

Ora si può solo prendere la mia parola per esso, ma lascia dimostrarlo che ne dite ...

php > $url = <<<'EOD'
<<< > "Which, % of Alice's tasks saw $s @ earnings?"
<<< > EOD;
php > echo $url, PHP_EOL;
"Which, % of Alice's tasks saw $s @ earnings?"
php > echo urlencode($url), PHP_EOL;
%22Which%2C+%25+of+Alice%27s+tasks+saw+%24s+%40+earnings%3F%22
php > echo rawurlencode($url), PHP_EOL;
%22Which%2C%20%25%20of%20Alice%27s%20tasks%20saw%20%24s%20%40%20earnings%3F%22
php > echo rawurldecode(urlencode($url)), PHP_EOL;
"Which,+%+of+Alice's+tasks+saw+$s+@+earnings?"
php > // oops that's not right???
php > echo urldecode(rawurlencode($url)), PHP_EOL;
"Which, % of Alice's tasks saw $s @ earnings?"
php > // now that's more like it

Sembrerebbe che PHP ha avuto esattamente questo in mente, anche se non ho mai incontrato nessuno rifiutando uno dei due formati, non posso pensare ad una migliore strategia di adottare come la vostra strategia di fatto, si può?

nJoy!

  

urlencode : Questo è diverso dal   »RFC 1738 codifica (vedi   rawurlencode ()) in quanto per storica   ragioni, gli spazi sono codificati come più   (+) I segni.

Spazi codificati come %20 vs. +

Il più grande motivo che ho visto usare rawurlencode() nella maggior parte dei casi è dovuto al fatto urlencode codifica spazi di testo come + (più segni) dove rawurlencode li codifica come il %20 comunemente visto:

echo urlencode("red shirt");
// red+shirt

echo rawurlencode("red shirt");
// red%20shirt

Ho visto in particolare alcuni punti finali API che accettano codificati query di testo si aspettano di vedere %20 per uno spazio e, di conseguenza, non riescono se un segno più viene usato al posto. Ovviamente questo sta andando a variare tra le implementazioni di API e la vostra situazione potrebbe essere diversa.

Credo urlencode è per i parametri di ricerca, mentre la rawurlencode è per i segmenti di percorso. Ciò è principalmente dovuto al %20 per segmenti di percorso vs + per parametri di ricerca. Vedere questa risposta che parla di spazi: Quando codificare lo spazio per più ( +) o 20%?

Tuttavia %20 ora lavora a parametri di query pure, che è il motivo per rawurlencode è sempre più sicuro. Tuttavia, il segno più tende ad essere utilizzato in cui l'esperienza degli utenti di editing e la leggibilità dei Parametri query materia.

Si noti che questo significa rawurldecode non decodifica + in spazi ( http: / /au2.php.net/manual/en/function.rawurldecode.php ). Questo è il motivo per cui il $ _GET viene sempre passato automaticamente attraverso urldecode, il che significa che + e %20 sono entrambi decodificati in spazi.

Se si desidera che la codifica e decodifica siano coerenti tra ingressi e uscite e selezionato usare sempre + e non %20 per i parametri di ricerca, allora urlencode va bene per parametri di ricerca (chiave e il valore).

La conclusione è:

segmenti di percorso - sempre usare rawurlencode / rawurldecode

parametri di query -. Per la decodifica utilizzare sempre urldecode (fatto automaticamente), per la codifica, sia rawurlencode o urlencode va bene, basta scegliere uno per essere coerenti, soprattutto quando si confrontano gli URL

semplice * Rawurlencode il percorso - percorso è la parte prima che il "?" - spazi devono essere codificati come% 20 * UrlEncode la stringa di query - stringa di query è la parte dopo il "?" -spaces sono meglio codificati come "+" = Rawurlencode è più compatibile in generale

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top