2010-06-08 30 views
25

Dudo si esto es cifrado pero no puedo encontrar una frase mejor. Necesito pasar una cadena de consulta larga como esta:¿Cómo comprimir/descomprimir una cadena de consulta larga en PHP?

http://test.com/test.php?key=[some_very_loooooooooooooooooooooooong_query_string] 

La cadena de consulta no contiene información sensible así que no estoy realmente preocupado por la seguridad en este caso. Es solo ... bueno, demasiado largo y feo. ¿Existe una función de biblioteca que me permita codificar/encriptar/comprimir la cadena de consulta en algo similar al resultado de un md5() (similar a, siempre una cadena de 32 caracteres), pero decodificar/descifrar/descomprimir-capaz?

+0

Usted ya lo nombró: "compresión" sería un título más apropiado tal vez;) O ¿por qué no enviar los datos a través de POST? –

+0

O guárdalo en la SESIÓN ... hay muchas maneras, pero él quiere almacenarlo en la uri. No es una mala idea: P –

+1

Tenga en cuenta que una cadena GET nunca debe exceder de 1 a 2 kilobytes de tamaño debido a las limitaciones del servidor y del navegador. –

Respuesta

31

La premisa básica es muy difícil. El transporte de cualquier valor en la URL significa que está restringido a un subconjunto de caracteres ASCII. Usar cualquier tipo de compresión como gzcompress reduciría el tamaño de la cadena, pero daría como resultado una burbuja binaria. Sin embargo, ese blob binario no se puede transportar en la URL, ya que produciría caracteres no válidos. Para transportar ese blob binario utilizando un subconjunto de ASCII, debe codificarlo de alguna manera y convertirlo en caracteres ASCII.

lo tanto, que desactive los caracteres ASCII en otra cosa que tendría luego se convierten en caracteres ASCII.

Pero, en realidad, la mayoría de las veces los caracteres ASCII se empieza con que ya son la longitud óptima. Aquí una prueba rápida:

$str = 'Hello I am a very very very very long search string'; 
echo $str . "\n"; 
echo base64_encode(gzcompress($str, 9)) . "\n"; 
echo bin2hex(gzcompress($str, 9)) . "\n"; 
echo urlencode(gzcompress($str, 9)) . "\n"; 

Hello I am a very very very very long search string 
eNrzSM3JyVfwVEjMVUhUKEstqkQncvLz0hWKUxOLkjMUikuKMvPSAc+AEoI= 
78daf348cdc9c957f05448cc554854284b2daa442772f2f3d2158a53138b9233148a4b8a32f3d201cf801282 
x%DA%F3H%CD%C9%C9W%F0TH%CCUHT%28K-%AAD%27r%F2%F3%D2%15%8AS%13%8B%923%14%8AK%8A2%F3%D2%01%CF%80%12%82 

Como puede ver, la secuencia original es la más corta. Entre las compresiones codificadas, base64 es la más corta, ya que utiliza el alfabeto más grande para representar los datos binarios. Sin embargo, es más largo que el original.

Para una combinación muy específica de caracteres con un algoritmo de compresión muy específico que se comprime en datos ASCII representables, es posible lograr algo de compresión, pero eso es más bien teórico. Actualización: En realidad, eso suena demasiado negativo. Lo que necesita es averiguar si la compresión tiene sentido para su caso de uso. Diferentes datos se comprimen de manera diferente y diferentes algoritmos de codificación funcionan de manera diferente. Además, las cadenas más largas pueden lograr una mejor relación de compresión. Probablemente haya un punto ideal en algún lugar donde se pueda lograr cierta compresión. Necesitas averiguar si estás en ese punto dulce la mayor parte del tiempo o no.

Algo como md5 no es adecuado ya que md5 es hash, lo que significa que no es reversible. No puede recuperar el valor original.

me temo que sólo puede enviar el parámetro a través de POST, si no funciona en la URL.

+3

En realidad no se puede decir con certeza si la codificación dará como resultado una cadena más larga que la original. Realmente depende de la cadena original. Si la compresión es lo suficientemente buena, incluso las versiones codificadas pueden ser más cortas. Probé mi ejemplo con base64 y es más corto que la cadena original. Pero de alguna manera estás en lo cierto, porque probablemente la mayoría del tiempo, las versiones codificadas serán más largas. –

+0

@Felix Sí, acabo de agregar ese mismo pensamiento a mi respuesta. No es imposible, pero muy poco práctico. – deceze

+0

@deceze: Sí. Impractical es una palabra muy buena para eso :) –

-1

base64_encode hace que la secuencia sea ilegible (aunque, por supuesto, se puede decodificar fácilmente) pero aumenta el volumen un 33%.

urlencode() convierte los caracteres no aptos para las URL en sus homólogos codificados en URL. Si su objetivo es hacer que la cadena funcione en la URL, esta puede ser la forma correcta para usted.

Si tiene una sesión ejecutándose, también podría considerar colocar la cadena de consulta en una variable de sesión con un número aleatorio (pequeño) y poner ese número aleatorio en la cadena GET. Este método no sobrevivirá más tiempo que la sesión actual, por supuesto.

Tenga en cuenta que una cadena GET nunca debe exceder de 1 a 2 kilobytes de tamaño debido a las limitaciones del servidor y del navegador.

5

Actualización:
gzcompress() no le ayudará. Por ejemplo, si se toma la respuesta de Pekka:

longitud de la cadena: 640
comprimido longitud de la cadena: 375
URL codificada longitud de la cadena: 925
(con base64_encode, que está a sólo 500 caracteres;))

Así de esta manera (que pasa los datos a través de la URL) no es probablemente la mejor manera ...

Si no exceder los límites de URLs con la cadena, ¿por qué te preocupas por ¿cómo se ve la cadena? Supongo que se crea, envía y procesa automáticamente de todos modos, ¿no?

Pero si quiere usarlo como p. Ej. algún tipo de enlace de confirmación en un correo electrónico, debe pensar en algo corto y fácil de escribir para el usuario de todos modos. Podría, por ej. almacene todos los datos necesarios en una base de datos y cree algún tipo de token.


Tal vez gzcompress() puede ayudarle. Pero esto dará como resultado caracteres no permitidos, por lo que tendrá que usar urlencode() también (lo que hace que la cadena sea más larga y fea de nuevo;)).

+0

Sí. El resultado tendrá que ser 'urlencode()' d, lo que lo hace probablemente poco práctico para cadenas muy pequeñas, pero puede funcionar para cadenas más grandes. –

+0

@Pekka: Sí, lo he notado. Realmente no parece tener un efecto en cadenas cortas. –

+0

Félix Sé que estás en Facebook, sobre la compresión de cadenas en Facebook. ¡Ya sabes que hay un UUID en Cassandra (db) y es un texto largo! Twitter e Instagram también usan Cassandra (y Cassandra se desarrolló inicialmente en Facebook) y cuando busqué las publicaciones de Facebook, Twitter e Instagram o la identificación de los usuarios, eso no era UUID y no estoy seguro de si están usando UUID (o timeuuid) en sus URL también o tienen un tipo de función y algoritmo para reducir y la duración del UUID. ** ¿Sabe y puede decir lo que Facebook está haciendo que tiene URL cortas si usa UUID? ** – M98

1

Para valores de cadena larga/muy larga, ¡le gustaría utilizar el método POST en lugar de GET!

para una buena codificación es posible que quieras probar urlencode()/urldecode()

o htmlentities()/html_entity_decode()

También tenga cuidado de que '% 2F' se traduce en el navegador como el '/' char (separador de directorio). Si usa solo urlencode, quizás quiera reemplazarlo.

os lo recomiendo gzcompress en parámetros GET.

38

Usted podría tratar de una combinación de gzdeflate (prima desinflado formato) para comprimir sus datos y base64_encode utilizar sólo los caracteres que se permiten sin código porciento (además, intercambiar los personajes + y / por - y _):

$output = rtrim(strtr(base64_encode(gzdeflate($input, 9)), '+/', '-_'), '='); 

Y a la inversa:

$output = gzinflate(base64_decode(strtr($input, '-_', '+/'))); 

Aquí se muestra un ejemplo:

$input = 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.'; 

// percent-encoding on plain text 
var_dump(urlencode($input)); 

// deflated input 
$output = rtrim(strtr(base64_encode(gzdeflate($input, 9)), '+/', '-_'), '='); 
var_dump($output); 

Los ahorros en este caso es aproximadamente el 23%.Pero la eficacia real de este procedimiento de compresión depende de los datos que está utilizando.

+0

100% exactamente al pie de la letra cortar y pastar exactamente lo que era buscando :) –

+0

Esto es brillante, como antes pude copiar y pegar esto en mi aplicación. Sin embargo, los apóstrofos se devuelven como \ ' – anastymous

10

Esto funciona muy bien para mí:

$out = urlencode(base64_encode(gzcompress($in))); 

ahorra mucho.

$in = 'Hello I am a very very very very long search string' // (51) 
$out = 64 

$in = 500 
$out = 328 

$in = 1000 
$out = 342 

$in = 1500 
$out = 352 

Cuanto más larga sea la cadena, mejor será la compresión. El parámetro de compresión no parece tener ningún efecto.

+0

He probado 'urlencode (base64_encode (gzcompress ($ in)));' con una matriz 'implode'd a una cadena. Empecé a ver compresión en cadenas de más de 80 caracteres. p.ej. de 110 a 94. Tus variables $ in/$ out no están muy bien explicadas en tu respuesta. Creo que estás diciendo que esos son los tamaños de entrada/salida de tus cadenas (antes/después de la compresión). Aquí está mi respuesta que usa la suya como punto de partida: http://stackoverflow.com/a/20915918/631764 –

+0

Si está creando las cadenas de entrada más largas repitiendo el mismo fragmento de texto obtendrá una muy buena compresión, ya que hay repetición patrones (baja entropía) en la entrada. Si comprimes una cadena con menos repetición (entropía más alta) obtendrás menos compresión. Para resumir, necesitas asegurarte el punto de referencia con datos reales (estáticos). – Henry

1

Estas funciones comprimirán y descomprimirán una cadena o una matriz.

A veces es posible que desee OBTENER una matriz.

function _encode_string_array ($stringArray) { 
    $s = strtr(base64_encode(addslashes(gzcompress(serialize($stringArray),9))), '+/=', '-_,'); 
    return $s; 
} 

function _decode_string_array ($stringArray) { 
    $s = unserialize(gzuncompress(stripslashes(base64_decode(strtr($stringArray, '-_,', '+/='))))); 
    return $s; 
} 
+0

Recuerde * NUNCA * deserializar datos a ciegas. Es un agujero de seguridad muy común. –

3

Básicamente, es como dicen: Comprimir texto, y enviarlo codificado de una manera útil. Pero :

1) métodos de compresión común son más pesados ​​que el texto debido diccionarios. Si los datos son siempre un orden indeterminado de trozos de datos determinados (como en un texto son palabras o sílabas [3], y números y algunos símbolos), podría usar siempre el mismo diccionario estático y no enviarlo (no lo haga). t pegarlo en la URL). Luego, , puede guardar el espacio del diccionario.

1.a) Si ya está enviando el idioma (o si es siempre el mismo), puede generar un diccionario por idioma.

1.b) Aproveche las limitaciones de formato. Si sabías que es un número, puedes codificarlo directamente (ver 3). Si sabía que era una fecha, podría codificarse como tiempo Unix [1] (segundos desde 01/01/1970), por lo que "21/05/2013 23:45:18" da vuelta "519C070E" (hexadecimal); si es una fecha del año, puede codificar como días desde el año nuevo, incluido el 29/02 (25/08 sería 237).

1,3) que conoce a mensajes de correo electrónico tiene que seguir ciertas reglas, y por lo general son de los mismos pocos servidores (Gmail, Yahoo, etc.) Usted podría tomar ventajas de que comprimirlo con su propio método simple:

[email protected],[email protected],[email protected] => samplemail1:1,samplemail2:5,[email protected]:1 

2) Si los datos sigue patrones, puede usarlo para ayudar a la compresión. Por ejemplo, si siempre sigue este golpeteo:

name=[TEXT 1]&phone=[PHONE]&mail=[MAIL]&desc=[TEXT 2]&create=[DATE 1]&modified=[DATE 2]&first=[NUMBER 1]&last=[NUMBER 2] 

Usted podría: 2.a) Ignorar el texto similar, y comprimir sólo el texto variable. Como:

[TEXT1]|[PHONE]|[MAIL]|[TEXT 2]|[DATE 1]|[DATE 2]|[NUMBER 1][NUMBER 2] 

2.b) Encode o comprimir datos por tipo (números codifican utilizando base64 [2] o similar). Como en 1). Esto le permite incluso suprimir separadores.Al igual que:

[DATE 1][DATE 2][NUMBER 1][NUMBER 2][PHONE][MAIL]|[TEXT 1]|[TEXT 2] 

3) Codificación:

3.a) Si bien es cierto que si comprimimos con codificación de caracteres no compatibles con HTTP, que se transformarán en un los más pesados (como 'año' => 'a% C3% B1o'), que aún puede ser útil. Tal vez quieras comprimirlo para almacenarlo en una base de datos Unicode o binaria, o pegarlo en sitios web (Facebook, Twitter, etc.).

3.b) Aunque Base64 [2] es un buen método, puede exprimir más a expensas de la velocidad (ya que utiliza funciones de usuario en lugar de compiladas).

Al menos con la función de Javascript encodeURI(), puede utilizar cualquiera de estos 80 caracteres a un valor de parámetro sin modificaciones que sufren:

ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.:,;+*-_/()[email protected]?~' 

Por lo tanto, podemos Buil nuestra una "base 80" (d) codificar funciones.

2
No

realmente una respuesta , pero una comparación de varios métodos sugeridos aquí.

Utiliza respuestas de @Gumbo y @deceze para obtener una comparación de longitud para una cadena bastante larga que estoy usando en un GET.

<?php 
    $test_str="33036,33037,33038,38780,38772,37671,36531,38360,39173,38676,37888,36828,39176,39196,37321,36840,38519,37946,36543,39287,38989,38976,36804,38880,38922,38292,38507,38893,38993,39035,37880,38897,38378,36880,38492,38910,36868,38196,38750,37938,39268,38209,36856,36767,37936,36805,39248,36777,39027,39056,38987,38779,38919,38771,36851,38675,37887,38246,38791,38783,38661,37899,36846,36834,39263,37928,36822,37947,38992,38516,39177,38904,38896,37320,39217,37879,38293,38511,38774,37670,38185,37927,37939,38286,38298,38977,37891,38881,38197,38457,36962,39171,36760,36748,39249,39231,39191,36951,36963,36755,38769,38891,38654,38792,36863,36875,36956,36968,38978,38299,36743,36753,37896,38926,39270,38372,37948,39250,38763,38190,38678,36761,37925,36776,36844,37323,38781,38744,38321,38202,38793,38510,38288,36816,38384,37906,38184,38192,38745,39218,38673,39178,39198,39036,38504,36754,39180,37919,38768,38195,36850,38203,38672,38882,38071,39189,36795,36783,38870,38764,39028,36762,36750,38980,36958,37924,38884,37920,38877,36858,38493,36742,37895,36835,37907,36823,38762,38361,37937,38373,37949,36950,39202,38495,38291,36533,39037,36716,38925,37620,38906,37878,37322,38754,36818,39029,39264,38297,38517,36969,38905,36957,36789,36741,37908,38302,38775,39216,36812,38767,36845,36849,39181,39168,38671,39188,38490,36961,39201,36717,38382,38070,37868,38984,36770,38981,38494,36807,38885,36759,36857,38924,39038,38888,38876,36879,37897,36534,36764,37931,38254,39030,38990,37909,38982,38290,36848,37857,37923,38249,38658,38383,36813,36765,36817,37263,36769,37869,38183,36861,38206,39031,36800,36788,36972,38508,38303,39051,38491,38983,38759,36740,37958,36967,37930,39174,39182,36806,36867,36855,39222,37862,36752,38242,37965,38894,38182,37922,37918,36814,36872,38886,36860,36527,38194,38975,36718,39224,37436,39032"; 

    echo(strlen($test_str)); echo("<br>"); 

    echo(strlen(base64_encode(gzcompress($test_str,9)))); echo("<br>"); 

    echo(strlen(bin2hex(gzcompress($test_str, 9)))); echo("<br>"); 

    echo(strlen(urlencode(gzcompress($test_str, 9)))); echo("<br>"); 

    echo(strlen(rtrim(strtr(base64_encode(gzdeflate($test_str, 9)), '+/', '-_'), '='))); 
?> 

Éstos son los resultados:

1799 (original length string) 
928 (51.58% compression) 
1388 
1712 
918 (51.028% compression) 

Los resultados son comparables a base64_encode con gzcompress Y base64_encode con gzdeflate (y algunos transalations de cuerda). gzdeflate parece dar una eficiencia ligeramente mejor

Cuestiones relacionadas