我怀疑这是否是加密但我找不到更好的短语。我需要传递一个这样的长查询字符串:
http://test.com/test.php?key=[some_very_loooooooooooooooooooooooong_query_string]
查询字符串中不包含任何敏感信息,因此在这种情况下我并不真正关心安全性。它只是......好吧,太长又丑。是否有一个库函数可以让我将查询字符串编码/加密/压缩成类似于md5()的结果(类似于,总是一个32个字符的字符串),但解码/解密/解压缩?
答案 0 :(得分:42)
您可以尝试组合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%。但是这种压缩程序的实际效率取决于您使用的数据。
答案 1 :(得分:33)
基本前提非常困难。传输URL中的任何值意味着您被限制为ASCII字符的子集。使用gzcompress
之类的任何类型的压缩都会减小字符串的大小,但会产生二进制blob。但是,二进制blob无法在URL中传输,因为它会产生无效字符。要使用ASCII子集传输该二进制blob,您需要以某种方式对其进行编码并将其转换为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 :(得分:11)
这对我很有用:
$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
所以字符串越长,压缩越好。压缩参数似乎没有任何影响。
答案 3 :(得分:5)
<强>更新强>
gzcompress()
对您无济于事。例如,如果你采取Pekka的答案:
字符串长度:640
压缩弦长:375
URL编码的字符串长度:925
(使用base64_encode,它只有500个字符;))
所以这种方式(通过URL传递数据)可能不是最好的方法......
如果你没有超过字符串的URL限制,你为什么要关心 字符串是什么样的?我认为无论如何都会自动创建,发送和处理,不是吗?
但是如果你想用它作为例如在电子邮件中有某种确认链接,你必须考虑一些简短的东西,并且无论如何都很容易为用户打字。你可以,例如将所有需要的数据存储在数据库中并创建某种令牌。
也许gzcompress()
可以帮到你。但是这会导致不允许的字符,所以你也必须使用urlencode()
(这会使字符串变长和丑陋;)。)
答案 4 :(得分:2)
基本上,就像他们说的那样:压缩文本,并以有用的方式发送它。的但强>:
1)由于词典,常见的压缩方法比文本重。如果数据始终是确定的数据块的未确定顺序(例如在文本中是单词或音节[3],以及数字和某些符号),您可以始终使用相同的静态字典,并且不要发送它(不要将其粘贴到URL上)。然后可以保存字典的空间。
1.a)如果您已经发送了该语言(或者它总是相同的话),您可以按照lang生成一个字典。
1.b)利用格式限制。如果你知道它是一个数字,你可以直接编码(见3)。如果您知道它是一个日期,您可以编码为Unix时间[1](自1970年1月1日起的秒数),因此“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'=&gt;'a% C3%B1o'),仍然有用。也许你想压缩它以存储在Unicode或二进制数据库中,或者粘贴到网站(Facebook,Twitter等)。
3.b)虽然Base64 [2]这是一个很好的方法,但你可以以牺牲速度为代价来挤压更多(因为你使用的是用户函数而不是编译的函数)。
至少使用Javascript的函数encodeURI(),你可以在参数值中使用这80个字符中的任何一个而不需要修改:
0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.:,;+*-_/()$=!@?~'
因此,我们可以构建一个“Base 80”(d)编码函数。
答案 5 :(得分:1)
对于长/非常长的字符串值,您希望使用POST方法而不是GET!
对于良好的编码,您可能想尝试urlencode()/ urldecode()
或htmlentities()/ html_entity_decode()
另外要小心'%2F'被翻译为浏览器'/'char(目录分隔符)。如果你只使用urlencode,你可能想要替换它。
我不建议在GET参数上使用gzcompress。
答案 6 :(得分:1)
这些函数将压缩和解压缩字符串或数组。
有时您可能想要获取数组。
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;
}
答案 7 :(得分:1)
不是一个真正的答案,而是对这里提出的各种方法的比较。
@Gumbo和@dezeze使用的答案来获取我在GET中使用的相当长的字符串的长度比较。
class org.springframework.context.support.ReloadableResourceBundleMessageSource
以下是结果:
<?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)), '+/', '-_'), '=')));
?>
base64_encode与gzcompress和base64_encode与gzdeflate(以及一些字符串转换)的结果相当。 gzdeflate似乎效率稍高
答案 8 :(得分:-1)
base64_encode
使字符串不可读(当然可以轻松解码)但是将音量提高了33%。
urlencode()
将任何不适合网址的字符转换为其网址编码的对应字符。如果您的目标是使字符串在URL中起作用,这可能是您正确的方法。
如果您正在运行会话,您还可以考虑将查询字符串放入具有随机(小)数字的会话变量中,并将该随机数放入GET字符串中。当然,这种方法的存活时间不会超过当前会话。
请注意,由于服务器和浏览器的限制,GET字符串的大小不应超过1-2 KB。