【问题标题】:How to check if a string is base64 valid in PHP如何检查字符串在 PHP 中是否为 base64 有效
【发布时间】:2011-05-15 18:05:48
【问题描述】:

我有一个字符串,想用 PHP 测试它是否是有效的 base64 编码。

【问题讨论】:

  • 这可能是重复的。

标签: php validation base64


【解决方案1】:

我意识到这是一个老话题,但使用 strict 参数不一定有帮助。

对诸如“我不是 base 64 编码”之类的字符串运行 base64_decode 不会返回 false。

如果您尝试使用 strict 解码字符串并使用 base64_encode 重新编码,您可以将结果与原始数据进行比较以确定它是否是有效的 bas64 编码值:

if ( base64_encode(base64_decode($data, true)) === $data){
    echo '$data is valid';
} else {
    echo '$data is NOT valid';
}

【讨论】:

  • 为什么这不起作用?字符串“节点”编码为 bm9kZQ==(我已经测试过了)
  • @Sam 那是因为“test”是一个非常好的base64字符串。它仅使用 base64 字符(a-z、A-Z、0-9),并且它的长度完全可以被 4 整除。这些是有效 base64 字符串的唯一要求。输入“test”时你预计会发生什么?
  • @PottyBert 如果您的 sn-p 返回无效,您知道如何找出问题所在吗?我使用了几个在线编码器对png图像进行编码,都返回不同的base64字符串并且根据这个sn-p都是无效的。
  • 即使使用 Laravel 的 crypt() 库,也能像魅力一样工作。
  • @catbadger 但这不是这个问题的目的,它是关于确定数据是否是有效的base64,字符串“123412341234”是,只是因为这对你的目的来说不够好,不是' t 表示它不是有效的 base64。在您的实例中,如果您控制数据的编码,则可以在 base64 编码之前以某种方式对其进行标记,这样您就可以确定是否应该在解码后通过解密传递它
【解决方案2】:

你可以使用这个功能:

 function is_base64($s)
{
      return (bool) preg_match('/^[a-zA-Z0-9\/\r\n+]*={0,2}$/', $s);
}

【讨论】:

  • 我认为这是最接近检测此问题的最佳方法。 base64_decode(
  • 我会在这里留下一个注释:注意正则表达式主题最大大小secure.php.net/manual/en/pcre.constants.php#118538 在 PHP 7 中,至少您将无法以这种方式检查 base64 编码的图像(默认PHP 设置)
  • 这不会检测到无效的 base 64 字符串,它只是检查字符集和格式是否正确。只需将 1 添加到任何未填充的 base64 编码字符串的末尾,它就会忽略附加的 1 进行解码。严格检查在这种情况下也不起作用。
  • @DeveloperChris 好吧,如果未填充的 base64 编码字符串的长度是 4 的倍数,那么添加到字符串末尾的任何其他字符都应该被忽略。但这没关系。
【解决方案3】:

对于字符串,你可以使用这个函数,在返回 true 之前检查几个 base64 属性:

function is_base64($s){
    // Check if there are valid base64 characters
    if (!preg_match('/^[a-zA-Z0-9\/\r\n+]*={0,2}$/', $s)) return false;

    // Decode the string in strict mode and check the results
    $decoded = base64_decode($s, true);
    if(false === $decoded) return false;

    // Encode the string again
    if(base64_encode($decoded) != $s) return false;

    return true;
}

【讨论】:

  • 这和我自己的实现很相似。首先检查有效字符,然后检查解码/编码字符串并与原始字符进行比较。
  • 最短版本function is_base64($s) { $decoded = base64_decode($s, true); return preg_match('/^[a-zA-Z0-9\/\r\n+]*={0,2}$/', $s) && false !== $decoded && base64_encode($decoded) == $s; }
  • 对于那些考虑使用 Andrew 的代码行的人,在后端(代码不在浏览器中运行)我建议易读性(同时保持性能)与所有代码在同一行中。并使用 cmets!不要增加技术债务!!!
【解决方案4】:

这段代码应该可以工作,因为如果字符串无效,解码函数会返回 FALSE:

if (base64_decode($mystring, true)) {
    // is valid
} else {
    // not valid
}

您可以在the documentation 中阅读有关 base64_decode 函数的更多信息。

【讨论】:

  • 否决,因为这不是确定字符串是否编码为 base64 的正确方法。它只检查字符串是否包含 base64 字母表之外的字符。正如 Kris 所说,字符串“我不是基于 64 位编码的”使用此方法不会返回 false。
  • 莫里斯在这里是正确的。请不要依赖这个答案。它是不正确的,并且不会确定字符串是否是 base64 编码的。来自文档:strict: Returns FALSE if input contains character from outside the base64 alphabet.我不知道为什么 PHP 决定以这种方式处理它,但无论如何,它并没有真正检测到 base64 编码。克里斯的回答是正确的。
  • 这会返回有效的“and”。 "and" 无效(base64 编码应该有许多可以被 4 整除的字符)。 base64_decode 将解码无效字符串。
  • @liljoshu 至于“可被 4 整除”,对于填充的 base64 字符串来说是正确的,但它们不必填充。
【解决方案5】:

我认为唯一的方法是执行 base64_decode() 并将 $strict 参数设置为 true,并查看它是否返回 false

【讨论】:

  • 制作CW,因为这是双重欺骗
  • 由于与另一个类似答案相同的原因而投反对票:It only checks wether the string has characters outside of the base64 alphabet.
【解决方案6】:

这是一个非常古老的问题,但我发现以下方法实际上是防弹的。它还考虑了那些在验证时会导致异常的带有无效字符的奇怪字符串。

    public static function isBase64Encoded($str) 
{
    try
    {
        $decoded = base64_decode($str, true);

        if ( base64_encode($decoded) === $str ) {
            return true;
        }
        else {
            return false;
        }
    }
    catch(Exception $e)
    {
        // If exception is caught, then it is not a base64 encoded string
        return false;
    }

}

我从this page 得到这个想法,并将其改编为 PHP。

【讨论】:

  • 像“ciao”这样的字符串将被成功解码成类似:“r&�”。这不是一种防弹方法。
【解决方案7】:

我尝试了以下方法:

  • base64解码字符串,严格参数设置为true。
  • base64 编码上一步的结果。如果结果与原始字符串不同,则原始字符串不是base64编码
  • 如果结果与前一个字符串相同,则检查解码后的字符串是否包含可打印字符。我使用 php 函数 ctype_print 来检查不可打印的字符。如果输入字符串包含一个或多个不可打印字符,则该函数返回 false。

以下代码实现了上述步骤:

public function IsBase64($data) {
    $decoded_data = base64_decode($data, true);
    $encoded_data = base64_encode($decoded_data);
    if ($encoded_data != $data) return false;
    else if (!ctype_print($decoded_data)) return false;

    return true;
}

以上代码可能会返回意想不到的结果。例如,对于字符串“json”,它将返回 false。 “json”可能是一个有效的 base64 编码字符串,因为它的字符数是 4 的倍数,并且所有字符都在 base64 编码字符串的允许范围内。看来我们必须知道原始字符串的允许字符范围,然后检查解码后的数据是否有这些字符。

【讨论】:

    【解决方案8】:

    我写的这个方法在我的项目中非常有效。当您将 base64 图像传递给此方法时,如果有效则返回 true,否则返回 false。让我们尝试让我知道任何错误。我将在功能中进行编辑和学习。

    /**
     * @param $str
     * @return bool
     */
    private function isValid64base($str){
        if (base64_decode($str, true) !== false){
            return true;
        } else {
            return false;
        }
    }
    

    【讨论】:

    • 哈哈哈,真有趣……应该有!==
    • 是的,现在可以了。我以为你在拖钓,因为这在你的项目中行不通。下次在某个沙箱中创建测试。
    • @JaroslavŠtreit 谢谢。
    【解决方案9】:

    好吧,伙计们......我终于找到了解决这个问题的防弹解决方案。使用以下函数检查字符串是否为 base64 编码 -

        private function is_base64_encoded($str) {
    
           $decoded_str = base64_decode($str);
           $Str1 = preg_replace('/[\x00-\x1F\x7F-\xFF]/', '', $decoded_str);
           if ($Str1!=$decoded_str || $Str1 == '') {
              return false;
           }
           return true;
        }
    

    【讨论】:

    • 唯一真正有效的
    【解决方案10】:

    如果您使用 js 进行 api 调用以将图像/文件上传到后端,这可能会有所帮助

    function is_base64_string($string)  //check base 64 encode 
    {
      // Check if there is no invalid character in string
      if (!preg_match('/^(?:[data]{4}:(text|image|application)\/[a-z]*)/', $string)){
        return false;
      }else{
        return true;
      }
    
    }
    

    【讨论】:

      【解决方案11】:

      老话题,但我找到了这个功能并且它正在工作:

      function checkBase64Encoded($encodedString) {
      $length = strlen($encodedString);
      
      // Check every character.
      for ($i = 0; $i < $length; ++$i) {
      $c = $encodedString[$i];
      if (
      ($c < '0' || $c > '9')
      && ($c < 'a' || $c > 'z')
      && ($c < 'A' || $c > 'Z')
      && ($c != '+')
      && ($c != '/')
      && ($c != '=')
      ) {
      // Bad character found.
      return false;
      }
      }
      // Only good characters found.
      return true;
      }
      

      【讨论】:

        【解决方案12】:

        您可以通过base64_decode 发送字符串($strict 设置为 TRUE),如果输入无效,它将返回 FALSE。

        您也可以使用 f.i.正则表达式查看字符串是否包含 base64 字母表之外的任何字符,并检查它是否在末尾包含正确数量的填充(= 字符)。但是仅仅使用 base64_decode 会容易得多,而且不应该存在格式错误的字符串造成任何伤害的风险。

        【讨论】:

          【解决方案13】:

          如果您的 base64 编码数据无效,base64_decode() 应该返回 false。

          【讨论】:

            【解决方案14】:

            我知道我提出了一个非常古老的问题,并且我尝试了所有提出的方法;我终于得到了这个涵盖了我几乎所有案例的正则表达式:

            $decoded = base64_decode($string, true);
            if (0 < preg_match('/((?![[:graph:]])(?!\s)(?!\p{L}))./', $decoded, $matched)) return false;
            

            基本上,我检查每个不可打印的字符 (:graph:) 不是空格或制表符 (\s),也不是 unicode 字母(所有重音符号:èéùìà 等)

            我仍然得到这个字符的误报:£§°但我从不在字符串中使用它们,对我来说使它们无效是完全可以的。 我将此检查与@merlucin 提出的函数汇总

            结果:

            function is_base64($s)
            {
              // Check if there are valid base64 characters
              if (!preg_match('/^[a-zA-Z0-9\/\r\n+]*={0,2}$/', $s)) return false;
            
              // Decode the string in strict mode and check the results
              $decoded = base64_decode($s, true);
              if(false === $decoded) return false;
            
              // if string returned contains not printable chars
              if (0 < preg_match('/((?![[:graph:]])(?!\s)(?!\p{L}))./', $decoded, $matched)) return false;
            
              // Encode the string again
              if(base64_encode($decoded) != $s) return false;
            
              return true;
            }
            

            【讨论】:

              【解决方案15】:

              我编写了一个解决方案来验证图像检查 sintaxy

              $image = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAABfVBMVEUAAAAxMhQAoIpFLCTimAE2IRs0IBodEg4OJyEAnYcAmoUAjnoALyn5rgNJLydEKyM5lWFFLCTuogI/JyBAKCHZnQoAlIAAkn48JR6fYgCIVACDUACPbAsAW06IWgAaDw0jFQscEQ4Am4XIfQDGewDhlwHelQEAi3gAe2oAd2cAXE8gFBAeEg8AVEgAtJwAsZn/vhMAuJ//xyMAu6BfQTf/wxv9wRlcPjVhQjj/vBBdQDb/xR9oSD1iRDlWOjH9xSL/uQr+twhkRTplRjxZPDPZpydILydAQD+pezNjRTNQNS3tuCZGLSX4sQn/tQTllgDhkgAArZUAqJFvTUD/wRgGtpp2m0aPaTl+azOIcjGkhS6OaS1ONCvNnirHmSrnsifHnSfFjyemfCfcqSa/jyLwuR/ptB/MmRxiPhnpqRX1sxHzqwnCfgb+tQTYjALnmQH2qQDzpQDejgAnsYQnsYNwTkBlRTtfQi9eQS+1kCy2kSuFYSuEYSvkpRfrqxQPeVhkAAAALnRSTlMADPz0qnhzNBPry5kH/vr36ubKxLy4sKmifVVNQT84Ih4Y2aWloqKMgHdJPDwse8ZSvQAAAbVJREFUOMuV0uVzggAYx3Gsbca6u3vDqSDqBigD25nrLrvX+bfvMSeId9vnBXD3+97zCuQ/ZhUDvV1dvQOKWfFdIWOZHfDMyhRi+4ibZHZLwS5Dukea97YzzAQFYEgTdtYm3DtkhAUKkmFI0mTCCFmH8ICbsEBRhmEWwi080U+xBNwApZlgqX7+rummWJcLEkAQLhdLdWt4wbSXOqX1Hu784uKc8+jpU8o7zQva7RSnb8BR9nZesGF/oelLT2X1XNL0q31dcOGDPnwKO7eBMxw+pD8FF2a8N9vcyfttKbh9O+HwG+8MLxiL3+FXDsc9Du4djiv8Lj7GC0bTMTx6dGzEgfH4KIrH0qO8YDyQjESMvyLJwDjCs5DaKsvlzOV3ah4RkFcCM+wlckRoymcG107ntRn4ppAmSzar9Tvh830lrFbbItJM0meDBcCzT4KIFfLOzB7IdMphFzUxWMjnC4MToqNkbWVY1RPw+wM9quHVSY1gnhyShlCd4aHo9xcfDTptSKnebPxjh0Kooewgmz2ofKFStaS+z2l1Nfv79c+gqlaog6io4HI1UKItKKuBVNuCFPmDH12fd4lDaGbkAAAAAElFTkSuQmCC';
              $allowedExtensions = ['png', 'jpg', 'jpeg'];
              
              // check if the data is empty
              if (empty($image)) {
                  echo "Empty data";
              }
              
              // check base64 format
              $explode = explode(',', $image);
              if(count($explode) !== 2){
                  echo "This string isn't sintaxed as base64";
              }
              //https://stackoverflow.com/a/11154248/4830771
              if (!preg_match('%^[a-zA-Z0-9/+]*={0,2}$%', $explode[1])) {
                  echo "This string isn't sintaxed as base64";
              }
              
              // check if type is allowed
              $format = str_replace(
                      ['data:image/', ';', 'base64'], 
                      ['', '', '',], 
                      $explode[0]
              );
              if (!in_array($format, $allowedExtensions)) {
                  echo "Image type isn't allowed";
              }
              echo "This image is base64";
              

              但安全的方法是使用Intervention

              use Intervention\Image\ImageManagerStatic;
              try {
                  ImageManagerStatic::make($value);
                  return true;
              } catch (Exception $e) {
                  return false;
              }
              

              【讨论】:

                【解决方案16】:

                这里的大多数答案都不可靠

                事实上,没有可靠的答案,因为许多非 base64 编码的文本会像 base64 编码一样可读,所以没有默认的方法可以确定。

                此外,值得注意的是 base64_decode 将解码许多无效字符串 例如,and 不是有效的 base64 编码,但 base64_decode 将对其进行解码。特别是jw。 (我很难学到这一点)

                也就是说,您最可靠的方法是,如果您控制输入,则在对字符串进行编码后添加一个标识符,该标识符是唯一的而不是 base64,并将其与其他检查一起包含.它不是防弹的,但它比我见过的任何其他解决方案都更防弹。例如:

                function my_base64_encode($string){
                  $prefix = 'z64ENCODEDz_';
                  $suffix = '_z64ENCODEDz';
                  return $prefix . base64_encode($string) . $suffix;
                }
                
                function my_base64_decode($string){
                  $prefix = 'z64ENCODEDz_';
                  $suffix = '_z64ENCODEDz';
                  if (substr($string, 0, strlen($prefix)) == $prefix) {
                    $string = substr($string, strlen($prefix));
                  }
                  if (substr($string, (0-(strlen($suffix)))) == $suffix) {
                    $string = substr($string, 0, (0-(strlen($suffix))));
                  }
                      return base64_decode($string);
                }
                
                function is_my_base64_encoded($string){
                  $prefix = 'z64ENCODEDz_';
                  $suffix = '_z64ENCODEDz';
                  if (strpos($string, 0, 12) == $prefix && strpos($string, -1, 12) == $suffix && my_base64_encode(my_base64_decode($string)) == $string && strlen($string)%4 == 0){
                    return true;
                  } else {
                    return false;
                  }
                }
                

                【讨论】:

                • 您是否在第二行的函数参数内部缺少$stringbase64_encode($string) 而不是 base64_encode()?
                • 而且,第 5 行的实际解码? base64_decode(rtrim(ltrim($string, "z64ENCODEDz_"), "_z64ENCODEDz")) 而不是 rtrim(ltrim($string, "z64ENCODEDz_"), "_z64ENCODEDz")?
                • 你是对的。我也应该使用 substr 而不是修剪。也解决了这个问题。
                【解决方案17】:

                我偶然发现了我的解决方案。

                使用base64_encode(base64_decode('xxx'))检查的人可能会发现有时无法检查test5555等字符串。

                如果无效的 base 64 字符串是 base64_decode() 而没有返回 false,那么当你尝试 json_encode() 时它会死掉。这是因为解码后的字符串无效。
                所以,我使用这种方法来检查 valid base 64 encoded 字符串。

                这里是代码。

                /**
                 * Check if the given string is valid base 64 encoded.
                 *
                 * @param string $string The string to check.
                 * @return bool Return `true` if valid, `false` for otherwise.
                 */
                function isBase64Encoded($string): bool
                {
                    if (!is_string($string)) {
                        // if check value is not string.
                        // base64_decode require this argument to be string, if not then just return `false`.
                        // don't use type hint because `false` value will be converted to empty string.
                        return false;
                    }
                
                    $decoded = base64_decode($string, true);
                    if (false === $decoded) {
                        return false;
                    }
                
                    if (json_encode([$decoded]) === false) {
                        return false;
                    }
                
                    return true;
                }// isBase64Encoded
                

                这是测试代码。

                // each tests value must be 'original string' => 'base 64 encoded string'
                $testValues = [
                    555 => 'NTU1',
                    5555 => 'NTU1NQ==',
                    'hello' => 'aGVsbG8=',
                    'สวัสดี' => '4Liq4Lin4Lix4Liq4LiU4Li1',
                    'test' => 'dGVzdA==',
                ];
                
                
                foreach ($testValues as $invalid => $valid) {
                    if (isBase64Encoded($invalid) === false) {
                        echo '<strong>' . $invalid . '</strong> is invalid base 64<br>';
                    } else {
                        echo '<strong style="color:red;">Error:</strong>';
                        echo '<strong>' . $invalid . '</strong> should not be valid base 64<br>';
                    }
                
                    if (isBase64Encoded($valid) === true) {
                        echo '<strong>' . $valid . '</strong> is valid base 64<br>';
                    } else {
                        echo '<strong style="color:red;">Error:</strong>';
                        echo '<strong>' . $valid . '</strong> should not be invalid base 64<br>';
                    }
                
                    echo '<br>';
                }
                

                测试结果:

                555 是无效的 base 64
                NTU1 是有效的 base 64

                5555 基数为 64 无效
                NTU1NQ== 基数为 64 有效

                hello 是无效的 base 64
                aGVsbG8= 是有效的 base 64

                สวัสดี 基数无效 64
                4Liq4Lin4Lix4Liq4LiU4Li1 基数有效 64

                测试基数为 64 无效
                dGVzdA== 基数为 64 有效

                【讨论】:

                  【解决方案18】:

                  我正在使用这种方法。它期望最后 2 个字符是 ==

                  substr($buff, -2, 1) == '=' &amp;&amp; substr($buff, -1, 1) == '=')

                  更新:如果上述检查失败,我最终会进行另一次检查 base64_decode($buff, true)

                  【讨论】:

                  • 仅供参考:substr($buff, -2) === '==') 将相同且更快。
                  • 为了更好地表达 SangamAngre 所说的,根据所需的填充,末尾可能只有一个“=”,无论是 8 位填充还是 16 位填充。
                  • 末尾有 == 是成为有效 Base64 字符串的必要条件,但不是充分条件。
                  【解决方案19】:

                  如果数据不是有效的base64,那么函数base64_decode($string, true) 将返回FALSE。

                  【讨论】:

                  • 声明不正确。正如文档所说:“如果 $string s not valid base64 then function base64_decode($string, true) 将返回 FALSE”。所以一些无效的base64字符串比如“ciao”会被解码为“r&�”
                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 2018-02-02
                  • 1970-01-01
                  • 1970-01-01
                  • 2011-02-26
                  • 2021-10-03
                  • 1970-01-01
                  相关资源
                  最近更新 更多