419 Stimmen

urlencode vs. rawurlencode?

Wenn ich eine URL mit einer Variablen erstellen möchte, habe ich zwei Möglichkeiten, die Zeichenfolge zu kodieren. urlencode() y rawurlencode() .

Was genau sind die Unterschiede und was ist vorzuziehen?

1 Stimmen

Ich würde wirklich gerne einige Gründe für die Wahl des einen gegenüber dem anderen sehen (z.B. Probleme, die mit dem einen oder dem anderen auftreten könnten), ich (und ich erwarte, dass andere) in der Lage sein wollen, sich einfach für eines zu entscheiden und es für immer mit dem geringsten Aufwand zu benutzen, also habe ich ein Kopfgeld auf diese Frage ausgesetzt.

37 Stimmen

@Tchalvak: Wenn Sie nur einen auswählen wollen, wählen Sie rawurlencode . Sie werden nur selten auf ein System stoßen, das bei Leerzeichen, die als %20 , während Systeme, die an Räumen, die als + sind häufiger anzutreffen.

350voto

Jonathan Fingland Punkte 54655

Das hängt von Ihrem Ziel ab. Wenn die Interoperabilität mit anderen Systemen wichtig ist, scheint rawurlencode der richtige Weg zu sein. Die einzige Ausnahme sind Altsysteme, die erwarten, dass der Abfrage-String dem Form-Encoding-Stil folgt und Leerzeichen als + statt als %20 kodiert werden (in diesem Fall benötigen Sie urlencode).

rawurlencode folgt RFC 1738 vor PHP 5.3.0 und RFC 3986 danach (siehe http://us2.php.net/manual/en/function.rawurlencode.php )

Gibt eine Zeichenkette zurück, in der alle nicht-alphanumerischen Zeichen außer -_.~ durch ein Prozentzeichen (%), gefolgt von zwei Hex-Ziffern, ersetzt wurden. Dies ist die Kodierung, die in " RFC 3986 beschrieben wird, um zu verhindern, dass literale Zeichen als spezielle URL-Begrenzungszeichen interpretiert werden, und um zu verhindern, dass URLs von Übertragungsmedien mit Zeichenumwandlungen (wie einigen E-Mail-Systemen) verstümmelt werden.

Anmerkung zu RFC 3986 vs. 1738. rawurlencode kodierte vor php 5.3 das Tilde-Zeichen ( ~ ) gemäß RFC 1738. Seit PHP 5.3 folgt rawurlencode jedoch RFC 3986, das keine Verschlüsselung von Tilde-Zeichen erfordert.

urlencode kodiert Leerzeichen als Pluszeichen (nicht als %20 wie in rawurlencode) (siehe http://us2.php.net/manual/en/function.urlencode.php )

Gibt eine Zeichenkette zurück, in der alle nicht alphanumerischen Zeichen außer -_. durch ein Prozentzeichen (%), gefolgt von zwei Hex-Ziffern und Leerzeichen, die als Pluszeichen (+) kodiert sind, ersetzt wurden. Die Kodierung erfolgt auf dieselbe Weise wie die Kodierung der gesendeten Daten aus einem WWW-Formular, d. h. auf dieselbe Weise wie beim Medientyp application/x-www-form-urlencoded. Dies unterscheidet sich von der " RFC 3986-Kodierung (siehe rawurlencode()) dadurch, dass aus historischen Gründen Leerzeichen als Pluszeichen (+) kodiert werden.

Dies entspricht der Definition für application/x-www-form-urlencoded in RFC 1866 .

Weitere Lektüre:

Vielleicht interessiert Sie auch die Diskussion unter http://bytes.com/groups/php/5624-urlencode-vs-rawurlencode .

Auch, RFC 2396 ist einen Blick wert. RFC 2396 definiert die gültige URI-Syntax. Der wichtigste Teil, der uns interessiert, stammt aus 3.4 Query Component:

Innerhalb einer Abfragekomponente werden die Zeichen ";", "/", "?", ":", "@", "&", "=", "+", ",", and "$" sind reserviert.

Wie Sie sehen können, ist die + ist ein reserviertes Zeichen in der Abfragezeichenfolge und müsste daher gemäß RFC 3986 kodiert werden (wie in rawurlencode).

85 Stimmen

Rawurlencode. Verwenden Sie in diesem Fall den Standard. urlencode wird nur noch für ältere Anwendungen verwendet.

2 Stimmen

Vielen Dank, das ist, was ich dachte, ich wollte nur eine zweite Meinung, bevor ich anfangen, viel Code zu aktualisieren.

0 Stimmen

Es scheint auch, dass ich in meiner anfänglichen Analyse falsch lag, dass urlencode die Legacy-Option war. siehe meine Bearbeitung für weitere Informationen

223voto

Incognito Punkte 19941

Der Beweis steht im Quellcode von PHP.

Ich zeige Ihnen, wie Sie diese Dinge in Zukunft selbst herausfinden können, wann immer Sie wollen. Haben Sie etwas Geduld mit mir, es wird viel C-Quellcode geben, den Sie überfliegen können (ich erkläre ihn). Wenn Sie Ihre C-Kenntnisse auffrischen möchten, ist unser SO-Wiki ein guter Ausgangspunkt .

Laden Sie den Quelltext herunter (oder verwenden Sie http://lxr.php.net/ um sie online zu durchsuchen), suchen Sie in allen Dateien nach dem Namen der Funktion und Sie werden etwas wie dieses finden:

PHP 5.3.6 (die aktuellste Version zum Zeitpunkt der Erstellung dieses Artikels) beschreibt die beiden Funktionen in ihrem nativen C-Code in der Datei 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);
}

Okay, was ist hier also anders?

Beide rufen im Wesentlichen zwei verschiedene interne Funktionen auf: php_raw_url_encode y php_url_encode

Suchen Sie also nach diesen Funktionen!

Sehen wir uns php_raw_url_encode an

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);
}

Und natürlich 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;
}

Bevor ich weitermache, möchte ich noch kurz etwas wissen, EBCDIC ist ein weiterer Zeichensatz ähnlich wie ASCII, aber ein absoluter Konkurrent. PHP versucht, mit beiden umzugehen. Aber im Grunde genommen bedeutet dies, dass das Byte EBCDIC 0x4c nicht das Byte L in ASCII, ist es eigentlich ein < . Ich bin sicher, dass Sie die Verwirrung hier sehen.

Diese beiden Funktionen verwalten EBCDIC, wenn der Webserver dies definiert hat.

Außerdem verwenden beide ein Array von Zeichen (denken Sie an den Typ String) hexchars Nachschlagen, um einige Werte zu erhalten, wird das Feld als solches beschrieben:

/* 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";

Darüber hinaus sind die Funktionen sehr unterschiedlich, und ich werde sie in ASCII und EBCDIC erklären.

Unterschiede bei ASCII:

URLENCODE:

  • Berechnet eine Start-/Endlänge der Eingabezeichenkette, weist Speicher zu
  • Durchläuft eine while-Schleife, inkrementiert, bis das Ende der Zeichenkette erreicht ist
  • Ergreift das gegenwärtige Zeichen
  • Entspricht das Zeichen dem ASCII-Zeichen 0x20 (d.h. ein "Leerzeichen"), fügen Sie ein + Zeichen in die Ausgabezeichenfolge ein.
  • Wenn es sich nicht um ein Leerzeichen und auch nicht um eine alphanumerische Zahl handelt ( isalnum(c) ), und ist auch nicht und _ , - , oder . Zeichen, dann geben wir , eine % auf die Position 0 des Arrays setzen, einen Array-Look-up auf die hexchars Array für eine Suche nach os_toascii Array (ein Array aus Apache, der übersetzt char in Hex-Code) für den Schlüssel von c (das aktuelle Zeichen), schieben wir dann bitweise um 4 nach rechts, weisen diesen Wert dem Zeichen 1 zu, und der Position 2 weisen wir das gleiche Lookup zu, außer dass wir eine logische Prüfung durchführen, um zu sehen, ob der Wert 15 (0xF) ist, und in diesem Fall eine 1 zurückgeben, oder andernfalls eine 0. Am Ende erhält man ein kodiertes Ergebnis.
  • Wenn es am Ende kein Leerzeichen ist, ist es alphanumerisch oder eine der _-. Zeichen, gibt er genau das aus, was er ist.

RAWURLENCODE:

  • Weist Speicher für die Zeichenkette zu
  • Iteriert darüber auf der Grundlage der im Funktionsaufruf angegebenen Länge (nicht in der Funktion berechnet wie bei URLENCODE).

Note : Viele Programmierer haben wahrscheinlich noch nie eine for-Schleife auf diese Weise iterieren sehen, es ist etwas hakelig und nicht die Standardkonvention, die bei den meisten for-Schleifen verwendet wird, passen Sie auf, es weist zu x y y prüft für den Ausgang auf len den Wert 0 erreicht, und erhöht beide x y y . Ich weiß, es ist nicht das, was Sie erwarten würden, aber es ist ein gültiger Code.

  • Weist das aktuelle Zeichen einer passenden Zeichenposition in str .
  • Es wird geprüft, ob das vorliegende Zeichen alphanumerisch ist oder eine der _-. Zeichen, und wenn dies nicht der Fall ist, führen wir fast dieselbe Zuweisung wie bei URLENCODE durch, wobei wir jedoch anders inkrementieren, indem wir y++ statt to[1] Das liegt daran, dass die Saiten auf unterschiedliche Weise aufgebaut werden, aber am Ende trotzdem das gleiche Ziel erreichen.
  • Wenn die Schleife beendet ist und die Länge abgelaufen ist, wird die Zeichenkette tatsächlich beendet und die \0 byte.
  • Sie gibt die kodierte Zeichenkette zurück.

Die Unterschiede:

  • UrlEncode prüft auf Leerzeichen, weist ein +-Zeichen zu, RawURLEncode tut dies nicht.
  • UrlEncode weist keine \0 Byte an die Zeichenkette an, RawUrlEncode tut dies (dies ist möglicherweise ein strittiger Punkt)
  • Sie iterieren unterschiedlich, eine davon kann bei fehlerhaften Zeichenketten zum Überlauf neigen, ich bin nur andeutend dies und ich haben nicht tatsächlich untersucht.

Sie iterieren grundsätzlich unterschiedlich, man vergibt ein + Zeichen bei ASCII 20.

Unterschiede in EBCDIC:

URLENCODE:

  • Gleicher Iterationsaufbau wie bei ASCII
  • Das Zeichen "Leerzeichen" wird immer noch in ein "+" übersetzt. Zeichen. Hinweis: Ich denke, dass dies in EBCDIC kompiliert werden muss, da sonst ein Fehler auftritt. Kann jemand dies bearbeiten und bestätigen?
  • Es prüft, ob das vorliegende Zeichen ein Zeichen vor 0 mit Ausnahme der Tatsache, dass er ein . ou - , OR weniger als A aber größer als char 9 , OR größer als Z und weniger als a aber nicht ein _ . OR größer als z (ja, EBCDIC ist ein ziemlicher Schlamassel). Wenn es mit einem dieser Werte übereinstimmt, führen Sie eine ähnliche Suche wie in der ASCII-Version durch (es ist nur keine Suche in os_toascii erforderlich).

RAWURLENCODE:

  • Gleicher Iterationsaufbau wie bei ASCII
  • Dieselbe Prüfung wie in der EBCDIC-Version von URL Encode beschrieben, mit der Ausnahme, dass, wenn der Wert größer als z schließt sie aus ~ aus der URL-Kodierung.
  • Gleiche Zuordnung wie beim ASCII RawUrlEncode
  • Noch das Anhängen der \0 Byte an die Zeichenkette an, bevor sie zurückgegeben wird.

Große Zusammenfassung

  • Beide verwenden die gleiche Hexchars-Lookup-Tabelle
  • URIEncode beendet eine Zeichenkette nicht mit \0 roh tut.
  • Wenn Sie in EBCDIC arbeiten, würde ich die Verwendung von RawUrlEncode vorschlagen, da es die ~ die UrlEncode nicht hat ( dies ist ein gemeldetes Problem ). Es ist erwähnenswert, dass ASCII und EBCDIC 0x20 beide Leerzeichen sind.
  • Sie iterieren unterschiedlich, eine kann schneller sein, eine kann anfällig für speicher- oder stringbasierte Exploits sein.
  • URIEncode macht ein Leerzeichen zu + macht RawUrlEncode ein Leerzeichen zu %20 über Array-Lookups.

Haftungsausschluss: Ich habe C seit Jahren nicht mehr angefasst, und mit EBCDIC habe ich mich schon sehr, sehr lange nicht mehr beschäftigt. Wenn ich irgendwo falsch liege, lassen Sie es mich wissen.

Vorgeschlagene Implementierungen

Aus all diesen Gründen ist rawurlencode in den meisten Fällen der richtige Weg. Wie Sie in der Antwort von Jonathan Fingland sehen, sollten Sie in den meisten Fällen dabei bleiben. Es befasst sich mit dem modernen Schema für URI-Komponenten, während urlencode Dinge auf die alte Art und Weise tut, wo + "Leerzeichen" bedeutete.

Wenn Sie versuchen, zwischen dem alten und dem neuen Format zu konvertieren, stellen Sie sicher, dass Ihr Code keine Fehler macht und etwas, das ein dekodiertes +-Zeichen ist, durch versehentliche Doppelkodierung in ein Leerzeichen verwandelt, oder ähnliche "Oops"-Szenarien rund um dieses Leerzeichen/20%/+-Problem.

Wenn Sie auf einem älteren System mit älterer Software arbeiten, die das neue Format nicht bevorzugt, sollten Sie bei urlencode bleiben. Ich glaube jedoch, dass %20 rückwärtskompatibel ist, da %20 nach dem alten Standard funktionierte, nur nicht bevorzugt wurde. Probieren Sie es aus, wenn Sie Lust haben, herumzuspielen, und lassen Sie uns wissen, wie es bei Ihnen funktioniert hat.

Im Grunde genommen sollten Sie bei Raw bleiben, es sei denn, Ihr EBCDIC-System hasst Sie wirklich. Die meisten Programmierer werden nie auf EBCDIC auf einem System stoßen, das nach dem Jahr 2000 gebaut wurde, vielleicht sogar nach 1990 (das ist zwar etwas übertrieben, aber meiner Meinung nach immer noch wahrscheinlich).

0 Stimmen

Ich musste mir noch nie Gedanken über eine doppelte Kodierung machen, schließlich sollte ich wissen, was ich kodiert habe, da ich es bin, der die Kodierung vornimmt, würde ich meinen. Da ich alles, was ich empfange, mit dem Kompatibilitätsmodus dekodiere, der weiß, wie man + als Leerzeichen behandelt, bin ich auch nie auf die Probleme gestoßen, vor denen Sie hier zu warnen versuchen. Ich kann verstehen, dass man sich den Quelltext ansieht, wenn man nicht weiß, was etwas tut, aber was genau haben wir hier gelernt, was wir nicht schon wussten, als wir einfach beide Funktionen ausgeführt haben. Ich weiß, dass ich voreingenommen bin, aber ich kann mir nicht helfen, aber ich denke, dass dies weit über das Ziel hinausgeschossen ist. Trotzdem: Hut ab vor der Leistung! =)

2 Stimmen

+1, für diesen Teil: "Ich glaube, dass %20 tatsächlich rückwärtskompatibel sein wird, denn nach dem alten Standard funktionierte %20, wurde aber nicht bevorzugt."

0 Stimmen

"UrlEncode weist keine \0 Byte zur Zeichenkette" Dies ist nicht korrekt. Er macht es einfach anders. Siehe *to = 0; . Das kann als Zuweisung des Wertes Null an die Stelle gelesen werden, an der to Punkte. Und das zu dieser Zeit, to zeigt auf die Stelle, an der das Null-Byte stehen sollte. Auch, 0 y '\0' sind gleich, sie drücken nur das Gleiche auf unterschiedliche Weise aus.

39voto

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

ergibt

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

während

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

ergibt

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

Der Unterschied besteht darin, dass die asd%20asd vs asd+asd

urlencode unterscheidet sich von RFC 1738 durch die Kodierung von Leerzeichen als + anstelle von %20

29voto

Neven Boyanov Punkte 739

Ein praktischer Grund, sich für das eine oder das andere zu entscheiden, ist die Verwendung des Ergebnisses in einer anderen Umgebung, z. B. in JavaScript.

In PHP urlencode('test 1') gibt zurück. 'test+1' während rawurlencode('test 1') gibt zurück. 'test%201' als Ergebnis.

Aber wenn Sie dies in JavaScript "entschlüsseln" müssen, indem Sie decodeURI() Funktion dann decodeURI("test+1") wird Ihnen "test+1" während decodeURI("test%201") wird Ihnen "test 1" als Ergebnis.

Mit anderen Worten, das Leerzeichen (" "), das durch urlencode als Plus ("+") in PHP wird nicht richtig dekodiert von decodeURI in JavaScript.

In solchen Fällen ist die rawurlencode PHP-Funktion verwendet werden sollte.

0 Stimmen

Es ist ein schönes Beispiel, obwohl ich lieber json_encode y JSON.parse zu diesem Zweck.

22voto

Salman A Punkte 246207

Ich glaube, Leerzeichen müssen als kodiert werden:

  • %20 bei Verwendung innerhalb der URL-Pfadkomponente
  • + wenn es innerhalb einer URL-Abfrage-String-Komponente oder von Formulardaten verwendet wird (siehe 17.13.4 Formularinhaltstypen )

Das folgende Beispiel zeigt die korrekte Verwendung von rawurlencode y urlencode :

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

Salida:

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

Was passiert, wenn Sie die Komponenten von Pfad und Abfragezeichenfolge andersherum kodieren? Für das folgende Beispiel:

http://example.com/category/latest+songs/search?q=lady%20gaga
  • Der Webserver sucht nach dem Verzeichnis latest+songs anstelle von latest songs
  • Der Parameter für die Abfragezeichenfolge q wird enthalten lady gaga

2 Stimmen

"Der Parameter der Abfragezeichenfolge q wird enthalten lady gaga " Was sollte er sonst enthalten? Der Abfrageparameter q scheint den gleichen Wert zu haben, der an die $_GET Array unabhängig von der Verwendung von rawurlencode o urlencode in PHP 5.2+. Allerdings, urlencode kodiert in der application/x-www-form-urlencoded Format, das standardmäßig für GET-Anfragen verwendet wird, also wende ich Ihren Ansatz an. +1

2 Stimmen

Ich wollte klarstellen, dass beide + y %20 werden als Leerzeichen dekodiert, wenn sie in Abfragezeichenfolgen verwendet werden.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X