Caesar Cipher in PHP - Step by Step Guide

advertisement

About This Tutorial

PHP is an excellent server-side language for implementing encryption algorithms and building secure backend systems. This comprehensive tutorial guides you through implementing the Caesar cipher in PHP, from basic functions to Laravel integration and RESTful API endpoints. Whether you're building educational tools or learning cryptographic concepts in a backend context, this guide covers everything you need. Before diving into the code, review our Beginner's Guide to Caesar Cipher to understand the encryption fundamentals.

Understanding the Basics

The Caesar cipher shifts each letter in the plaintext by a fixed number of positions in the alphabet. In PHP, we'll use the ord() and chr() functions along with modular arithmetic to implement this efficiently for server-side applications and APIs.

Example:

With a shift of 3, "HELLO" becomes "KHOOR"

Basic PHP Implementation

Let's start with a straightforward encryption function that demonstrates the core concept:

<?php
/**
 * Encrypts text using Caesar cipher with given shift value.
 *
 * @param string $text Text to encrypt
 * @param int $shift Number of positions to shift (1-25)
 * @return string Encrypted text
 */
function caesarEncrypt(string $text, int $shift): string
{
    $result = '';
    $textLength = strlen($text);

    for ($i = 0; $i < $textLength; $i++) {
        $char = $text[$i];

        // Check if character is uppercase letter
        if ($char >= 'A' && $char <= 'Z') {
            // Shift within uppercase letters (A-Z)
            $code = ord($char);
            $char = chr((($code - 65 + $shift) % 26) + 65);
        }
        // Check if character is lowercase letter
        elseif ($char >= 'a' && $char <= 'z') {
            // Shift within lowercase letters (a-z)
            $code = ord($char);
            $char = chr((($code - 97 + $shift) % 26) + 97);
        }
        // Keep non-alphabetic characters unchanged

        $result .= $char;
    }

    return $result;
}

// Example usage
$plaintext = "Hello World!";
$shift = 3;
$encrypted = caesarEncrypt($plaintext, $shift);

echo "Original: $plaintext\n";
echo "Encrypted: $encrypted\n";

// Output:
// Original: Hello World!
// Encrypted: Khoor Zruog!

How the PHP Implementation Works

Understanding the key PHP functions used in Caesar cipher:

ord() Function

Returns the ASCII value of a character. For 'A', ord('A') returns 65. This is essential for converting letters to numbers for mathematical operations.

chr() Function

Converts ASCII values back to characters. chr(65) returns 'A'. Used to rebuild the encrypted string after shifting.

Modulo Arithmetic (% 26)

The modulo operator wraps letters around the alphabet. When 'Z' + 1 exceeds the alphabet, it wraps to 'A'. Critical for maintaining alphabetic bounds.

String Functions

str_split(), strlen(), and string concatenation enable efficient text processing. Modern PHP also supports mb_* functions for Unicode.

Modern PHP 8+ Implementation

Using modern PHP features including type declarations, named arguments, and match expressions:

<?php

declare(strict_types=1);

/**
 * Modern PHP 8+ Caesar cipher implementation
 */
function caesarCipher(string $text, int $shift): string
{
    $shift = (($shift % 26) + 26) % 26; // Normalize shift

    return implode('', array_map(
        fn($char) => match(true) {
            ctype_upper($char) => chr(((ord($char) - 65 + $shift) % 26) + 65),
            ctype_lower($char) => chr(((ord($char) - 97 + $shift) % 26) + 97),
            default => $char
        },
        str_split($text)
    ));
}

function caesarDecrypt(string $text, int $shift): string
{
    return caesarCipher($text, -$shift);
}

// Example usage with modern features
$message = "PHP is powerful for backend development!";
$encrypted = caesarCipher($message, 7);
$decrypted = caesarDecrypt($encrypted, 7);

echo "Original: $message\n";
echo "Encrypted: $encrypted\n";
echo "Decrypted: $decrypted\n";

Laravel Integration

Create a Laravel service class for Caesar cipher operations with dependency injection and proper error handling:

<?php

namespace App\Services;

/**
 * Caesar Cipher Service for Laravel applications
 */
class CaesarCipherService
{
    private int $shift;

    public function __construct(int $shift = 3)
    {
        $this->setShift($shift);
    }

    /**
     * Encrypt text using Caesar cipher
     */
    public function encrypt(string $text): string
    {
        return $this->transform($text, $this->shift);
    }

    /**
     * Decrypt text using Caesar cipher
     */
    public function decrypt(string $text): string
    {
        return $this->transform($text, -$this->shift);
    }

    /**
     * Transform text with given shift
     */
    private function transform(string $text, int $shift): string
    {
        $result = '';
        $shift = (($shift % 26) + 26) % 26;

        foreach (str_split($text) as $char) {
            if (ctype_upper($char)) {
                $result .= chr(((ord($char) - 65 + $shift) % 26) + 65);
            } elseif (ctype_lower($char)) {
                $result .= chr(((ord($char) - 97 + $shift) % 26) + 97);
            } else {
                $result .= $char;
            }
        }

        return $result;
    }

    /**
     * Set new shift value
     */
    public function setShift(int $shift): self
    {
        if ($shift < 0 || $shift > 25) {
            throw new \InvalidArgumentException(
                'Shift must be between 0 and 25'
            );
        }

        $this->shift = $shift;
        return $this;
    }

    /**
     * Get current shift value
     */
    public function getShift(): int
    {
        return $this->shift;
    }
}

Building a RESTful API Endpoint

Create a Laravel API controller to expose Caesar cipher functionality via HTTP endpoints:

<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Services\CaesarCipherService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;

class CaesarCipherController extends Controller
{
    public function __construct(
        private CaesarCipherService $cipherService
    ) {}

    /**
     * Encrypt text using Caesar cipher
     *
     * @param Request $request
     * @return JsonResponse
     */
    public function encrypt(Request $request): JsonResponse
    {
        $validator = Validator::make($request->all(), [
            'text' => 'required|string|max:10000',
            'shift' => 'required|integer|min:1|max:25'
        ]);

        if ($validator->fails()) {
            return response()->json([
                'success' => false,
                'errors' => $validator->errors()
            ], 422);
        }

        try {
            $this->cipherService->setShift($request->input('shift'));
            $encrypted = $this->cipherService->encrypt(
                $request->input('text')
            );

            return response()->json([
                'success' => true,
                'data' => [
                    'original' => $request->input('text'),
                    'encrypted' => $encrypted,
                    'shift' => $request->input('shift')
                ]
            ]);
        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'Encryption failed: ' . $e->getMessage()
            ], 500);
        }
    }

    /**
     * Decrypt text using Caesar cipher
     *
     * @param Request $request
     * @return JsonResponse
     */
    public function decrypt(Request $request): JsonResponse
    {
        $validator = Validator::make($request->all(), [
            'text' => 'required|string|max:10000',
            'shift' => 'required|integer|min:1|max:25'
        ]);

        if ($validator->fails()) {
            return response()->json([
                'success' => false,
                'errors' => $validator->errors()
            ], 422);
        }

        try {
            $this->cipherService->setShift($request->input('shift'));
            $decrypted = $this->cipherService->decrypt(
                $request->input('text')
            );

            return response()->json([
                'success' => true,
                'data' => [
                    'encrypted' => $request->input('text'),
                    'decrypted' => $decrypted,
                    'shift' => $request->input('shift')
                ]
            ]);
        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'Decryption failed: ' . $e->getMessage()
            ], 500);
        }
    }
}

// routes/api.php
// Route::post('/caesar/encrypt', [CaesarCipherController::class, 'encrypt']);
// Route::post('/caesar/decrypt', [CaesarCipherController::class, 'decrypt']);

Advanced Class-Based Implementation

For production applications, a comprehensive class-based approach provides better organization, validation, and reusability:

<?php

declare(strict_types=1);

/**
 * Comprehensive Caesar Cipher implementation with advanced features
 */
class CaesarCipher
{
    private int $shift;
    private string $alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';

    public function __construct(int $shift = 3)
    {
        $this->setShift($shift);
    }

    /**
     * Encrypt text
     */
    public function encrypt(string $text): string
    {
        return $this->transform($text, $this->shift);
    }

    /**
     * Decrypt text
     */
    public function decrypt(string $text): string
    {
        return $this->transform($text, -$this->shift);
    }

    /**
     * Transform text with given shift
     */
    private function transform(string $text, int $shift): string
    {
        $result = '';
        $shift = (($shift % 26) + 26) % 26;

        foreach (str_split($text) as $char) {
            if (ctype_upper($char)) {
                $result .= chr(((ord($char) - 65 + $shift) % 26) + 65);
            } elseif (ctype_lower($char)) {
                $result .= chr(((ord($char) - 97 + $shift) % 26) + 97);
            } else {
                $result .= $char;
            }
        }

        return $result;
    }

    /**
     * Brute force attack - try all possible shifts
     *
     * @param string $encryptedText Text to decrypt
     * @return array All 26 possible decryptions
     */
    public function bruteForce(string $encryptedText): array
    {
        $results = [];

        for ($shift = 0; $shift < 26; $shift++) {
            $results[] = [
                'shift' => $shift,
                'text' => $this->transform($encryptedText, -$shift)
            ];
        }

        return $results;
    }

    /**
     * Encrypt/decrypt file contents
     */
    public function processFile(
        string $inputFile,
        string $outputFile,
        bool $encrypt = true
    ): bool {
        if (!file_exists($inputFile)) {
            throw new \RuntimeException("Input file not found");
        }

        $content = file_get_contents($inputFile);
        $processed = $encrypt
            ? $this->encrypt($content)
            : $this->decrypt($content);

        return file_put_contents($outputFile, $processed) !== false;
    }

    /**
     * Set shift value with validation
     */
    public function setShift(int $shift): self
    {
        $this->shift = (($shift % 26) + 26) % 26;
        return $this;
    }

    /**
     * Get current shift value
     */
    public function getShift(): int
    {
        return $this->shift;
    }

    /**
     * ROT13 - Caesar cipher with shift of 13
     */
    public static function rot13(string $text): string
    {
        return (new self(13))->encrypt($text);
    }

    /**
     * Check if text is likely encrypted with Caesar cipher
     */
    public function isLikelyEncrypted(string $text): bool
    {
        // Simple heuristic: check letter frequency distribution
        $letterCount = preg_match_all('/[a-zA-Z]/', $text);
        if ($letterCount === 0) {
            return false;
        }

        // Count common English letters (E, T, A, O, I, N)
        $commonLetters = preg_match_all('/[etaoinETAOIN]/', $text);
        $ratio = $commonLetters / $letterCount;

        // If ratio is very low, text might be encrypted
        return $ratio < 0.3;
    }
}

// Example usage
$cipher = new CaesarCipher(5);

// Encryption
$message = "PHP is great for backend development!";
$encrypted = $cipher->encrypt($message);
echo "Original: $message\n";
echo "Encrypted: $encrypted\n";

// Decryption
$decrypted = $cipher->decrypt($encrypted);
echo "Decrypted: $decrypted\n";

// Brute force attack
$mysteryText = "Mjqqt Btwqi";
echo "\nBrute force results:\n";
foreach (array_slice($cipher->bruteForce($mysteryText), 0, 5) as $result) {
    echo "Shift {$result['shift']}: {$result['text']}\n";
}

// ROT13
$rot13Text = CaesarCipher::rot13("Hello World");
echo "\nROT13: $rot13Text\n";

PHP Best Practices

Our implementation follows modern PHP standards and best practices:

  • Type Declarations: Use strict typing with declare(strict_types=1) for better code safety
  • PHPDoc Comments: Clear documentation explaining parameters, return types, and exceptions
  • PSR-12 Coding Standard: Follow PHP-FIG standards for consistent code style
  • Error Handling: Use exceptions for error conditions rather than return codes
  • Input Validation: Always validate and sanitize user input, especially in web contexts
  • Dependency Injection: Use Laravel's service container for better testability

Common Mistakes to Avoid

Watch out for these common errors when implementing Caesar cipher in PHP:

  • Character Encoding Issues: Always use UTF-8 encoding and consider mb_* functions for international characters
  • Forgetting Modulo: Without % 26, character codes can exceed valid ASCII range
  • Not Normalizing Shift: Handle negative shifts and values > 26 correctly
  • Case Sensitivity: Handle uppercase and lowercase letters with different base values (65 for A, 97 for a)
  • Security Misconceptions: Never use Caesar cipher for real security - it's educational only

Command-Line Interface (CLI) Usage

PHP scripts can be executed from the command line for batch processing and automation:

<?php
// caesar-cli.php - Command-line Caesar cipher tool

declare(strict_types=1);

require_once 'CaesarCipher.php';

function displayHelp(): void
{
    echo <<<HELP
    Caesar Cipher CLI Tool

    Usage:
        php caesar-cli.php [operation] [text] [shift]

    Operations:
        encrypt    Encrypt the provided text
        decrypt    Decrypt the provided text
        brute      Try all shifts (brute force attack)

    Examples:
        php caesar-cli.php encrypt "Hello World" 3
        php caesar-cli.php decrypt "Khoor Zruog" 3
        php caesar-cli.php brute "Mjqqt Btwqi"

    HELP;
}

// Parse command-line arguments
if ($argc < 2) {
    displayHelp();
    exit(1);
}

$operation = $argv[1] ?? '';
$text = $argv[2] ?? '';
$shift = isset($argv[3]) ? (int)$argv[3] : 3;

try {
    $cipher = new CaesarCipher($shift);

    switch ($operation) {
        case 'encrypt':
            if (empty($text)) {
                throw new InvalidArgumentException('Text is required');
            }
            $result = $cipher->encrypt($text);
            echo "Encrypted: $result\n";
            break;

        case 'decrypt':
            if (empty($text)) {
                throw new InvalidArgumentException('Text is required');
            }
            $result = $cipher->decrypt($text);
            echo "Decrypted: $result\n";
            break;

        case 'brute':
            if (empty($text)) {
                throw new InvalidArgumentException('Text is required');
            }
            echo "Brute force results:\n";
            foreach ($cipher->bruteForce($text) as $result) {
                printf(
                    "Shift %2d: %s\n",
                    $result['shift'],
                    $result['text']
                );
            }
            break;

        default:
            displayHelp();
            exit(1);
    }
} catch (Exception $e) {
    echo "Error: " . $e->getMessage() . "\n";
    exit(1);
}

Practical Use Cases

PHP Caesar cipher implementations are perfect for:

Building educational web applications and APIs
Creating backend services for cipher tools
Implementing puzzle game mechanics
Learning cryptography fundamentals in PHP
Teaching secure coding practices
Processing batch encryption tasks via CLI

Performance Considerations

The implementation has O(n) time complexity where n is the text length. For optimal performance in PHP:

  • Use str_split() and array functions instead of character-by-character iteration
  • Consider caching encrypted alphabets for bulk operations
  • Use mb_string extension for UTF-8 text handling
  • For large files, process in chunks to manage memory usage
  • Enable OPcache in production for bytecode caching
  • Profile with Xdebug or Blackfire for optimization opportunities

Testing Your Implementation

Comprehensive PHPUnit test cases to verify your Caesar cipher works correctly:

<?php

namespace Tests\Unit;

use PHPUnit\Framework\TestCase;
use App\Services\CaesarCipherService;

class CaesarCipherTest extends TestCase
{
    private CaesarCipherService $cipher;

    protected function setUp(): void
    {
        $this->cipher = new CaesarCipherService(3);
    }

    /** @test */
    public function it_encrypts_basic_text_correctly()
    {
        $this->assertEquals('DEF', $this->cipher->encrypt('ABC'));
    }

    /** @test */
    public function it_handles_wrap_around_from_z_to_a()
    {
        $this->assertEquals('ABC', $this->cipher->encrypt('XYZ'));
    }

    /** @test */
    public function it_preserves_case()
    {
        $this->assertEquals('Khoor', $this->cipher->encrypt('Hello'));
    }

    /** @test */
    public function it_keeps_non_alphabetic_characters_unchanged()
    {
        $encrypted = $this->cipher->encrypt('Hello, World!');
        $this->assertEquals('Khoor, Zruog!', $encrypted);
    }

    /** @test */
    public function encryption_and_decryption_are_reversible()
    {
        $original = 'PHP Programming';
        $encrypted = $this->cipher->encrypt($original);
        $decrypted = $this->cipher->decrypt($encrypted);

        $this->assertEquals($original, $decrypted);
    }

    /** @test */
    public function it_handles_shift_of_zero()
    {
        $this->cipher->setShift(0);
        $this->assertEquals('Test', $this->cipher->encrypt('Test'));
    }

    /** @test */
    public function it_throws_exception_for_invalid_shift()
    {
        $this->expectException(\InvalidArgumentException::class);
        $this->cipher->setShift(26);
    }

    /** @test */
    public function it_handles_empty_string()
    {
        $this->assertEquals('', $this->cipher->encrypt(''));
    }

    /** @test */
    public function it_handles_long_text()
    {
        $longText = str_repeat('ABC ', 1000);
        $encrypted = $this->cipher->encrypt($longText);
        $decrypted = $this->cipher->decrypt($encrypted);

        $this->assertEquals($longText, $decrypted);
    }
}

Enhancement Ideas

Extend this implementation with additional features:

Add support for custom alphabets (non-Latin characters)
Implement automatic language detection
Create Laravel Artisan commands for CLI operations
Build RESTful API with rate limiting
Add database storage for encryption history
Implement frequency analysis visualization
Create Laravel Blade components for UI
Add queue support for batch processing

Related Resources

Continue your cryptography and PHP learning journey:

Summary

You've learned how to implement the Caesar cipher in PHP from basic functions to Laravel integration and RESTful APIs. We covered classic implementations, modern PHP 8+ syntax, service classes, API endpoints, and command-line tools. This knowledge forms the foundation for building more sophisticated server-side encryption tools and understanding backend cryptography.

Practice by creating your own Laravel service, build a complete API with authentication, or experiment with more complex encryption algorithms. While Caesar cipher isn't suitable for securing sensitive data, it provides an excellent introduction to cryptographic concepts and PHP string manipulation for backend developers.