Ejecutar el código
Guarda el código como caesar.php y ejecútalo en la terminal. No necesitas un servidor web para esto:
php caesar.phpSi el cifrado en sí es nuevo para ti, la guía lo explica sin código.
Cómo funciona el código
str_split corta el texto en bytes sueltos y ctype_alpha reconoce las letras de la A a la Z. ord() da el número de una letra: 72 para la H y 104 para la h. Al restar 65 o 97 obtienes su posición en el alfabeto, de 0 a 25.
Después de sumar el desplazamiento, el módulo da la vuelta al alfabeto: con un desplazamiento de 3, la Z cae en la C. chr() devuelve el número a su forma de letra.
Espacios, signos y cifras pasan por la rama else sin cambios. Lo mismo ocurre con la ñ: en UTF-8 son dos bytes, y ninguno es una letra para ctype_alpha.
Descifrar en PHP
No hace falta una segunda función. Descifrar es desplazar en sentido contrario, así que basta con pasar un número negativo:
echo caesar('¡Krod, pxqgr!', -3), "\n";// ¡Hola, mundo!De ahí el + 26 adicional de la fórmula. En PHP, % conserva el signo del número de la izquierda: -3 % 26 da -3, y esa posición no existe. Si sumas 26 y vuelves a aplicar el módulo sale 23, y la A vuelve a la X. PHP incluye además str_rot13(), aunque solo conoce el desplazamiento de 13.
Un formulario web
Coloca este código debajo de la función, guarda el archivo y arranca el servidor integrado con php -S localhost:8000 caesar.php. Después abre esa dirección en el navegador.
<?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>Cifrar</button></form><p><?= htmlspecialchars($result) ?></p>Las dos salidas pasan por htmlspecialchars, porque el texto viene del visitante. Sin eso, cualquiera podría meter un script en tu página.
Un script de línea de comandos
Sustituye las dos últimas líneas de caesar.php por este código para recibir el desplazamiento y el texto como argumentos:
if ($argc !== 3) { exit("Uso: php caesar.php <desplazamiento> <texto>\n");} echo caesar($argv[2], (int) $argv[1]), "\n"; // php caesar.php 3 "Hola"// KrodUn endpoint JSON en Laravel
En un proyecto Laravel, pon la función en un helper o en una clase propia y añade esta ruta a routes/api.php. Laravel valida los datos y devuelve el array como JSON.
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'])];});Ante datos no válidos, el framework responde con un error por sí solo, de modo que la función solo recibe valores limpios. Si solo necesitas un endpoint que funcione, nuestra API REST gratuita ya está en marcha.
Romper el cifrado por fuerza bruta
Con 26 letras solo hay 25 desplazamientos posibles, y un bucle corto basta para leer el mensaje sin la clave. Busca en la salida la línea que tenga sentido:
function crack(string $text): void{ for ($shift = 1; $shift < 26; $shift++) { echo $shift, ' ', caesar($text, -$shift), "\n"; }} crack('¡Krod, pxqgr!');// 1 ¡Jqnc, owpfq!// 2 ¡Ipmb, nvoep!// 3 ¡Hola, mundo!// ...El artículo sobre el ataque de fuerza bruta entra en más detalle, y el descifrador en línea hace lo mismo en tu navegador.
Cifrado César con la ñ
Para desplazar también la ñ, guarda el alfabeto en una cadena y usa las funciones mb_, que cuentan caracteres y no bytes. Son las mismas 27 letras que usa nuestra herramienta:
const ALPHABET = 'abcdefghijklmnñopqrstuvwxyz'; 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('El niño', 3), "\n";// Hñ plqrAhora la vuelta depende de mb_strlen, así que no tienes que escribir el 27 en ningún sitio. Puedes comparar el resultado en la herramienta de cifrado César con el alfabeto español.
Cifrar un archivo de texto
Lee el archivo entero con file_get_contents y escribe el resultado con file_put_contents. La primera devuelve false si falla, así que conviene comprobarlo.
$text = file_get_contents('message.txt'); if ($text === false) { exit("No se puede leer message.txt\n");} file_put_contents('encrypted.txt', caesar($text, 3));El mismo cifrado como clase
Una clase resulta útil si usas la misma clave muchas veces. Una clase readonly, disponible desde PHP 8.2, evita que el desplazamiento cambie después de fijarlo:
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('¡Hola, mundo!'), "\n";// ¡Mtqf, rzsit!Probar el código
La configuración de producción suele desactivar assert, así que actívalo al probar: php -d zend.assertions=1 -d assert.exception=1 caesar.php. Si todo va bien, imprime OK. En un proyecto real, las mismas comprobaciones encajan en PHPUnit o Pest.
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";Errores frecuentes
El más común es % con un desplazamiento negativo, como vimos antes. Le sigue mostrar el resultado sin htmlspecialchars. Además, strlen y $text[0] trabajan con bytes, de modo que en UTF-8 parten la ñ por la mitad. Para caracteres completos, usa las funciones mb_.
Preguntas frecuentes
¿Qué versión de PHP necesito?
La función principal funciona en PHP 7 y posteriores, y la clase readonly requiere PHP 8.2. Hemos ejecutado el código de esta página en PHP 8.4.
¿Sirve para proteger datos reales?
No. El bucle de arriba lo rompe en segundos. Úsalo para aprender y para pasatiempos. Para datos reales, PHP tiene cifrado moderno en la extensión sodium, y las contraseñas se tratan con password_hash().
¿Cómo compruebo que mi resultado es correcto?
Introduce el mismo texto y desplazamiento en nuestra herramienta de cifrado César y compara. También puedes llamar a la API REST gratuita desde tus pruebas.