Datei hochladen
  1. base64hub
  2. Base64 im Code
  3. PHP
Code

Base64 in PHP

PHP hat zwei Funktionen, base64_encode und base64_decode, dazu einen Stream-Filter für große Dateien. Alle Ausgaben unten stammen von PHP 8.4.

Einen String kodieren und dekodieren

PHP-Strings sind Bytestrings, base64_encode kodiert also genau die Bytes, die der String enthält. Eine als UTF-8 gespeicherte Quelldatei liefert Ihnen UTF-8-Base64 ohne Umwandlungsschritt:

<?php
$enc = base64_encode("héllo wörld");
echo $enc;                  // aMOpbGxvIHfDtnJsZA==
echo base64_decode($enc);   // héllo wörld

Kommt Text aus einer Datenbank oder einem Formular in einem anderen Zeichensatz, wandeln Sie ihn zuerst mit mb_convert_encoding($s, 'UTF-8', 'Windows-1252') um. Sonst ist das Base64 für diese Bytes zwar korrekt, ergibt anderswo dekodiert aber Zeichensalat. Mit dem Tool Base64 in Text können Sie verschiedene Zeichensätze auf das Ergebnis anwenden.

Strict-Modus: base64_decode($s, true)

Ohne das zweite Argument wirft base64_decode jedes Zeichen weg, das nicht im Alphabet steht, und dekodiert den Rest. Mit true gibt es stattdessen false zurück:

var_dump(base64_decode("aGk=!!"));        // string(2) "hi"
var_dump(base64_decode("aGk=!!", true));  // bool(false)

Prüfen Sie immer mit ===, denn eine gültige leere Eingabe ergibt "", und das ist falsy:

$bytes = base64_decode($input, true);
if ($bytes === false) {
    throw new InvalidArgumentException('Invalid Base64');
}

Der Strict-Modus ist weniger streng, als der Name vermuten lässt. Getestet mit PHP 8.4:

EingabeErgebnis im Strict-Modus
aGk (ohne Padding)"hi"
"aGk=\n" (abschließender Zeilenumbruch)"hi"
aGl= (Padding-Bits ungleich null)"hi"
aGk== (überzähliges Padding)false
a (unmögliche Länge)false
PDw_Pz8-Pg== (URL-sichere Zeichen)false

Brauchen Sie ausschließlich kanonisches Base64, entfernen Sie Leerraum, dekodieren im Strict-Modus und prüfen dann base64_encode($bytes) === $input. Der Base64-Validator führt dieselben Prüfungen aus und zeigt auf das fehlerhafte Zeichen.

URL-sicheres Base64 mit und ohne Padding

PHP hat keine eingebaute Base64URL-Funktion. Tauschen Sie die beiden Zeichen mit strtr, das bei Abbildungen einzelner Zeichen schneller ist als str_replace:

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

Da der Strict-Modus fehlendes Padding toleriert, müssen Sie vor dem Dekodieren kein = ergänzen. Mehr zu den Unterschieden unter Base64 vs. Base64URL.

Eine Datei kodieren und dekodieren

echo base64_encode(file_get_contents("hello.txt"));   // aGVsbG8K

file_put_contents("copy.txt", base64_decode("aGVsbG8K", true));

Für eine Data-URI stellen Sie den MIME-Typ voran: 'data:image/png;base64,' . base64_encode($png). Ist fileinfo aktiviert, kann mime_content_type($path) den Typ erkennen.

Große Dateien mit Stream-Filtern

file_get_contents lädt die ganze Datei plus die Base64-Kopie, der Speicherbedarf liegt also bei etwa dem 2,3-Fachen der Dateigröße. Der Stream-Filter convert.base64-encode kodiert beim Kopieren:

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

Das Dekodieren funktioniert genauso oder in einer Zeile über eine php://filter-URL:

copy("php://filter/read=convert.base64-decode/resource=big.b64", "big.out");

Beide lieferten bei einer 300-KB-Testdatei dieselbe Ausgabe wie die Funktionen im Speicher. Eine eigene Schleife funktioniert ebenfalls, wenn jeder Block ein Vielfaches von 3 Bytes ist, zum Beispiel fread($in, 3 * 8192). Jede andere Größe setzt = mitten in die Ausgabe.

MIME-Zeilenumbruch

E-Mail-Inhalte brauchen Zeilen mit höchstens 76 Zeichen. Genau das macht chunk_split, standardmäßig mit \r\n als Zeilenende:

echo chunk_split(base64_encode(str_repeat("x", 60)));
// eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4
// eHh4

Es hängt außerdem ein abschließendes \r\n an. Mail-Bibliotheken erledigen das für Sie; der MIME-Base64-Encoder zeigt das Format.

Häufige Fallstricke

  • Strict-Modus vergessen bei nicht vertrauenswürdigen Eingaben. Fehlerhafte Daten werden zu zufälligen Bytes dekodiert und scheitern irgendwo weit entfernt von der Ursache.
  • URL-sichere Eingabe im Standardmodus. base64_decode("PDw_Pz8-Pg==") liefert string(6) "<<���", nicht <<???>>. Übersetzen Sie vorher mit strtr.
  • null übergeben. Ab PHP 8.1 erhalten Sie Deprecated: base64_encode(): Passing null to parameter #1 ($string) of type string is deprecated. Ein Array wirft TypeError: base64_encode(): Argument #1 ($string) must be of type string, array given.
  • + wird zum Leerzeichen. Standard-Base64 in einem Query-String wird durch das URL-Dekodieren verstümmelt, weil + dort ein Leerzeichen bedeutet. Verwenden Sie die URL-sichere Variante oder rawurlencode.
  • Als Passwortspeicher verwenden. Base64 verbirgt nichts. Verwenden Sie password_hash für Passwörter und lesen Sie Kodierung vs. Verschlüsselung.

Versionshinweise

  • base64_encode, base64_decode und das Flag $strict gibt es in allen unterstützten PHP-Versionen (der Strict-Modus kam mit 5.2).
  • Seit PHP 8.0 ist der Rückgabetyp von base64_decode als string|false deklariert, und ein Array oder Objekt wirft einen TypeError statt einer Warnung.
  • Der Filter convert.base64-encode akzeptiert die Optionen line-length und line-break-chars für MIME-Ausgabe, zum Beispiel stream_filter_append($out, 'convert.base64-encode', STREAM_FILTER_WRITE, ['line-length' => 76, 'line-break-chars' => "\r\n"]).

Häufige Fragen

Was bewirkt der zweite Parameter von base64_decode?

base64_decode($s, true) aktiviert den Strict-Modus: Die Funktion gibt false zurück, wenn die Eingabe Zeichen außerhalb des Base64-Alphabets enthält. Ohne ihn werden diese Zeichen stillschweigend verworfen.

Hat PHP eine Funktion base64url_encode?

Nein. Kodieren Sie mit rtrim(strtr(base64_encode($data), '+/', '-_'), '=') und dekodieren Sie mit base64_decode(strtr($s, '-_', '+/'), true). Der Strict-Modus akzeptiert das fehlende Padding.

Ist der Strict-Modus von base64_decode ein vollständiger Validator?

Nein. Er akzeptiert weiterhin Leerraum, fehlendes Padding und Padding-Bits ungleich null wie bei aGl=. Für eine exakte Prüfung kodieren Sie das Ergebnis erneut und vergleichen es mit der normalisierten Eingabe.

Warum liefert base64_decode Datenmüll statt false?

Wahrscheinlich haben Sie es ohne true aufgerufen. Im Standardmodus verwirft base64_decode('PDw_Pz8-Pg==') das _ und das - und liefert sechs falsche Bytes. Übersetzen Sie URL-sichere Eingaben vorher mit strtr.

Weiterlesen