web-dev-qa-db-ja.com

PHPでbase64エンコーディングを検出しますか?

PHPで文字列がbase64_encoded()されているかどうかを検出する方法はありますか?

一部のストレージをプレーンテキストからbase64に変換しており、その一部は更新が必要なCookie内にあります。テキストがまだエンコードされていない場合、Cookieをリセットします。それ以外の場合はそのままにします。

29

既に回答された質問に対する遅い回答をおologiesびしますが、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

おそらく、max()の代わりにデコードされた値のmean()を使用する必要があります。PHPには残念ながら組み込みのmean()がないため、この例ではmax()を使用しました。どのしきい値(例:200)に対してどの尺度(平均、最大など)を使用するかは、推定使用プロファイルによって異なります。

結論として、勝つ唯一の動きはプレーしないことです。私はそもそもbase64を見分けることを避けたいと思います。

25
chrishiestand

私は同じ問題を抱えていた、私はこの解決策で終わった:

if ( base64_encode(base64_decode($data)) === $data){
    echo '$data is valid';
} else {
    echo '$data is NOT valid';
}
18
Amir
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

16
alex

3つのことを1つの関数に組み合わせて、指定された文字列が有効なBase 64エンコードかどうかをチェックできます。

function validBase64($string)
{
    $decoded = base64_decode($string, true);

    // Check if there is no invalid character in string
    if (!preg_match('/^[a-zA-Z0-9\/\r\n+]*={0,2}$/', $string)) return false;

    // Decode the string in strict mode and send the response
    if (!base64_decode($string, true)) return false;

    // Encode and compare it to original one
    if (base64_encode($decoded) != $string) return false;

    return true;
}
8

私は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

4
Albert

私のソリューションは次のとおりです。

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

デコードされた$stringは無効です。たとえば、「node」、「123」、「」など。

3
Special K.

入力が有効なbase64エンコードデータでない場合、base64_decode()はFALSEを返しません。代わりにimap_base64()を使用してください。$ textにBase64アルファベット以外の文字が含まれている場合はFALSEを返します imap_base64()Reference

3
Sivaguru

決して遅くない方がよい: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;
  }
}
1
Marki

たぶんあなたが求めたものとは違うかもしれません。しかし、それが誰かに役立つことを願っています。

私の場合、解決策はすべてのデータを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;
   }

このスレッドの以前のすべての回答の著者に感謝します:)

0
Mikhail.root

最適なオプションは次のとおりです。

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

通常、base64のテキストにはスペースがありません。

私はうまく機能したこの機能を使用しました。文字列内のスペースの数が20分の1より小さいかどうかをテストします。

例:20文字ごとに少なくとも1スペース---(スペース/ strlen)<0.05

function normalizaBase64($data){
    $spaces = substr_count ( $data ," ");
    if (($spaces/strlen($data))<0.05)
    {
        return base64_decode($data);
    }
    return $data;
}
0
Gustavo Gallas