Как сжать / распаковать длинную строку запроса в PHP?

Я сомневаюсь, что это шифрование, но я не могу найти лучшую фразу. Мне нужно передать длинную строку запроса следующим образом:

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

Строка запроса содержит НЕТ чувствительную информацию, поэтому в этом случае я действительно не беспокоюсь о безопасности. Это просто … хорошо, слишком долго и уродливо. Есть ли библиотечная функция, которая может позволить мне кодировать / шифровать / сжимать строку запроса во что-то похожее на результат md5 () (аналогично строке, всегда 32 символьной строки), но декодировать / расшифровывать / декомпрессировать?

Основная посылка очень сложная. Транспортировка любого значения в URL означает, что вы ограничены подмножеством символов ASCII. Использование любого типа сжатия, такого как gzcompress , уменьшит размер строки, но приведет к бинарному блобу. Этот двоичный блок не может быть перенесен в URL-адрес, поскольку он приведет к созданию недопустимых символов. Чтобы передать этот двоичный код с помощью подмножества ASCII, вам необходимо каким-то образом закодировать его и превратить в ASCII-символы.

Таким образом, вы превратили бы символы ASCII во что-то другое, которое затем превратилось бы в символы ASCII.

Но на самом деле, в большинстве случаев символы ASCII, с которых вы начинаете, уже являются оптимальной длиной. Вот быстрый тест:

 $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 

Как вы можете видеть, исходная строка является самой короткой. Среди кодированных сжатий base64 является самым коротким, поскольку он использует самый большой алфавит для представления двоичных данных. Тем не менее, он еще длиннее оригинала.

Для некоторой очень конкретной комбинации символов с некоторым очень специфическим алгоритмом сжатия, который сжимается к ASCII-представимым данным, может быть возможно добиться некоторого сжатия, но это довольно теоретически. Обновление: На самом деле это звучит слишком негативно. Дело в том, что вам нужно выяснить, имеет ли смысл сжатие для вашего случая использования. Различные данные сжимаются по-разному, а разные алгоритмы кодирования работают по-разному. Кроме того, более длинные строки могут обеспечить лучшую степень сжатия. Там, вероятно, есть сладкое место где-то, где может быть достигнуто некоторое сжатие. Вам нужно выяснить, действительно ли вы находитесь в этом сладком месте большую часть времени или нет.

Что-то вроде md5 не подходит, поскольку md5 является хешем , что означает, что он не обратим. Вы не можете вернуть исходное значение.

Боюсь, вы можете отправлять этот параметр только через POST, если он не работает в URL-адресе.

Вы можете попробовать комбинацию gzdeflate (raw deflate format) для сжатия ваших данных и base64_encode для использования только тех символов, которые разрешены без кодирования Percent (дополнительно обмениваются символами + и / и - и _ ):

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

И наоборот:

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

Вот пример:

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

Экономия в этом случае составляет около 23%. Но фактическая эффективность этого прецедента сжатия зависит от данных, которые вы используете.

Это отлично работает для меня:

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

Экономит много.

 $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 

Поэтому чем длиннее строка, тем лучше сжатие. Параметр сжатия, похоже, не имеет никакого эффекта.

Обновить:
gzcompress() вам не поможет. Например, если вы ответите Пекке:

Длина строки: 640
Длина сжатой строки: 375
Длина строки в кодировке URL: 925
(с base64_encode, это всего 500 символов;))

Таким образом, этот способ (передача данных по URL-адресу), вероятно, не самый лучший способ …

Если вы не превысите лимиты URL-адресов с помощью строки, почему вас беспокоит, как выглядит строка? Я предполагаю, что он будет создан, отправлен и обработан автоматически в любом случае, не так ли?

Но если вы хотите использовать его, например, какую-то ссылку на подтверждение в электронном письме, вам нужно подумать о чем-то кратком и легком для пользователя. Вы могли бы, например, хранить все необходимые данные в базе данных и создавать своего рода токен.


Возможно, gzcompress() может вам помочь. Но это приведет к недопустимым символам, поэтому вам также придется использовать urlencode() (что делает строку длиннее и уродливой снова;)).

В принципе, это похоже на то, что они говорят: сжимайте текст и отправляйте его в удобной форме. Но :

1) Общие методы сжатия тяжелее текста из-за словарей . Если данные всегда являются неопределенным порядком определенных фрагментов данных (например, в тексте есть слова или слоги [3], а также номера и некоторые символы), вы можете использовать всегда один и тот же статический словарь и не отправлять его (дон ' t вставьте его в URL-адрес). Затем вы можете сохранить пространство словаря.

1.a) Если вы уже отправляете язык (или если он всегда один и тот же), вы можете создать словарь для каждого языка.

1.b) Используйте ограничения формата. Если вы знаете, что это номер, вы можете его напрямую закодировать (см. 3). Если вы знаете, что это дата, вы можете закодировать как Unix-time [1] (секунды с 01.01.1970), поэтому «21/05/2013 23:45:18» превращается в «519C070E» (hex); если это дата года, вы можете закодировать как дни с нового года, включая 29/02 (25/08 будет 237).

1.3). Вы знакомы с электронными письмами, которые должны следовать определенным правилам и обычно находятся на одних и тех же серверах (gmail, yahoo и т. Д.). Вы можете воспользоваться преимуществами этого, чтобы сжать его с помощью вашего собственного простого метода:

 samplemail1@gmail.com,samplemail2@yahoo.com.ar,samplemail3@idontknowyou.com => samplemail1:1,samplemail2:5,samplemail3@idontknowyou:1 

2) Если данные следуют шаблонам , вы можете использовать их для сжатия. Например, если всегда следует этот шаг:

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

Вы могли: 2.а) игнорировать аналогичный текст и сжимать только переменный текст. Подобно:

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

2.b) Кодировать или сжимать данные по типу (кодировать номера, используя base64 [2] или аналогичные). Как в 1). Это позволяет даже отключать разделители. Подобно:

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

3) Кодирование:

3.a) Хотя верно, что если мы сжимаем кодирование с символами, не поддерживаемыми HTTP, они будут преобразованы в более тяжелые (например, 'año' => 'a% C3% B1o'), которые все еще могут быть полезны , Может быть, вы захотите сжать его для хранения в юникодной или двоичной базе данных или вставить на веб-сайтах (Facebook, Twitter и т. Д.).

3.b) Хотя Base64 [2] это хороший метод, вы можете сжать больше за счет скорости (поскольку вы используете пользовательские функции вместо скомпилированных).

По крайней мере, с функцией javascript encodeURI () вы можете использовать любой из этих 80 символов при значении параметра без изменений:

 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.:,;+*-_/()$=!@?~' 

Таким образом, мы можем построить нашу функцию «Base 80» (d) для кодирования.

На самом деле это не ответ, а сравнение различных методов, предложенных здесь.

Используемые ответы @Gumbo и @deceze для сравнения длин для довольно длинной строки, которую я использую в 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)), '+/', '-_'), '='))); ?> - <?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)), '+/', '-_'), '='))); ?> 

Вот результаты:

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

Результаты сопоставимы для base64_encode с gzcompress И base64_encode с gzdeflate (и некоторые строковые трансаляции). gzdeflate, похоже, дает немного лучшую эффективность

Для длинных / очень длинных строковых значений вы хотите использовать метод POST вместо GET!

для хорошей кодировки вы можете попробовать urlencode () / urldecode ()

или htmlentities () / html_entity_decode ()

Также будьте осторожны, чтобы «% 2F» был переведен в браузер как символ «/» (разделитель каталога). Если вы используете только urlencode, вы можете захотеть заменить на нем.

Я не рекомендую gzcompress по параметрам GET.

Эти функции будут сжимать и распаковывать строку или массив.

Иногда вам может понадобиться GET массив.

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

base64_encode делает строку нечитаемой (хотя, конечно, легко декодируемой), но увеличивает громкость на 33%.

urlencode() превращает любые символы, непригодные для URL, в их URL-кодированные копии. Если ваша цель – заставить строку работать в URL-адресе, это может быть правильным для вас.

Если у вас есть сеанс, вы можете также рассмотреть возможность ввода строки запроса в переменную сеанса со случайным (маленьким) номером и поместить это случайное число в строку GET. Конечно, этот метод не сохранится дольше, чем текущая сессия.

Обратите внимание, что строка GET никогда не должна превышать 1-2 килобайта в размере из-за ограничений сервера и браузера.