Charger un fichier
  1. base64hub
  2. Base64 dans le code
  3. PHP
Code

Base64 en PHP

PHP propose deux fonctions, base64_encode et base64_decode, ainsi qu’un filtre de flux pour les gros fichiers. Toutes les sorties ci-dessous proviennent de PHP 8.4.

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éeRé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==") renvoie string(6) "<<���", pas <<???>>. Convertissez d’abord avec strtr.
  • Passer null. Depuis PHP 8.1, vous obtenez Deprecated: base64_encode(): Passing null to parameter #1 ($string) of type string is deprecated. Passer un tableau lève TypeError: 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 ou rawurlencode.
  • S’en servir pour stocker des mots de passe. Base64 ne cache rien. Utilisez password_hash pour les mots de passe et voyez encodage ou chiffrement.

Notes de version

  • base64_encode, base64_decode et le paramètre $strict existent dans toutes les versions de PHP maintenues (le mode strict est arrivé avec la 5.2).
  • Depuis PHP 8.0, base64_decode est déclarée comme renvoyant string|false, et passer un tableau ou un objet lève une TypeError au lieu d’un avertissement.
  • Le filtre convert.base64-encode accepte les options line-length et line-break-chars pour une sortie MIME, par exemple stream_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.

Continuer la lecture