But*_*kus 1 php arrays query-string
我正在寻找最简洁的URL而不是最短的PHP代码.我不希望我的用户被编码数组时PHP创建的可怕URL吓到.
如果只填充一个数组($fn),PHP将在查询字符串中执行大量重复http_build_query:
$fs = array(5, 12, 99);
$url = "http://$_SERVER[HTTP_HOST]/?" .
http_build_query(array('c' => 'asdf', 'fs' => $fs));
Run Code Online (Sandbox Code Playgroud)
结果$url是
http://example.com/?c=asdf&fs[0]=5&fs[1]=12&fs[3]=99
Run Code Online (Sandbox Code Playgroud)
如何将其降至最低(使用PHP或在PHP中轻松实现的方法)?
http_build_query将数组序列化为URL的常用方法是什么?PHP会自动将其反序列化$_GET.
当想要仅序列化(非关联)整数数组时,您还有其他选项.
对于小型阵列,转换为下划线列表非常方便有效.它完成了$fs = implode('_', $fs).然后你的URL看起来像这样:
http://example.com/?c=asdf&fs=5_12_99
Run Code Online (Sandbox Code Playgroud)
缺点是您必须明确explode('_', $_GET['fs'])地将值作为数组返回.
也可以使用其他分隔符.下划线被认为是字母数字,因此很少有特殊含义.在URL中,它通常用作空间替换(例如,通过MediaWiki).在下划线文本中使用时很难区分.连字符是另一种常见的空间替代品.它也经常用作减号.逗号是一个典型的列表分隔符,但不像下划线和连字符是由百分比编码的http_build_query,几乎在任何地方都有特殊含义.类似的情况是垂直条("管").
当在URL中使用大型数组时,您应该首先停止编写开始思考.这几乎总是表明糟糕的设计.POST HTTP方法不会更合适吗?您是否有更多可读和空间有效的方法来识别所寻址的资源?
理想情况下,URL应该易于理解并且(至少部分地)记住.在里面放置一个大blob真是个坏主意.
现在我警告你了.如果您仍需要在URL中嵌入大型数组,请继续.尽可能地压缩数据,base64 -对它们进行编码以将二进制blob转换为text并对文本进行url-encode以对其进行清理以嵌入URL.
嗯.或者更好地使用base64的修改版本.我选择的一个是使用
-而不是+,_而不是/和=.define('URL_BASE64_FROM', '+/');
define('URL_BASE64_TO', '-_');
function url_base64_encode($data) {
$encoded = base64_encode($data);
if ($encoded === false) {
return false;
}
return str_replace('=', '', strtr($encoded, URL_BASE64_FROM, URL_BASE64_TO));
}
function url_base64_decode($data) {
$len = strlen($data);
if (is_null($len)) {
return false;
}
$padded = str_pad($data, 4 - $len % 4, '=', STR_PAD_RIGHT);
return base64_decode(strtr($padded, URL_BASE64_TO, URL_BASE64_FROM));
}
Run Code Online (Sandbox Code Playgroud)
这会在每个字符上保存两个字节,否则将进行百分比编码.也没有必要调用urlencode函数.
应该在gzip(gzcompress)和bzip2(bzcompress)之间做出选择.不想在比较中投入时间,对于任何块大小设置,gzip在几个相对较小的输入(大约100个字符)上看起来更好.
但是应该将哪些数据输入压缩算法?
在C中,可以将整数数组转换为字符数组(字节)并将其移交给压缩函数.这是最明显的做事方式.在PHP中,最明显的做法是将所有整数转换为十进制表示为字符串,然后使用分隔符进行连接,并且仅在压缩之后进行连接.多么浪费空间!
所以,让我们使用C方法!我们将摆脱分隔符和其他方式浪费空间并使用以下方法编码2个字节的每个整数pack:
define('PACK_NUMS_FORMAT', 'n*');
function pack_nums($num_arr) {
array_unshift($num_arr, PACK_NUMS_FORMAT);
return call_user_func_array('pack', $num_arr);
}
function unpack_nums($packed_arr) {
return unpack(PACK_NUMS_FORMAT, $packed_arr);
}
Run Code Online (Sandbox Code Playgroud)
警告:在这种情况下pack,unpack行为与机器有关.字节顺序可以在机器之间改变.但我认为这在实践中不会成为问题,因为应用程序不会同时在具有不同字节序的两个系统上运行.但是,在集成多个系统时,可能会出现问题.此外,如果您切换到具有不同字节顺序的系统,使用原始链接的链接将中断.
现在打包,压缩和修改base64,一体化:
function url_embed_array($arr) {
return url_base64_encode(gzcompress(pack_nums($arr)));
}
function url_parse_array($data) {
return unpack_nums(gzuncompress(url_base64_decode($data)));
}
Run Code Online (Sandbox Code Playgroud)
在IdeOne上查看结果.它优于OP的答案,在他的40元素数组中,我的解决方案产生91个字符,而他的98个字符.当使用range(1, 1000)(生成array(1, 2, 3, …, 1000))作为基准时,OP的解决方案产生2712个字符,而我的只有2032个字符.这大约好25%.
为了完整起见,OP的解决方案是
function url_embed_array($arr) {
return urlencode(base64_encode(gzcompress(implode(',', $arr))));
}
Run Code Online (Sandbox Code Playgroud)