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?
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?
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).
Rawurlencode. Verwenden Sie in diesem Fall den Standard. urlencode wird nur noch für ältere Anwendungen verwendet.
Vielen Dank, das ist, was ich dachte, ich wollte nur eine zweite Meinung, bevor ich anfangen, viel Code zu aktualisieren.
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
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!
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);
}
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.
URLENCODE:
+
Zeichen in die Ausgabezeichenfolge ein.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._-.
Zeichen, gibt er genau das aus, was er ist.RAWURLENCODE:
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.
str
._-.
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.\0
byte.Die Unterschiede:
\0
Byte an die Zeichenkette an, RawUrlEncode tut dies (dies ist möglicherweise ein strittiger Punkt)Sie iterieren grundsätzlich unterschiedlich, man vergibt ein + Zeichen bei ASCII 20.
URLENCODE:
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:
z
schließt sie aus ~
aus der URL-Kodierung.\0
Byte an die Zeichenkette an, bevor sie zurückgegeben wird.~
die UrlEncode nicht hat ( dies ist ein gemeldetes Problem ). Es ist erwähnenswert, dass ASCII und EBCDIC 0x20 beide Leerzeichen sind.+
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.
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).
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! =)
+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."
"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.
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
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.
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
latest+songs
anstelle von latest songs
q
wird enthalten lady gaga
"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
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.
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.