serialize codificar code php urlencode url-encoding

php - codificar - urlencode vs rawurlencode?



url encode laravel (11)

Si quiero crear una URL usando una variable, tengo dos opciones para codificar la cadena. urlencode() y rawurlencode() .

¿Cuáles son exactamente las diferencias y cuál es la preferida?



1. ¿Cuáles son exactamente las diferencias y

La única diferencia es en la forma en que se tratan los espacios:

urlencode - basado en implementaciones heredadas convierte espacios a +

rawurlencode - basado en RFC 1738 traduce espacios a% 20

El motivo de la diferencia es que + es reservado y válido (no codificado) en las URL.

2. ¿Cuál es el preferido?

Realmente me gustaría ver algunas razones para elegir una sobre la otra ... Quiero poder simplemente elegir una y usarla para siempre con el menor problema.

Justo lo suficiente, tengo una estrategia simple que sigo al tomar estas decisiones que compartiré con usted con la esperanza de que pueda ayudar.

Creo que fue la especificación HTTP / 1.1 RFC 2616 la que pedía " Aplicaciones tolerantes "

Los clientes DEBEN ser tolerantes al analizar la línea de estado y los servidores tolerantes al analizar la línea de solicitud.

Cuando nos enfrentamos a preguntas como estas, la mejor estrategia es siempre consumir todo lo posible y producir lo que cumple con las normas.

Por lo tanto, mi consejo es utilizar el rawurlencode en rawurlencode para producir cadenas codificadas RFC 1738 que cumplan con los estándares y usar el urldecode de urldecode para que sea compatible con versiones anteriores y acomodar cualquier cosa que pueda llegar a consumir.

Ahora solo puede tomar mi palabra, pero demostrémoslo si ...

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

Parecería que PHP tenía exactamente esto en mente, aunque nunca he encontrado a nadie que rechace ninguno de los dos formatos, no puedo pensar en una mejor estrategia para adoptar como su estrategia de facto, ¿verdad?

nJoy!


Espacios codificados como %20 vs. +

La razón principal por la que he visto usar rawurlencode() en la mayoría de los casos es porque urlencode codifica espacios de texto como + (signos más), donde rawurlencode codifica como el %20 comúnmente visto:

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

He visto específicamente que ciertos puntos finales de la API que aceptan consultas de texto codificado esperan ver %20 para un espacio y, como resultado, fallan si en su lugar se utiliza un signo más. Obviamente, esto va a diferir entre las implementaciones de API y su kilometraje puede variar.


Creo que los espacios deben estar codificados como:

  • %20 cuando se usa dentro del componente de la ruta URL
  • + cuando se utiliza dentro del componente de cadena de consulta de URL o datos de formulario (consulte 17.13.4 Tipos de contenido de formulario )

El siguiente ejemplo muestra el uso correcto de 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

¿Qué sucede si codificas la ruta y los componentes de la cadena de consulta al revés? Para el siguiente ejemplo:

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

  • El servidor web buscará el directorio latest+songs lugar de las latest songs
  • El parámetro de cadena de consulta q contendrá lady gaga

Creo que urlencode es para los parámetros de consulta, mientras que el rawurlencode es para los segmentos de ruta. Esto se debe principalmente a %20 para segmentos de ruta vs + para parámetros de consulta. Vea esta respuesta que habla sobre los espacios: ¿ Cuándo codificar el espacio para más (+) o% 20?

Sin embargo, %20 ahora también funciona en parámetros de consulta, por lo que rawurlencode siempre es más seguro. Sin embargo, el signo más tiende a usarse cuando la experiencia del usuario en la edición y la legibilidad de los parámetros de consulta son importantes.

Tenga en cuenta que esto significa que rawurldecode no decodifica + en espacios ( http://au2.php.net/manual/en/function.rawurldecode.php ). Esta es la razón por la que $ _GET siempre se pasa automáticamente a través de urldecode , lo que significa que + y %20 se descodifican en espacios.

Si desea que la codificación y la decodificación sean coherentes entre las entradas y las salidas y ha seleccionado usar siempre + y no %20 para los parámetros de consulta, entonces urlencode está bien para los parámetros de consulta (clave y valor).

La conclusión es:

Segmentos de ruta de acceso: utilice siempre el código / código de código bruto

Parámetros de consulta: para decodificar siempre use urldecode (hecho automáticamente), para codificar, tanto rawurlencode como urlencode están bien, solo elija uno para que sea consistente, especialmente al comparar URL.


Dependerá de su propósito. Si la interoperabilidad con otros sistemas es importante, entonces parece que Rawur es el camino a seguir. La única excepción son los sistemas heredados que esperan que la cadena de consulta siga el estilo de codificación de formulario de los espacios codificados como + en lugar de% 20 (en cuyo caso necesita urlencode).

rawurlencode sigue RFC 1738 antes de PHP 5.3.0 y RFC 3986 después (vea http://us2.php.net/manual/en/function.rawurlencode.php )

Devuelve una cadena en la que todos los caracteres no alfanuméricos excepto -_. ~ Se han reemplazado con un signo de porcentaje (%) seguido de dos dígitos hexadecimales. Esta es la codificación descrita en »RFC 3986 para evitar que los caracteres literales se interpreten como delimitadores de URL especiales, y para evitar que las URL se conviertan en medios de transmisión con conversiones de caracteres (como algunos sistemas de correo electrónico).

Nota sobre RFC 3986 vs 1738. rawurlencode antes de php 5.3 codificó el carácter de tilde ( ~ ) de acuerdo con RFC 1738. Sin embargo, a partir de PHP 5.3, rawurlencode sigue a RFC 3986 que no requiere la codificación de caracteres de tilde.

urlencode codifica espacios como signos más (no como %20 como se hace en rawurlencode) (vea http://us2.php.net/manual/en/function.urlencode.php )

Devuelve una cadena en la que todos los caracteres no alfanuméricos, excepto -_. se han reemplazado con un signo de porcentaje (%) seguido de dos dígitos hexadecimales y espacios codificados como signos más (+). Se codifica de la misma manera que se codifican los datos publicados desde un formulario WWW, es decir, de la misma forma que en el tipo de medio de aplicación / x-www-form-urlencoded. Esto difiere de la codificación »RFC 3986 (vea rawurlencode ()) en que, por razones históricas, los espacios se codifican como signos más (+).

Esto corresponde a la definición de aplicación / x-www-form-urlencoded en RFC 1866 .

Lectura adicional:

También puede querer ver la discusión en http://bytes.com/groups/php/5624-urlencode-vs-rawurlencode .

Además, RFC 2396 merece una visita. RFC 2396 define la sintaxis URI válida. La parte principal en la que estamos interesados ​​es del componente de consulta 3.4:

Dentro de un componente de consulta, los caracteres ";", "/", "?", ":", "@",
"&", "=", "+", ",", and "$"
";", "/", "?", ":", "@",
"&", "=", "+", ",", and "$"
";", "/", "?", ":", "@",
"&", "=", "+", ",", and "$"
están reservados.

Como puede ver, el + es un carácter reservado en la cadena de consulta y, por lo tanto, deberá codificarse según RFC 3986 (como en rawurlencode).


La diferencia está en los valores de retorno, es decir:

http://us2.php.net/manual/en/function.urlencode.php :

Devuelve una cadena en la que todos los caracteres no alfanuméricos, excepto -_. se han reemplazado con un signo de porcentaje (%) seguido de dos dígitos hexadecimales y espacios codificados como signos más (+). Se codifica de la misma manera que se codifican los datos publicados desde un formulario WWW, es decir, de la misma forma que en el tipo de medio de aplicación / x-www-form-urlencoded. Esto difiere de la codificación »RFC 1738 (vea rawurlencode ()) en que, por razones históricas, los espacios se codifican como signos más (+).

http://us2.php.net/manual/en/function.rawurlencode.php :

Devuelve una cadena en la que todos los caracteres no alfanuméricos, excepto -_. se han reemplazado con un signo de porcentaje (%) seguido de dos dígitos hexadecimales. Esta es la codificación descrita en »RFC 1738 para evitar que los caracteres literales se interpreten como delimitadores de URL especiales, y para evitar que las URL se conviertan en medios de transmisión con conversiones de caracteres (como algunos sistemas de correo electrónico).

Los dos son muy similares, pero el último (rawurlencode) reemplazará los espacios con un ''%'' y dos dígitos hexadecimales, que es adecuado para codificar contraseñas o similares, donde un ''+'' no es, por ejemplo:

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


La prueba está en el código fuente de PHP.

Lo guiaré a través de un proceso rápido de cómo descubrir este tipo de cosas por su cuenta en el futuro en el momento que lo desee. Tenga paciencia conmigo, habrá un montón de código fuente en C que puede hojear (lo explico). Si quieres refrescar algo de C, un buen lugar para comenzar es nuestra wiki de SO .

Descargue la fuente (o use http://lxr.php.net/ para buscarla en línea), grep todos los archivos para el nombre de la función, encontrará algo como esto:

PHP 5.3.6 (más reciente en el momento de la escritura) describe las dos funciones en su código C nativo en el archivo 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); }

Bien, entonces, ¿qué es diferente aquí?

Ambos están esencialmente llamando a dos funciones internas diferentes respectivamente: php_raw_url_encode y php_url_encode

¡Así que ve a buscar esas funciones!

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

Y por supuesto, 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 poco de conocimiento antes de seguir adelante, EBCDIC es otro conjunto de caracteres , similar a ASCII, pero un competidor total. PHP intenta lidiar con ambos. Pero básicamente, esto significa que el byte EBCDIC 0x4c byte no es la L en ASCII, en realidad es un < . Estoy seguro de que ves la confusión aquí.

Ambas funciones administran EBCDIC si el servidor web lo ha definido.

Además, ambos usan una matriz de caracteres (tipo de cadena de hexchars ) hexchars de caracteres hexchars para obtener algunos valores, la matriz se describe como tal:

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

Más allá de eso, las funciones son realmente diferentes, y las explicaré en ASCII y EBCDIC.

Diferencias en ASCII:

URLENCODE:

  • Calcula una longitud de inicio / final de la cadena de entrada, asigna memoria
  • Camina a través de un bucle while, incrementa hasta que llegamos al final de la cadena
  • Agarra el personaje actual.
  • Si el carácter es igual a ASCII Char 0x20 (es decir, un "espacio"), agregue un signo + a la cadena de salida.
  • Si no es un espacio, y tampoco es alfanumérico ( isalnum(c) ), y tampoco es y _ , - , o . carácter, luego nosotros, emitimos un signo % a la posición 0 de la matriz, hacemos una búsqueda de matriz a la matriz hexchars para una búsqueda de la matriz os_toascii (una matriz de Apache que traduce el código char a hex) para la clave de c (el carácter actual ), luego, a nivel de bits, cambiamos a la derecha por 4, asignamos ese valor al carácter 1, y a la posición 2 asignamos la misma búsqueda, excepto que realizamos una lógica y para ver si el valor es 15 (0xF), y devolvemos un 1 en ese caso, o un 0 de lo contrario. Al final, terminarás con algo codificado.
  • Si termina no es un espacio, es alfanumérico o uno de los _-. caracteres, produce exactamente lo que es.

RAWURLENCODE:

  • Asigna memoria para la cadena.
  • Iteriza sobre él según la longitud proporcionada en la llamada de función (no calculada en función como con URLENCODE)

Nota: Muchos programadores probablemente nunca han visto una iteración de bucle for de esta manera, es un tanto pirata y no es la convención estándar utilizada con la mayoría de los bucles for, preste atención, asigna y , comprueba la salida en len llega a 0 e incrementa ambos x y y . Lo sé, no es lo que esperas, pero es un código válido.

  • Asigna el carácter actual a una posición de carácter coincidente en str .
  • Comprueba si el carácter actual es alfanumérico, o uno de los _-. chars, y si no lo es, hacemos casi la misma asignación que con URLENCODE donde realiza búsquedas, sin embargo, incrementamos de manera diferente, usando y++ lugar de to[1] , esto se debe a que las cadenas se están construyendo de diferentes maneras, Pero de todos modos alcanzaré el mismo objetivo al final.
  • Cuando se completa el bucle y desaparece la longitud, en realidad termina la cadena, asignando el byte /0 .
  • Devuelve la cadena codificada.

Diferencias:

  • UrlEncode comprueba si hay espacio, asigna un signo +, RawURLEncode no.
  • UrlEncode no asigna un /0 byte a la cadena, RawUrlEncode lo hace (esto puede ser un punto discutible)
  • Ellos iteran de manera diferente, uno puede ser propenso a desbordarse con cadenas mal formadas, simplemente estoy sugiriendo esto y no he investigado realmente.

Básicamente, se iteran de forma diferente, se asigna un signo + en el caso de ASCII 20.

Diferencias en EBCDIC:

URLENCODE:

  • La misma configuración de iteración que con ASCII
  • Todavía traduciendo el carácter "espacio" a un signo + . Nota: creo que esto debe compilarse en EBCDIC o terminará con un error. ¿Puede alguien editar y confirmar esto?
  • Comprueba si el char actual es un char antes de 0 , con la excepción de ser un . o - , O menos que A pero mayor que char 9 , O mayor que Z y menor que a pero no a _ . O mayor que z (sí, EBCDIC está un poco desordenado para trabajar). Si coincide con alguno de ellos, realice una búsqueda similar a la que se encuentra en la versión ASCII (simplemente no requiere una búsqueda en os_toascii).

RAWURLENCODE:

  • La misma configuración de iteración que con ASCII
  • La misma verificación que se describe en la versión EBCDIC de URL Encode, con la excepción de que si es mayor que z , excluye ~ de la codificación URL.
  • Misma asignación que el ASCII RawUrlEncode
  • Aún agregando el byte /0 a la cadena antes de regresar.

Gran resumen

  • Ambos usan la misma tabla de búsqueda de hexchars
  • URIEncode no termina una cadena con / 0, raw lo hace.
  • Si está trabajando en EBCDIC, sugeriría usar RawUrlEncode, ya que administra el ~ que UrlEncode no ( este es un problema reportado ). Vale la pena señalar que ASCII y EBCDIC 0x20 son espacios.
  • Se repiten de manera diferente, uno puede ser más rápido, uno puede ser propenso a ataques de memoria o basados ​​en cadenas.
  • URIEncode hace un espacio en + , RawUrlEncode hace un espacio en %20 través de búsquedas de matriz.

Descargo de responsabilidad: no he tocado C en años y no he visto EBCDIC en mucho tiempo. Si me equivoco en alguna parte, hágamelo saber.

Implementaciones sugeridas

Basado en todo esto, rawurlencode es el camino a seguir la mayor parte del tiempo. Como ves en la respuesta de Jonathan Fingland, apégate a ella en la mayoría de los casos. Se trata del esquema moderno para los componentes URI, donde a medida que urlencode hace las cosas a la antigua usanza, + significa "espacio".

Si estás intentando convertir entre el formato antiguo y el nuevo, asegúrate de que tu código no funcione correctamente y convierte algo que es un inicio de sesión descodificado en un espacio por codificación doble accidental, o escenarios similares de "oops" al respecto Espacio / 20% / + problema.

Sin embargo, si está trabajando en un sistema más antiguo con un software antiguo que no prefiere el formato nuevo, siga con urlencode, creo que% 20 será compatible con versiones anteriores, ya que, según el antiguo estándar% 20, no funcionó. privilegiado. Dale una oportunidad si estás listo para jugar, déjanos saber cómo te fue.

Básicamente, debes seguir con Raw, a menos que tu sistema EBCDIC realmente te odie. La mayoría de los programadores nunca se encontrarán con EBCDIC en ningún sistema creado después del año 2000, tal vez incluso en 1990 (eso es un empujón, pero en mi opinión es probable).


Una razón práctica para elegir uno sobre el otro es si va a utilizar el resultado en otro entorno, por ejemplo, JavaScript.

En PHP urlencode(''test 1'') devuelve ''test+1'' mientras que rawurlencode(''test 1'') devuelve ''test%201'' como resultado.

Pero si necesita "decodificar" esto en JavaScript usando la función decodeURI () , entonces decodeURI("test+1") le dará "test+1" mientras que decodeURI("test%201") le dará "test 1" como resultado.

En otras palabras, el espacio ("") codificado por urlencode a más ("+") en PHP no será decodificado correctamente por decodeURI en JavaScript.

En tales casos, debe utilizarse la función de PHP rawurlencode .


simple * rawurlencode la ruta - la ruta es la parte antes de "?" - los espacios deben estar codificados como% 20 * urlencode la cadena de consulta - La cadena de consulta es la parte después de "?" -los espacios se codifican mejor como "+" = rawurlencode generalmente es más compatible


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

rendimientos

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

mientras

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

rendimientos

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

La diferencia es que asd%20asd vs asd+asd

urlencode difiere de RFC 1738 al codificar espacios como + lugar de %20