web-dev-qa-db-fra.com

Détecter l'encodage base64 en PHP?

Est-il possible de détecter si une chaîne a été base64_encoded () en PHP? 

Nous convertissons une base de stockage de texte brut en base64 et une partie de celle-ci réside dans un cookie qui doit être mis à jour. J'aimerais réinitialiser leur cookie si le texte n'a pas encore été encodé, sinon laissez-le tranquille.

26

Toutes mes excuses pour une réponse tardive à une question déjà répondue, mais je ne pense pas que base64_decode ($ x, true) soit une solution suffisamment bonne pour résoudre ce problème. En fait, il peut ne pas y avoir une très bonne solution qui va à l’encontre d’une entrée donnée. Par exemple, je peux mettre beaucoup de mauvaises valeurs dans $ x et ne pas obtenir une valeur de retour fausse.

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Ǻ��ܡם"

Je pense qu’en plus de la vérification stricte de la valeur de retour, vous devez également effectuer une validation post-décodage. Le moyen le plus fiable consiste à décoder puis à vérifier un ensemble connu de valeurs possibles.

Une solution plus générale avec une précision inférieure à 100% (plus proche avec des chaînes longues, imprécises pour des chaînes courtes) consiste à vérifier votre sortie pour voir si nombre d'entre elles se trouvent en dehors d'une plage normale de caractères utf-8 (ou du codage que vous utilisez).

Voir cet exemple:

<?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";

?>

Résultats:

Max value english = 195
Max nonsense = 233

Donc, vous pouvez faire quelque chose comme ça:

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

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

Vous devriez probablement utiliser la moyenne () des valeurs décodées au lieu de la max (), je viens d'utiliser max () dans cet exemple car il n'y a malheureusement pas de moyenne intégrée () dans PHP. Quelle mesure utilisez-vous (moyenne, maximum, etc.) par rapport à quel seuil (200, par exemple) dépend de votre profil d'utilisation estimé?.

En conclusion, le seul coup gagnant est de ne pas jouer. J'essayerais d'éviter de devoir discerner base64 en premier lieu.

24
chrishiestand

J'ai eu le même problème, j'ai fini avec cette solution:

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

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

12
alex

Nous pouvons combiner trois choses en une seule fonction pour vérifier si une chaîne donnée est une base 64 valide, codée ou non.

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;
}
7
Abhinav bhardwaj

J'étais sur le point de construire une bascule base64 en php, voici ce que j'ai fait:

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);
}

Cela fonctionne parfaitement pour moi . Voici toutes mes pensées à ce sujet: http://www.albertmartin.de/blog/code.php/19/base64-detection

Et ici, vous pouvez l'essayer: http://www.albertmartin.de/tools

3
Albert

base64_decode () ne retournera pas FALSE si l'entrée n'est pas une donnée encodée en base64 valide. Utilisez plutôt imap_base64(), il renvoie FALSE si $ text contient des caractères extérieurs à l'alphabet Base64 imap_base64 () Référence

2
Sivaguru

Voici ma solution:

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

Il renverra false si le $string décodé est invalide, par exemple: "noeud", "123", "", etc.

1
Special K.

Peut-être que ce n'est pas exactement ce que vous avez demandé. Mais espérons que ce sera utile pour quelqu'un.

Dans mon cas, la solution consistait à coder toutes les données avec json_encode, puis base64_encode.

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

cette valeur peut être stockée ou utilisée selon vos besoins . Ensuite, pour vérifier si cette valeur n'est pas simplement une chaîne de texte mais que vos données codées sont simplement utilisées

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

ou bien

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

Merci à tous les auteurs de réponses précédentes dans ce fil :)

0
Mikhail.root

Votre meilleure option est:

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

Habituellement, un texte en base64 n'a pas d'espaces. 

J'ai utilisé cette fonction qui a bien fonctionné pour moi. Il teste si le nombre d'espaces dans la chaîne est inférieur à 1 sur 20.

par exemple: au moins 1 espace pour 20 caractères --- (espaces/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

Mieux vaut tard que jamais: vous pourriez peut-être utiliser mb_detect_encoding() pour savoir si la chaîne encodée semble avoir été un texte quelconque:

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;
  }
}
0
Marki