有没有办法确定字符串是否经过两次base64编码?
例如,我能否使用带有preg_match
函数的正则表达式模式来判断这一点?
(实用回答。)不要使用正则表达式。使用 base64_decode()
函数并将其可选的$strict
参数设置为true
,以查看它是否符合您期望的格式。或者尝试多次解码它,直到它无法再解码为止。例如:
function base64_decode_multiple(string $data, int $count = 2) {
while ($count-- > 0 && ($decoded = base64_decode($data, true)) !== false) {
$data = $decoded;
}
return $data;
}
(理论答案。) 双64进制编码字符串是规则的,因为有限数量的字节序列可以正确地将一个64进制编码的消息进行编码。
你只需要验证每组四个字符,就可以一次性检查是否有东西被编码成了64进制。由于使用=
作为填充符号,因此在64进制编码的消息中,最后四个字节可能是特殊情况。使用正则表达式:
<char> := [A-Za-z0-9+/]
<end-char> := [A-Za-z0-9+/=]
<chunk> := <char>{4}
<end-chunk> := <char>{2} <end-char>{2} | <char>{3} <end-char>
<base64-encoded> := <chunk>* <end-chunk>?
使用正则表达式也可以判断某个内容是否已经进行了两次base64编码,但这并不是一个简单或优美的解决方案,因为一次仅仅检查4个字节是不够的。
例如:"QUFBQQ==" 经过base64解码后得到 "AAAA" ,再次base64解码后得到3个NUL字节。
$ echo -n "QUFBQQ==" | base64 -d | xxd
00000000: 4141 4141 AAAA
$ echo -n "AAAA" | base64 -d | xxd
00000000: 0000 00 ...
此时,我们可以列举出所有双重Base64编码,其中Base64编码是在Base64字母表中4个字节(“AAAA”,“AAAB”,“AAAC”,“AAAD”等),并将其最小化:
<ugly 4> := QUFBQQ== | QUFBQg== | QUFBQw== | QUFBRA== | ...
我们可以列举所有双重Base64编码的前4个字节,其中Base64编码为8个或更长的字节(不涉及使用=
填充的情况),并将其最小化:
<chunk 4> := QUFB | QkFB | Q0FB | REFB | ...
双重base64编码字符串的一个分区(漂亮的那个)不会在末尾包含=
符号;它们的长度是8的倍数:
<pretty double-base64-encoded> := <chunk 4>{2}*
另一种双重base64编码字符串的分割方式将具有长度为4的倍数但不是8(4、12、20等)的长度;它们可以被视为在末尾有一个丑陋比特的漂亮字符串:
<ugly double-base64-encoded> := <chunk 4>{2}* <ugly 4>
我们可以构建一个组合的正则表达式:
<double-base64-encoded> := <pretty double-base64-encoded>
| <ugly double-base64-encoded>
就像你不想检查一个整数是否在某个有限区间内一样,我说过,你可能不想因为双重Base64编码的消息是正常的而经历所有这些麻烦。此外,这是一个得到错误答案时应该问另一个问题的好例子。:-)