在 PHP 中检测 base64 编码?

Posted

技术标签:

【中文标题】在 PHP 中检测 base64 编码?【英文标题】:Detect base64 encoding in PHP? 【发布时间】:2011-02-03 02:56:07 【问题描述】:

有什么方法可以检测一个字符串是否在 php 中经过 base64_encoded() 处理?

我们正在将一些存储从纯文本转换为 base64,其中一部分存储在需要更新的 cookie 中。如果文本尚未编码,我想重置他们的 cookie,否则不要理会它。

【问题讨论】:

【参考方案1】:

抱歉,对已回答的问题的回复较晚,但我认为 base64_decode($x,true) 不足以解决这个问题。事实上,可能没有针对任何给定输入的非常好的解决方案。例如,我可以在 $x 中放入很多错误的值,而不会得到错误的返回值。

var_dump(base64_decode('wtf mate',true));
string(5) "���j�"

var_dump(base64_decode('This is definitely not base64 encoded',true));
string(24) "N���^~)��r��[jǺ��ܡם"

我认为除了严格的返回值检查之外,您还需要进行解码后验证。最可靠的方法是您可以解码然后检查一组已知的可能值。

准确度低于 100% 的更通用的解决方案(较长字符串更接近,短字符串不准确)是,如果您检查输出以查看是否有许多超出 utf-8 的正常范围(或您使用的任何编码) ) 字符。

看这个例子:

<?php
$english = array();
foreach (str_split('az019AZ~~~!@#$%^*()_+|?><": Iñtërnâtiônàlizætiøn') as $char) 
  echo ord($char) . "\n";
  $english[] = ord($char);

  echo "Max value english = " . max($english) . "\n";

$nonsense = array();
echo "\n\nbase64:\n";
foreach (str_split(base64_decode('Not base64 encoded',true)) as $char) 
  echo ord($char) . "\n";
  $nonsense[] = ord($char);


  echo "Max nonsense = " . max($nonsense) . "\n";

?>

结果:

Max value english = 195
Max nonsense = 233

所以你可以这样做:

if ( $maxDecodedValue > 200 )  //decoded string is Garbage - original string not base64 encoded

else  //decoded string is useful - it was base64 encoded

您可能应该使用解码值的 mean() 而不是 max(),我在这个示例中只使用了 max(),因为遗憾的是 PHP 中没有内置的 mean()。您针对什么阈值(例如 200)使用什么度量(平均值、最大值等)取决于您估计的使用情况。

总之,唯一的制胜法宝就是不玩。我会尽量避免首先识别 base64。

【讨论】:

【参考方案2】:
function is_base64_encoded($data)

    if (preg_match('%^[a-zA-Z0-9/+]*=0,2$%', $data)) 
       return TRUE;
     else 
       return FALSE;
    
;

is_base64_encoded("iash21iawhdj98UH3"); // true
is_base64_encoded("#iu3498r"); // false
is_base64_encoded("asiudfh9w=8uihf"); // false
is_base64_encoded("a398UIhnj43f/1!+sadfh3w84hduihhjw=="); // false

http://php.net/manual/en/function.base64-decode.php#81425

【讨论】:

这非常有用,但您的第四个示例 is_base64_encoded("a398UIhnj43f/1!+sadfh3w84hduihhjw=="); // true 在我的测试中返回 FALSE。 @Dylan 那是因为那不是一个有效的base64。他只是评论错了。 这只是匹配一个任意长度的字符串,并以 = 结尾。它与普通字符串或 base64 编码的字符串没有区别。 base64_decode 如果无法解析 base64 编码的字符串,则返回 false,因此您只需要做:return base64_decode($str) !== false。【参考方案3】:

我遇到了同样的问题,我最终得到了这个解决方案:

if ( base64_encode(base64_decode($data)) === $data)
    echo '$data is valid';
 else 
    echo '$data is NOT valid';

【讨论】:

唯一不好的是我应该先想到它;-) 如果我做 $data='iujhklsc' 我得到有效,但它不是; 良好的测试@Mohit - 我可以重现这个问题。这是一个聪明的解决方案,但显然也不起作用。问题是 base64_decode() 将“解码”非 base64 数据,然后 base64_encode() 简单地反转函数。 这不起作用。我在另一个答案上也看到了..买家要小心。 不适用于“123412341234”。说真的,为什么我一直看到这个答案?【参考方案4】:

迟到总比没有好:您也许可以使用mb_detect_encoding() 来确定编码的字符串是否似乎是某种文本:

function is_base64_string($s) 
  // first check if we're dealing with an actual valid base64 encoded string
  if (($b = base64_decode($s, TRUE)) === FALSE) 
    return FALSE;
  

  // now check whether the decoded data could be actual text
  $e = mb_detect_encoding($b);
  if (in_array($e, array('UTF-8', 'ASCII')))  // YMMV
    return TRUE;
   else 
    return FALSE;
  

更新对于喜欢简短的人

function is_base64_string_s($str, $enc=array('UTF-8', 'ASCII')) 
  return !(($b = base64_decode($str, TRUE)) === FALSE) && in_array(mb_detect_encoding($b), $enc);

【讨论】:

简直太棒了!!这可能是最好的,因为它允许程序员选择有效的编码列表(当然可以作为第二个参数传递以增加灵活性) 确实是一个被低估的解决方案。我责怪答案的时差。 如果编码的字符串不是 UTF-8 或 ASCII 怎么办... @TiamiyuSaheedOluwatosin 然后返回“false”。 @Marki 你的意思是 base 64 编码只支持 UTF-8 或 ASCII 字符集【参考方案5】:

我们可以将三件事组合成一个函数来检查给定的字符串是否是有效的 base 64 编码。

function validBase64($string)

 $decoded = base64_decode($string, true);
 $result = false;
    
 // Check if there is no invalid character in string
 if (!preg_match('/^[a-zA-Z0-9\/\r\n+]*=0,2$/', $string)) $result = false;
        
 // Decode the string in strict mode and send the response
 if (!$decoded) $result = false;
        
 // Encode and compare it to original one
 if (base64_encode($decoded) != $string) $result = false;
        
 return $result;

【讨论】:

我认为“$str”实际上应该是第二行的“$string”。 你不应该同时检查输入 mod 4 == 0 的长度吗? @frumbert 并非所有实现都需要填充。但如果您要测试 mod 4,您首先需要去除所有空格【参考方案6】:

我正要在 php 中构建一个 base64 切换,这就是我所做的:

function base64Toggle($str) 
    if (!preg_match('~[^0-9a-zA-Z+/=]~', $str)) 
        $check = str_split(base64_decode($str));
        $x = 0;
        foreach ($check as $char) if (ord($char) > 126) $x++;
        if ($x/count($check)*100 < 30) return base64_decode($str);
    
    return base64_encode($str);

它非常适合我。 以下是我对此的完整想法:http://www.albertmartin.de/blog/code.php/19/base64-detection

你可以在这里试试:http://www.albertmartin.de/tools

【讨论】:

我个人喜欢这个解决方案,因为它最接近(return false 代替 return base64_encode($str)return true 代替 return base64_decode($str) 并且您获得了一个近乎完美的 OP 解决方案)。感谢您在博客上的解释。 我想你也应该看看(Marki 的解决方案)[***.com/a/51877882/1369473].它更灵活,更不容易出错【参考方案7】:

如果输入不是有效的 base64 编码数据,base64_decode() 将不会返回 FALSE。请改用imap_base64(),如果 $text 包含 Base64 字母表之外的字符,则返回 FALSE imap_base64() Reference

【讨论】:

base64_decode($string, true)相同,即严格形式【参考方案8】:

这是我的解决方案:

if(empty(htmlspecialchars(base64_decode($string, true)))) return false;

如果解码后的$string无效,则返回false,例如:“node”、“123”、“”等

【讨论】:

好一个。比其他大多数人都好【参考方案9】:
$is_base64 = function(string $string) : bool 
    $zero_one = ['MA==', 'MQ=='];
    if (in_array($string, $zero_one)) return TRUE;

    if (empty(htmlspecialchars(base64_decode($string, TRUE))))
        return FALSE;

    return TRUE;
;

var_dump('*** These yell false ***');
var_dump($is_base64(''));
var_dump($is_base64('This is definitely not base64 encoded'));
var_dump($is_base64('node'));
var_dump($is_base64('node '));
var_dump($is_base64('123'));
var_dump($is_base64(0));
var_dump($is_base64(1));
var_dump($is_base64(123));
var_dump($is_base64(1.23));

var_dump('*** These yell true ***');
var_dump($is_base64(base64_encode('This is definitely base64 encoded')));
var_dump($is_base64(base64_encode('node')));
var_dump($is_base64(base64_encode('123')));
var_dump($is_base64(base64_encode(0)));
var_dump($is_base64(base64_encode(1)));
var_dump($is_base64(base64_encode(123)));
var_dump($is_base64(base64_encode(1.23)));
var_dump($is_base64(base64_encode(TRUE)));

var_dump('*** Should these yell true? Might be edge cases ***');
var_dump($is_base64(base64_encode('')));
var_dump($is_base64(base64_encode(FALSE)));
var_dump($is_base64(base64_encode(NULL)));

【讨论】:

【参考方案10】:

可能不是您所要求的。但希望它对某人有用。

在我的情况下,解决方案是使用 json_encode 编码所有数据,然后使用 base64_encode。

$encoded=base64_encode(json_encode($data));

可以根据需要存储或使用此值。 然后检查这个值是否不仅仅是一个文本字符串,而是你的数据编码,你只需使用

function isData($test_string)
   if(base64_decode($test_string,true)&&json_decode(base64_decode($test_string)))
      return true;
   else
    return false;
   

或者

function isNotData($test_string)
   if(base64_decode($test_string,true)&&json_decode(base64_decode($test_string)))
      return false;
   else
    return true;
   

感谢此线程中所有以前的答案作者:)

【讨论】:

如果不是 json_encode() 首先...问题就在这里。 aGVsbG8=hello 的 base64 编码字符串。 isData('aGVsbG8=') 应该是 true 但得到了 falsejson_decode() 无法检测到正确解码的 base 64 字符串。【参考方案11】:

base64 格式的文本通常没有空格。

我使用了这个对我来说很好用的功能。它测试字符串中的空格数是否小于 20 中的 1。

例如:每 20 个字符至少 1 个空格 --- ( 空格 / strlen )

function normalizaBase64($data)
    $spaces = substr_count ( $data ," ");
    if (($spaces/strlen($data))<0.05)
    
        return base64_decode($data);
    
    return $data;

【讨论】:

【参考方案12】:

您最好的选择是:

$base64_test = mb_substr(trim($some_base64_data), 0, 76);
return (base64_decode($base64_test, true) === FALSE ? FALSE : TRUE);

【讨论】:

以上是关于在 PHP 中检测 base64 编码?的主要内容,如果未能解决你的问题,请参考以下文章

用于检测 base64 编码字符串的正则表达式

检测base64编码

通过python扩展spark mllib 算法包(e.g.基于spark使用孤立森林进行异常检测)

PHP IMAP 解码消息

字符串是 64 位编码的吗?

C# UTF-8 base64 编码在 PHP 中无法正确解码