Как сжать / распаковать длинную строку запроса в PHP? - PullRequest
29 голосов
/ 08 июня 2010

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

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

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

Ответы [ 9 ]

42 голосов
/ 08 июня 2010

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

$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%. Но фактическая эффективность этой процедуры сжатия зависит от данных, которые вы используете.

33 голосов
/ 08 июня 2010

Основная предпосылка очень сложная. Перенос любого значения в 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.

11 голосов
/ 02 ноября 2012

Это прекрасно работает для меня:

$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

Чем длиннее строка, тем лучше сжатие.Параметр сжатия, похоже, не оказывает никакого влияния.

5 голосов
/ 08 июня 2010

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

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

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

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

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


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

2 голосов
/ 21 мая 2013

По сути, это как говорят: сожмите текст и с пользой отправьте его. Но :

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

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

1.b) Воспользуйтесь преимуществами ограничений формата.Если вы знаете, что это число, вы можете закодировать его напрямую (см. 3).Если вы знаете, что это дата, вы можете закодировать ее как Unix-time [1] (секунд с 01.01.1970), поэтому «21.05.2013 23:45:18» превращает «519C070E» (шестнадцатеричное);если это дата года, вы можете закодировать дни с нового года, включая 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.a) Игнорировать аналогичный текст и сжимать только переменный текст.Например:

[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'), , которые все еще могут быть полезны .Может быть, вы хотите сжать его для хранения в Unicode или двоичной базе данных или для вставки на веб-сайты (Facebook, Twitter и т. Д.).

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

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

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

Итак, мы можем построить наши функции кодирования "Base 80" (d).

1 голос
/ 07 октября 2016

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

Использовал ответы @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)), '+/', '-_'), '=')));
?>

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

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

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

1 голос
/ 18 мая 2013

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

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

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;
}
1 голос
/ 08 июня 2010

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

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

или htmlentities () / html_entity_decode ()

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

я не рекомендую gzcompress для параметров GET.

0 голосов
/ 08 июня 2010

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...