Caesar Cipher en PHP: didacticiel de chiffrement prêt pour le Web
Apprenez à implémenter le chiffre César en PHP avec des exemples de code complets. Couvre les fonctions de base, la conception de classe POO, la gestion UTF-8, l'intégration de formulaires Web et un point de terminaison d'API REST pour le chiffrement.
PHP est l'un des langages côté serveur les plus largement déployés sur le Web, alimentant tout, des blogs personnels aux applications d'entreprise. L'implémentation du chiffrement César en PHP est un exercice pratique qui combine des compétences en manipulation de chaînes, en conception orientée objet et en développement Web. Parce que PHP est si étroitement lié aux applications Web, ce didacticiel va au-delà des scripts autonomes pour vous montrer comment créer des formulaires Web et des points de terminaison d'API REST qui effectuent le chiffrement César.
Ce guide couvre cinq implémentations: une fonction de base, une classe POO avec un ensemble complet de fonctionnalités, une version multi-octets sécurisée pour le texte UTF-8, un formulaire HTML interactif et un point de terminaison d'API REST JSON. Tout le code fonctionne sur PHP 8.1 ou version ultérieure.
Essayez-le en ligne: testez instantanément le cryptage du chiffre César avec notre encodeur du chiffre César gratuit avant de créer votre propre implémentation PHP.
Fonction PHP de base
L'approche la plus simple utilise une fonction autonome qui parcourt chaque caractère de la chaîne d'entrée, en décalant les lettres tout en préservant les caractères non alphabétiques.
<?php
function caesarEncrypt(string $text, int $shift): string
{
// Normalize shift to 0-25 range
$shift = (($shift % 26) + 26) % 26;
$result = '';
for ($i = 0; $i < strlen($text); $i++) {
$char = $text[$i];
if (ctype_upper($char)) {
$result .= chr((ord($char) - ord('A') + $shift) % 26 + ord('A'));
} elseif (ctype_lower($char)) {
$result .= chr((ord($char) - ord('a') + $shift) % 26 + ord('a'));
} else {
$result .= $char;
}
}
return $result;
}
function caesarDecrypt(string $text, int $shift): string
{
return caesarEncrypt($text, 26 - (($shift % 26 + 26) % 26));
}
// Example usage
$message = "Hello, World! The quick brown fox jumps over the lazy dog.";
$shift = 7;
$encrypted = caesarEncrypt($message, $shift);
$decrypted = caesarDecrypt($encrypted, $shift);
echo "Original: $message\n";
echo "Encrypted: $encrypted\n";
echo "Decrypted: $decrypted\n";
Sortie:
Original: Hello, World! The quick brown fox jumps over the lazy dog.
Encrypted: Olssv, Dvysk! Aol xbpjr iyvdu mve qbtwz vcly aol shgf kvn.
Decrypted: Hello, World! The quick brown fox jumps over the lazy dog.
Détails clés sur cette implémentation:
ord()etchr(): la fonctionord()de PHP renvoie la valeur ASCII d'un caractère etchr()reconvertit une valeur ASCII en caractère. Ce sont les équivalents PHP de la conversion vers et depuis des entiers en C ou Java.ctype_upper()etctype_lower(): ces fonctions vérifient la casse des caractères de manière plus fiable que les comparaisons manuelles de plages ASCII, bien que les deux approches fonctionnent correctement pour la saisie ASCII.- Concaténation de chaînes: les chaînes PHP sont modifiables, mais l'opérateur
.=crée de nouvelles chaînes en interne. Pour les textes très longs, cela est assez efficace puisque le moteur de chaînes de PHP gère automatiquement la gestion de la mémoire.
Classe CaesarCipher orientée objet
Une classe POO bien conçue encapsule la valeur de décalage et fournit une interface claire pour le chiffrement, le déchiffrement et l'analyse par force brute. Cette classe prend également en charge le chaînage de méthodes et implémente les fonctionnalités de PHP 8.1+ telles que les propriétés en lecture seule et les énumérations.
<?php
class CaesarCipher
{
public readonly int $shift;
public function __construct(int $shift)
{
$this->shift = (($shift % 26) + 26) % 26;
}
/**
* Encrypt plaintext using the configured shift value.
*/
public function encrypt(string $text): string
{
return $this->transform($text, $this->shift);
}
/**
* Decrypt ciphertext using the configured shift value.
*/
public function decrypt(string $text): string
{
return $this->transform($text, 26 - $this->shift);
}
/**
* Try all 26 possible shifts and return the results.
*
* @return array<int, string> Associative array mapping shift => decrypted text
*/
public static function bruteForce(string $ciphertext): array
{
$results = [];
for ($shift = 0; $shift < 26; $shift++) {
$cipher = new self($shift);
$results[$shift] = $cipher->decrypt($ciphertext);
}
return $results;
}
/**
* Score text based on English letter frequency to help identify
* the most likely decryption in brute force results.
*/
public static function scoreEnglish(string $text): float
{
$frequencies = [
'a' => 8.167, 'b' => 1.492, 'c' => 2.782, 'd' => 4.253,
'e' => 12.702, 'f' => 2.228, 'g' => 2.015, 'h' => 6.094,
'i' => 6.966, 'j' => 0.153, 'k' => 0.772, 'l' => 4.025,
'm' => 2.406, 'n' => 6.749, 'o' => 7.507, 'p' => 1.929,
'q' => 0.095, 'r' => 5.987, 's' => 6.327, 't' => 9.056,
'u' => 2.758, 'v' => 0.978, 'w' => 2.360, 'x' => 0.150,
'y' => 1.974, 'z' => 0.074,
];
$score = 0.0;
$letterCount = 0;
$lower = strtolower($text);
for ($i = 0; $i < strlen($lower); $i++) {
$ch = $lower[$i];
if (isset($frequencies[$ch])) {
$score += $frequencies[$ch];
$letterCount++;
}
}
return $letterCount > 0 ? $score / $letterCount : 0.0;
}
/**
* Automatically detect the most likely shift value for ciphertext.
*
* @return array{shift: int, text: string, score: float}
*/
public static function autoDecrypt(string $ciphertext): array
{
$results = self::bruteForce($ciphertext);
$bestShift = 0;
$bestScore = 0.0;
foreach ($results as $shift => $text) {
$score = self::scoreEnglish($text);
if ($score > $bestScore) {
$bestScore = $score;
$bestShift = $shift;
}
}
return [
'shift' => $bestShift,
'text' => $results[$bestShift],
'score' => round($bestScore, 3),
];
}
private function transform(string $text, int $shift): string
{
$result = '';
$len = strlen($text);
for ($i = 0; $i < $len; $i++) {
$ch = $text[$i];
$ord = ord($ch);
if ($ord >= 65 && $ord <= 90) {
$result .= chr(($ord - 65 + $shift) % 26 + 65);
} elseif ($ord >= 97 && $ord <= 122) {
$result .= chr(($ord - 97 + $shift) % 26 + 97);
} else {
$result .= $ch;
}
}
return $result;
}
public function __toString(): string
{
return "CaesarCipher(shift={$this->shift})";
}
}
// Usage examples
$cipher = new CaesarCipher(13);
echo $cipher . "\n";
echo "Encrypted: " . $cipher->encrypt("Attack at dawn!") . "\n";
echo "Decrypted: " . $cipher->decrypt("Nggnpx ng qnja!") . "\n";
// Auto-detect encryption
echo "\n--- Auto Decrypt ---\n";
$result = CaesarCipher::autoDecrypt("Wklv lv d vhfuhw phvvdjh!");
echo "Detected shift: {$result['shift']}\n";
echo "Decrypted text: {$result['text']}\n";
echo "Confidence score: {$result['score']}\n";
La méthode autoDecrypt() est particulièrement utile. Il effectue une attaque par force brute, puis utilise l'analyse de la fréquence des lettres anglaises pour identifier automatiquement la valeur de décalage la plus probable. La fonction de notation compare la fréquence de chaque lettre du texte déchiffré aux fréquences de lettres anglaises connues, et le décryptage avec le score le plus élevé est la réponse correcte la plus probable.
Gestion des caractères UTF-8 et multi-octets
Les fonctions de chaîne PHP standard telles que strlen() et l'indexation entre crochets fonctionnent sur des octets et non sur des caractères. Lors du traitement de texte pouvant contenir des caractères UTF-8 multioctets (lettres accentuées, emoji, caractères CJK), vous devez utiliser l'extension mbstring de PHP. La version suivante gère correctement les entrées UTF-8 en traitant uniquement les lettres ASCII tout en passant en toute sécurité tous les autres caractères.
<?php
function caesarEncryptUtf8(string $text, int $shift): string
{
$shift = (($shift % 26) + 26) % 26;
$result = '';
$length = mb_strlen($text, 'UTF-8');
for ($i = 0; $i < $length; $i++) {
$char = mb_substr($text, $i, 1, 'UTF-8');
$ord = ord($char);
// Only transform single-byte ASCII letters
if (strlen($char) === 1) {
if ($ord >= 65 && $ord <= 90) {
$result .= chr(($ord - 65 + $shift) % 26 + 65);
continue;
} elseif ($ord >= 97 && $ord <= 122) {
$result .= chr(($ord - 97 + $shift) % 26 + 97);
continue;
}
}
// Non-ASCII and non-letter characters pass through unchanged
$result .= $char;
}
return $result;
}
// Examples with international text
echo caesarEncryptUtf8("Hello, World!", 3) . "\n";
// Output: Khoor, Zruog!
echo caesarEncryptUtf8("Café résumé — enjoy!", 5) . "\n";
// Output: Hfké wéxzré — jsotd!
echo caesarEncryptUtf8("Tokyo 東京 is amazing!", 10) . "\n";
// Output: Dyuiy 東京 sc kwkjsxq!
L’idée clé consiste à vérifier strlen($char) === 1 pour déterminer si un caractère est un caractère ASCII à un octet. Les caractères UTF-8 multioctets (y compris les lettres accentuées comme e avec aigu) ont une longueur d'octet supérieure à 1, ils sont donc transmis sans modification. C’est le comportement correct pour un chiffre César classique, qui ne fonctionne que sur les 26 lettres anglaises.
Intégration de formulaires Web
L'une des plus grandes forces de PHP réside dans la façon dont il s'intègre naturellement aux formulaires HTML. L'exemple suivant crée une page Web complète et autonome sur laquelle les utilisateurs peuvent crypter et déchiffrer du texte via une interface de navigateur.
<?php
$result = '';
$inputText = '';
$shift = 3;
$mode = 'encrypt';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$inputText = $_POST['text'] ?? '';
$shift = (int)($_POST['shift'] ?? 3);
$mode = $_POST['mode'] ?? 'encrypt';
// Sanitize input for display (prevent XSS)
$inputText = strip_tags($inputText);
$normalizedShift = (($shift % 26) + 26) % 26;
$effectiveShift = ($mode === 'decrypt')
? 26 - $normalizedShift
: $normalizedShift;
$result = '';
for ($i = 0; $i < strlen($inputText); $i++) {
$ch = $inputText[$i];
$ord = ord($ch);
if ($ord >= 65 && $ord <= 90) {
$result .= chr(($ord - 65 + $effectiveShift) % 26 + 65);
} elseif ($ord >= 97 && $ord <= 122) {
$result .= chr(($ord - 97 + $effectiveShift) % 26 + 97);
} else {
$result .= $ch;
}
}
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Caesar Cipher Tool</title>
<style>
body { font-family: system-ui, sans-serif; max-width: 600px; margin: 2rem auto; padding: 0 1rem; }
label { display: block; margin-top: 1rem; font-weight: bold; }
textarea, input, select, button { width: 100%; padding: 0.5rem; margin-top: 0.25rem; box-sizing: border-box; }
textarea { height: 120px; font-family: monospace; }
button { margin-top: 1rem; background: #2563eb; color: white; border: none; border-radius: 4px; cursor: pointer; font-size: 1rem; }
button:hover { background: #1d4ed8; }
.result { margin-top: 1.5rem; padding: 1rem; background: #f0fdf4; border: 1px solid #86efac; border-radius: 4px; }
.result pre { white-space: pre-wrap; word-wrap: break-word; margin: 0; }
</style>
</head>
<body>
<h1>Caesar Cipher</h1>
<form method="POST">
<label for="text">Enter your text:</label>
<textarea id="text" name="text" required><?= htmlspecialchars($inputText) ?></textarea>
<label for="shift">Shift value (1-25):</label>
<input type="number" id="shift" name="shift" min="1" max="25"
value="<?= htmlspecialchars((string)$shift) ?>">
<label for="mode">Mode:</label>
<select id="mode" name="mode">
<option value="encrypt" <?= $mode === 'encrypt' ? 'selected' : '' ?>>Encrypt</option>
<option value="decrypt" <?= $mode === 'decrypt' ? 'selected' : '' ?>>Decrypt</option>
</select>
<button type="submit">Process</button>
</form>
<?php if ($result !== '' && $_SERVER['REQUEST_METHOD'] === 'POST'): ?>
<div class="result">
<h2><?= $mode === 'encrypt' ? 'Encrypted' : 'Decrypted' ?> Result:</h2>
<pre><?= htmlspecialchars($result) ?></pre>
</div>
<?php endif; ?>
</body>
</html>
Considérations de sécurité dans ce formulaire Web:
htmlspecialchars(): toutes les entrées utilisateur sont échappées avant d'être rendues au format HTML pour empêcher les attaques de scripts intersites (XSS). Ceci est essentiel pour tout formulaire Web qui affiche les entrées de l’utilisateur.strip_tags(): supprime toutes les balises HTML du texte saisi avant le traitement. Il s'agit d'une couche de défense supplémentaire contre XSS.- Validation d'entrée: la valeur de décalage est convertie en
int, ce qui évite toute confusion de type. Les attributs HTMLminetmaxfournissent une validation côté client, mais la validation côté serveur (la normalisation modulo) est ce qui applique réellement la contrainte.
Enregistrez-le sous le nom caesar.php et servez-le avec le serveur intégré de PHP pour des tests rapides:
php -S localhost:8000
# Then open http://localhost:8000/caesar.php in your browser
Point de terminaison de l'API REST
Pour l'accès par programmation, une API JSON est plus appropriée qu'un formulaire HTML. L'implémentation suivante fournit des points de terminaison de chiffrement, de déchiffrement et de force brute qui acceptent les entrées JSON et renvoient des réponses JSON. Il peut être utilisé avec des frameworks comme Laravel ou Slim, mais fonctionne également de manière autonome.
<?php
header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type');
// Handle CORS preflight
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
http_response_code(204);
exit;
}
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
http_response_code(405);
echo json_encode(['error' => 'Method not allowed. Use POST.']);
exit;
}
$input = json_decode(file_get_contents('php://input'), true);
if ($input === null) {
http_response_code(400);
echo json_encode(['error' => 'Invalid JSON input.']);
exit;
}
$action = $input['action'] ?? '';
$text = $input['text'] ?? '';
$shift = (int)($input['shift'] ?? 0);
if (empty($text)) {
http_response_code(400);
echo json_encode(['error' => 'Text field is required.']);
exit;
}
// Limit input length to prevent abuse
if (strlen($text) > 10000) {
http_response_code(400);
echo json_encode(['error' => 'Text exceeds maximum length of 10,000 characters.']);
exit;
}
function transform(string $text, int $shift): string
{
$shift = (($shift % 26) + 26) % 26;
$result = '';
for ($i = 0; $i < strlen($text); $i++) {
$ord = ord($text[$i]);
if ($ord >= 65 && $ord <= 90) {
$result .= chr(($ord - 65 + $shift) % 26 + 65);
} elseif ($ord >= 97 && $ord <= 122) {
$result .= chr(($ord - 97 + $shift) % 26 + 97);
} else {
$result .= $text[$i];
}
}
return $result;
}
$response = match ($action) {
'encrypt' => [
'action' => 'encrypt',
'shift' => (($shift % 26) + 26) % 26,
'input' => $text,
'result' => transform($text, $shift),
],
'decrypt' => [
'action' => 'decrypt',
'shift' => (($shift % 26) + 26) % 26,
'input' => $text,
'result' => transform($text, 26 - (($shift % 26 + 26) % 26)),
],
'bruteforce' => [
'action' => 'bruteforce',
'input' => $text,
'results' => array_map(
fn(int $s) => [
'shift' => $s,
'text' => transform($text, 26 - $s),
],
range(0, 25)
),
],
default => null,
};
if ($response === null) {
http_response_code(400);
echo json_encode([
'error' => "Invalid action '$action'. Use 'encrypt', 'decrypt', or 'bruteforce'.",
]);
exit;
}
echo json_encode($response, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
Utilisation avec curl:
# Encrypt
curl -X POST http://localhost:8000/api.php \
-H "Content-Type: application/json" \
-d '{"action":"encrypt","text":"Hello World","shift":5}'
# Response:
# {
# "action": "encrypt",
# "shift": 5,
# "input": "Hello World",
# "result": "Mjqqt Btwqi"
# }
# Decrypt
curl -X POST http://localhost:8000/api.php \
-H "Content-Type: application/json" \
-d '{"action":"decrypt","text":"Mjqqt Btwqi","shift":5}'
# Brute force
curl -X POST http://localhost:8000/api.php \
-H "Content-Type: application/json" \
-d '{"action":"bruteforce","text":"Khoor Zruog"}'
L'API inclut plusieurs considérations de production:
- En-têtes CORS: autorisez les requêtes d'origine croisée afin que l'API puisse être appelée à partir de JavaScript sur différents domaines.
- Limite de longueur d'entrée: évite les abus en rejetant le texte de plus de 10 000 caractères.
- Validation de méthode: Seules les requêtes POST sont acceptées; d'autres méthodes renvoient un statut 405.
- Validation JSON: une entrée JSON mal formée renvoie une erreur 400 claire.
- Match expression: l'expression
matchde PHP 8.0 fournit un moyen propre et exhaustif d'acheminer entre les actions.
Conseils de performances
Pour la plupart des cas d’utilisation, la fonction de base est suffisamment rapide. PHP peut traiter des millions de caractères par seconde avec de simples opérations sur les chaînes. Toutefois, si vous créez un point de terminaison d'API à fort trafic, envisagez ces optimisations:
Évitez les appels strlen répétés: stockez le résultat de strlen() dans une variable plutôt que de l'appeler à chaque itération de boucle. Bien que PHP mette en cache la longueur de la chaîne en interne, la surcharge d'appel de fonction existe toujours.
Utilisez strtr pour des substitutions simples: la fonction strtr() de PHP peut effectuer une traduction caractère par caractère très efficacement lorsqu'on lui donne une table de traduction:
function caesarFast(string $text, int $shift): string
{
$shift = (($shift % 26) + 26) % 26;
$from = implode('', array_map('chr', [...range(65, 90), ...range(97, 122)]));
$to = '';
foreach ([65, 97] as $base) {
for ($i = 0; $i < 26; $i++) {
$to .= chr(($i + $shift) % 26 + $base);
}
}
return strtr($text, $from, $to);
}
Cette approche crée la table de substitution une seule fois, puis traite la chaîne entière en un seul appel de fonction au niveau C, ce qui est nettement plus rapide qu'une boucle PHP pour les chaînes très longues.
Résumé
La polyvalence de PHP en fait un excellent langage pour les implémentations du chiffrement César qui vont des simples scripts aux applications Web et API. La fonction de base couvre des cas d'utilisation autonomes. La classe POO fournit un composant réutilisable avec détection automatique. La version UTF-8 gère correctement le texte international. Le formulaire Web crée une expérience de navigateur interactive. Et l'API REST permet un accès par programmation depuis n'importe quel client.
Ces implémentations démontrent les atouts de PHP en matière de développement Web tout en enseignant les concepts cryptographiques fondamentaux. Les modèles présentés ici, notamment la validation des entrées, la prévention XSS, la gestion CORS et les API JSON, sont applicables à n'importe quelle application Web PHP, ce qui en fait plus qu'un simple exercice de cryptographie.
Prochaines étapes: essayez nos outils interactifs encodeur du chiffre César et décodeur, ou explorez le chiffre de Vigenere pour une technique de cryptage plus avancée.