Encoder et décoder une chaîne
Les chaînes PHP sont des chaînes d’octets : base64_encode encode donc les octets que contient la chaîne, quels qu’ils soient. Avec un fichier source enregistré en UTF-8, vous obtenez du Base64 d’UTF-8 sans étape de conversion :
<?php
$enc = base64_encode("héllo wörld");
echo $enc; // aMOpbGxvIHfDtnJsZA==
echo base64_decode($enc); // héllo wörld
Si le texte vient d’une base de données ou d’un formulaire dans un autre jeu de caractères, convertissez-le d’abord avec mb_convert_encoding($s, 'UTF-8', 'Windows-1252'). Sinon, le Base64 est correct pour ces octets, mais se décode en mojibake ailleurs. L’outil Base64 en texte permet d’essayer différents jeux de caractères sur le résultat.
Le mode strict : base64_decode($s, true)
Sans le deuxième argument, base64_decode jette tout caractère qui n’est pas dans l’alphabet et décode le reste. Avec true, la fonction renvoie false à la place :
var_dump(base64_decode("aGk=!!")); // string(2) "hi"
var_dump(base64_decode("aGk=!!", true)); // bool(false)
Testez toujours avec === : une entrée vide valide se décode en "", qui est évalué comme faux.
$bytes = base64_decode($input, true);
if ($bytes === false) {
throw new InvalidArgumentException('Invalid Base64');
}
Le mode strict l’est moins que son nom ne le laisse croire. Tests effectués sous PHP 8.4 :
| Entrée | Résultat en mode strict |
|---|---|
aGk (sans remplissage) | "hi" |
"aGk=\n" (saut de ligne final) | "hi" |
aGl= (bits de remplissage non nuls) | "hi" |
aGk== (remplissage en trop) | false |
a (longueur impossible) | false |
PDw_Pz8-Pg== (caractères URL-safe) | false |
Si vous n’acceptez que du Base64 canonique, supprimez les espaces, décodez en mode strict, puis vérifiez base64_encode($bytes) === $input. Le validateur Base64 effectue les mêmes contrôles et désigne le caractère fautif.
Base64 URL-safe avec et sans remplissage
PHP n’a pas de fonction Base64URL intégrée. Échangez les deux caractères avec strtr, plus rapide que str_replace pour des correspondances caractère par caractère :
function b64url_encode(string $data, bool $pad = false): string {
$s = strtr(base64_encode($data), '+/', '-_');
return $pad ? $s : rtrim($s, '=');
}
function b64url_decode(string $s): string|false {
return base64_decode(strtr($s, '-_', '+/'), true);
}
echo b64url_encode("<<???>>"); // PDw_Pz8-Pg
echo b64url_encode("<<???>>", true); // PDw_Pz8-Pg==
echo b64url_decode("PDw_Pz8-Pg"); // <<???>>
Comme le mode strict tolère l’absence de remplissage, inutile de rajouter les = avant de décoder. Plus de détails sur les différences dans Base64 ou Base64URL.
Encoder et décoder un fichier
echo base64_encode(file_get_contents("hello.txt")); // aGVsbG8K
file_put_contents("copy.txt", base64_decode("aGVsbG8K", true));
Pour une data URI, ajoutez le type MIME devant : 'data:image/png;base64,' . base64_encode($png). mime_content_type($path) peut détecter le type si fileinfo est activé.
Gros fichiers avec les filtres de flux
file_get_contents charge le fichier entier puis sa copie en Base64 : la mémoire utilisée atteint environ 2,3 fois la taille du fichier. Le filtre de flux convert.base64-encode encode au fil de la copie :
$in = fopen("big.bin", "rb");
$out = fopen("big.b64", "wb");
stream_filter_append($out, "convert.base64-encode");
stream_copy_to_stream($in, $out);
fclose($in);
fclose($out);
Le décodage fonctionne de la même façon, ou en une ligne avec une URL php://filter :
copy("php://filter/read=convert.base64-decode/resource=big.b64", "big.out");
Les deux ont produit une sortie identique à celle des fonctions en mémoire sur un fichier de test de 300 Ko. Une boucle manuelle marche aussi si chaque morceau est un multiple de 3 octets, par exemple fread($in, 3 * 8192). Toute autre taille insère des = au milieu de la sortie.
Découpage des lignes MIME
Le corps des e-mails exige des lignes de 76 caractères au plus. chunk_split fait exactement cela, avec des fins de ligne \r\n par défaut :
echo chunk_split(base64_encode(str_repeat("x", 60)));
// eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4
// eHh4
La fonction ajoute aussi un \r\n final. Les bibliothèques d’e-mail s’en chargent pour vous ; l’encodeur Base64 MIME montre le format.
Pièges courants
- Oublier le mode strict sur une entrée non fiable. Des données invalides se décodent en octets aléatoires et l’erreur se manifeste loin de sa cause.
- Une entrée URL-safe en mode par défaut.
base64_decode("PDw_Pz8-Pg==")renvoiestring(6) "<<���", pas<<???>>. Convertissez d’abord avecstrtr. - Passer
null. Depuis PHP 8.1, vous obtenezDeprecated: base64_encode(): Passing null to parameter #1 ($string) of type string is deprecated. Passer un tableau lèveTypeError: base64_encode(): Argument #1 ($string) must be of type string, array given. - Le
+qui devient une espace. Du Base64 standard dans une chaîne de requête est abîmé par le décodage d’URL, car+y signifie espace. Utilisez la variante URL-safe ourawurlencode. - S’en servir pour stocker des mots de passe. Base64 ne cache rien. Utilisez
password_hashpour les mots de passe et voyez encodage ou chiffrement.
Notes de version
base64_encode,base64_decodeet le paramètre$strictexistent dans toutes les versions de PHP maintenues (le mode strict est arrivé avec la 5.2).- Depuis PHP 8.0,
base64_decodeest déclarée comme renvoyantstring|false, et passer un tableau ou un objet lève uneTypeErrorau lieu d’un avertissement. - Le filtre
convert.base64-encodeaccepte les optionsline-lengthetline-break-charspour une sortie MIME, par exemplestream_filter_append($out, 'convert.base64-encode', STREAM_FILTER_WRITE, ['line-length' => 76, 'line-break-chars' => "\r\n"]).
FAQ
À quoi sert le deuxième paramètre de base64_decode ?
base64_decode($s, true) active le mode strict : la fonction renvoie false quand l’entrée contient des caractères hors de l’alphabet Base64. Sans lui, ces caractères sont supprimés sans avertissement.
PHP a-t-il une fonction base64url_encode ?
Non. Utilisez rtrim(strtr(base64_encode($data), '+/', '-_'), '=') pour encoder et base64_decode(strtr($s, '-_', '+/'), true) pour décoder. Le mode strict accepte le remplissage manquant.
Le mode strict de base64_decode est-il un vrai validateur ?
Non. Il accepte toujours les espaces, un remplissage manquant et des bits de remplissage non nuls comme dans aGl=. Pour une validation exacte, réencodez le résultat et comparez-le avec l’entrée normalisée.
Pourquoi base64_decode renvoie-t-il n'importe quoi au lieu de false ?
Vous l’avez sans doute appelé sans true. En mode par défaut, base64_decode('PDw_Pz8-Pg==') supprime les _ et - et renvoie six octets erronés. Convertissez d’abord l’entrée URL-safe avec strtr.