Подтвердить что ты не робот

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

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

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

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

4b9b3361

Ответ 1

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

Ответ 2

Вы можете попробовать комбинацию gzdeflate (необработанный формат дефляции) для сжатия ваших данных и 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%. Но фактическая эффективность этого прецедента сжатия зависит от данных, которые вы используете.

Ответ 3

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

$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

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

Ответ 4

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

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

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

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

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


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

Ответ 5

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

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

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

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 и т.д.). Вы могли бы воспользоваться преимуществами этого, чтобы сжать его с помощью собственного простого метод:

[email protected],[email protected],[email protected] => samplemail1:1,samplemail2:5,[email protected]: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 '), , которые могут быть полезны. Возможно, вы захотите сжать его для хранения в юникодной или двоичной базе данных или вставить на веб-сайты (Facebook, Twitter и т.д.).

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

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

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

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

Ответ 6

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

Используемые ответы @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, кажется, дает немного лучшую эффективность

Ответ 7

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

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

или htmlentities()/html_entity_decode()

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

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

Ответ 8

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

Иногда вам может понадобиться 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;
}

Ответ 9

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

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

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

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