Zum Inhalt springen

Caesar-Verschlüsselung in PHP

Die ganze Funktion hat rund ein Dutzend Zeilen. Kopiere sie, oder gib eigenen Text ein und schau zu, was der Code mit jedem Buchstaben macht.

caesar.php
<?php function caesar(string $text, int $shift): string{    $result = '';    foreach (str_split($text) as $c) {        if (ctype_alpha($c)) {            $base = ctype_upper($c) ? 65 : 97;            $index = ((ord($c) - $base + $shift) % 26 + 26) % 26;            $result .= chr($index + $base);        } else {            $result .= $c;        }    }    return $result;} echo caesar('Hallo Welt!', 3), "\n";// Kdoor Zhow!
Werbung

Den Code ausführen

Speichere den Code als caesar.php und starte ihn im Terminal. Einen Webserver brauchst du dafür nicht:

Terminal
php caesar.php

Ist die Chiffre selbst noch neu für dich, hilft die Anleitung ganz ohne Code.

So funktioniert der Code

str_split zerlegt den Text in einzelne Bytes, und ctype_alpha erkennt die Buchstaben A bis Z. ord() liefert die Nummer eines Buchstabens: 72 für H und 104 für h. Ziehst du 65 oder 97 ab, erhältst du die Position im Alphabet, von 0 bis 25.

Nach dem Addieren der Verschiebung sorgt der Modulo dafür, dass es vorne weitergeht: Bei der Verschiebung 3 landet Z auf C. chr() macht aus der Zahl wieder einen Buchstaben.

Leerzeichen, Satzzeichen und Ziffern laufen unverändert durch den else-Zweig. Das gilt auch für Umlaute: In UTF-8 ist ä zwei Bytes groß, und keines davon gilt für ctype_alpha als Buchstabe.

Entschlüsseln in PHP

Eine zweite Funktion brauchst du nicht. Entschlüsseln ist dieselbe Verschiebung in die andere Richtung, also übergibst du eine negative Zahl:

PHP
echo caesar('Kdoor Zhow!', -3), "\n";// Hallo Welt!

Deshalb steht in der Formel das zusätzliche + 26. In PHP behält % das Vorzeichen der linken Zahl, -3 % 26 ergibt also -3, und diese Position gibt es nicht. Mit 26 dazu und einem zweiten Modulo kommt 23 heraus, und A geht zurück zu X. PHP bringt übrigens str_rot13() mit, das kennt aber nur die Verschiebung 13.

Ein Webformular

Setz diesen Code unter die Funktion, speichere die Datei und starte den eingebauten Server mit php -S localhost:8000 caesar.php. Öffne dann diese Adresse im Browser.

PHP
<?php$text = $_POST['text'] ?? '';$shift = (int) ($_POST['shift'] ?? 3);$result = $text === '' ? '' : caesar($text, $shift);?><form method="post">    <textarea name="text"><?= htmlspecialchars($text) ?></textarea>    <input name="shift" type="number" value="<?= $shift ?>">    <button>Verschlüsseln</button></form><p><?= htmlspecialchars($result) ?></p>

Beide Ausgaben laufen durch htmlspecialchars, denn der Text stammt vom Besucher. Ohne das könnte jeder ein Skript in deine Seite einschleusen.

Ein Kommandozeilen-Skript

Ersetze die letzten beiden Zeilen von caesar.php durch diesen Code, dann kommen Verschiebung und Text als Argumente:

PHP
if ($argc !== 3) {    exit("Aufruf: php caesar.php <Verschiebung> <Text>\n");} echo caesar($argv[2], (int) $argv[1]), "\n"; // php caesar.php 3 "Hallo"// Kdoor

Ein JSON-Endpunkt in Laravel

Lege die Funktion in einem Laravel-Projekt in einen Helper oder eine eigene Klasse und ergänze diese Route in routes/api.php. Laravel prüft die Eingabe und gibt das Array als JSON zurück.

PHP
use Illuminate\Http\Request;use Illuminate\Support\Facades\Route; Route::post('/caesar', function (Request $request) {    $data = $request->validate([        'text' => 'required|string|max:1000',        'shift' => 'required|integer|between:-25,25',    ]);     return ['result' => caesar($data['text'], (int) $data['shift'])];});

Auf ungültige Eingaben antwortet das Framework selbst mit einem Fehler, die Funktion bekommt also nur saubere Werte. Brauchst du einfach einen fertigen Endpunkt, läuft unsere kostenlose REST-API bereits.

Die Chiffre mit Brute Force knacken

Bei 26 Buchstaben gibt es nur 25 Verschiebungen zum Ausprobieren, also liest eine kurze Schleife die Nachricht auch ohne Schlüssel. Du musst nur die Zeile finden, die einen Sinn ergibt:

PHP
function crack(string $text): void{    for ($shift = 1; $shift < 26; $shift++) {        echo $shift, ' ', caesar($text, -$shift), "\n";    }} crack('Kdoor Zhow!');// 1 Jcnnq Ygnv!// 2 Ibmmp Xfmu!// 3 Hallo Welt!// ...

Mehr dazu steht im Artikel über den Brute-Force-Angriff, und der Caesar-Knacker erledigt dasselbe im Browser.

Caesar mit Umlauten und ß

Sollen auch ä, ö, ü und ß verschoben werden, legst du das Alphabet als String ab und nutzt die mb_-Funktionen, die Zeichen statt Bytes zählen. Das sind dieselben 30 Zeichen wie in unserem Tool:

PHP
const ALPHABET = 'aäbcdefghijklmnoöpqrstuüvwxyzß'; function caesarAlphabet(string $text, int $shift): string{    $size = mb_strlen(ALPHABET);    $result = '';    foreach (mb_str_split($text) as $c) {        $lower = mb_strtolower($c);        $position = mb_strpos(ALPHABET, $lower);        if ($position === false) {            $result .= $c;        } else {            $index = (($position + $shift) % $size + $size) % $size;            $next = mb_substr(ALPHABET, $index, 1);            $result .= $c === $lower ? $next : mb_strtoupper($next);        }    }    return $result;} echo caesarAlphabet('Schöne Grüße', 3), "\n";// Üfkrph Juxbh

Der Umlauf nutzt jetzt mb_strlen, die 30 musst du also nirgends eintragen. Eine Besonderheit hat das ß: mb_strtoupper('ß') ergibt SS, ein Großbuchstabe, der auf ß fällt, wird also zu zwei Zeichen. Vergleichen kannst du das Ergebnis im Caesar-Tool mit dem deutschen Alphabet.

Eine Textdatei verschlüsseln

Lies die ganze Datei mit file_get_contents und schreib das Ergebnis mit file_put_contents. Die erste Funktion liefert im Fehlerfall false, das solltest du prüfen.

PHP
$text = file_get_contents('message.txt'); if ($text === false) {    exit("message.txt kann nicht gelesen werden\n");} file_put_contents('encrypted.txt', caesar($text, 3));

Dieselbe Chiffre als Klasse

Eine Klasse lohnt sich, wenn du einen Schlüssel oft verwendest. Eine readonly-Klasse, verfügbar ab PHP 8.2, verhindert, dass sich die Verschiebung nachträglich ändert:

PHP
final readonly class CaesarCipher{    public function __construct(private int $shift = 3)    {    }     public function encrypt(string $text): string    {        return caesar($text, $this->shift);    }     public function decrypt(string $text): string    {        return caesar($text, -$this->shift);    }} echo (new CaesarCipher(5))->encrypt('Hallo Welt!'), "\n";// Mfqqt Bjqy!

Den Code testen

Produktionseinstellungen schalten assert meist ab, aktiviere es also für die Tests: php -d zend.assertions=1 -d assert.exception=1 caesar.php. Ist alles in Ordnung, gibt das Programm OK aus. In einem echten Projekt passen dieselben Prüfungen in PHPUnit oder Pest.

PHP
assert(caesar('ABC', 3) === 'DEF');assert(caesar('xyz', 3) === 'abc');assert(caesar('Hello, World!', 5) === 'Mjqqt, Btwqi!');assert(caesar(caesar('PHP', 7), -7) === 'PHP');assert(caesar('A', -27) === 'Z');assert(caesar('é', 3) === 'é');echo "OK\n";

Häufige Fehler

Am häufigsten ist % bei negativer Verschiebung, wie oben beschrieben. Danach kommt die Ausgabe ohne htmlspecialchars. Außerdem arbeiten strlen und $text[0] mit Bytes und zerschneiden in UTF-8-Text Umlaute. Für ganze Zeichen nimmst du die mb_-Funktionen.

Häufige Fragen

Welche PHP-Version brauche ich?

Die Hauptfunktion läuft ab PHP 7, die readonly-Klasse braucht PHP 8.2. Wir haben den Code dieser Seite mit PHP 8.4 ausgeführt.

Kann ich damit echte Daten schützen?

Nein. Die Schleife von oben knackt die Chiffre in Sekunden. Nimm sie zum Lernen und für Rätsel. Für echte Daten hat PHP moderne Verschlüsselung in der Erweiterung sodium, und Passwörter gehören in password_hash().

Wie prüfe ich, ob mein Ergebnis stimmt?

Gib denselben Text und dieselbe Verschiebung in unser Caesar-Tool ein und vergleiche. Aus deinen Tests heraus kannst du auch die kostenlose REST-API aufrufen.

Wie es weitergeht