Szyfr Cezara w PHP - Przewodnik Krok po Kroku

reklama

O Tym Tutorialu

PHP jest doskonałym językiem serwerowym do implementacji algorytmów szyfrowania i budowania bezpiecznych systemów backendowych. Ten kompleksowy tutorial przeprowadzi Cię przez implementację szyfru Cezara w PHP, od podstawowych funkcji po integrację z Laravel i endpointy RESTful API. Niezależnie od tego, czy tworzysz narzędzia edukacyjne, czy uczysz się koncepcji kryptograficznych w kontekście backendu, ten przewodnik pokrywa wszystko, czego potrzebujesz. Przed zanurzeniem się w kod, zapoznaj się z naszym Przewodnikiem dla Początkujących po Szyfrze Cezara, aby zrozumieć podstawy szyfrowania.

Zrozumienie Podstaw

Szyfr Cezara przesuwa każdą literę w tekście jawnym o stałą liczbę pozycji w alfabecie. W PHP użyjemy funkcji ord() i chr() wraz z arytmetyką modularną, aby zaimplementować to efektywnie dla aplikacji serwerowych i API.

Przykład:

Przy przesunięciu o 3, "HELLO" staje się "KHOOR"

Podstawowa Implementacja PHP

Zacznijmy od prostej funkcji szyfrującej, która demonstruje główną koncepcję:

<?php
/**
 * Szyfruje tekst używając szyfru Cezara z podaną wartością przesunięcia.
 *
 * @param string $text Tekst do zaszyfrowania
 * @param int $shift Liczba pozycji do przesunięcia (1-25)
 * @return string Zaszyfrowany tekst
 */
function caesarEncrypt(string $text, int $shift): string
{
    $result = '';
    $textLength = strlen($text);

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

        // Sprawdź czy znak jest wielką literą
        if ($char >= 'A' && $char <= 'Z') {
            // Przesuń w obrębie wielkich liter (A-Z)
            $code = ord($char);
            $char = chr((($code - 65 + $shift) % 26) + 65);
        }
        // Sprawdź czy znak jest małą literą
        elseif ($char >= 'a' && $char <= 'z') {
            // Przesuń w obrębie małych liter (a-z)
            $code = ord($char);
            $char = chr((($code - 97 + $shift) % 26) + 97);
        }
        // Zachowaj znaki niealfabetyczne bez zmian

        $result .= $char;
    }

    return $result;
}

// Przykład użycia
$plaintext = "Hello World!";
$shift = 3;
$encrypted = caesarEncrypt($plaintext, $shift);

echo "Oryginalny: $plaintext\n";
echo "Zaszyfrowany: $encrypted\n";

// Wyjście:
// Oryginalny: Hello World!
// Zaszyfrowany: Khoor Zruog!

Jak Działa Implementacja PHP

Zrozumienie kluczowych funkcji PHP używanych w szyfrze Cezara:

Funkcja ord()

Zwraca wartość ASCII znaku. Dla 'A', ord('A') zwraca 65. Jest to niezbędne do konwersji liter na liczby dla operacji matematycznych.

Funkcja chr()

Konwertuje wartości ASCII z powrotem na znaki. chr(65) zwraca 'A'. Używana do odbudowania zaszyfrowanego ciągu po przesunięciu.

Arytmetyka Modulo (% 26)

Operator modulo owija litery wokół alfabetu. Gdy 'Z' + 1 przekracza alfabet, wraca do 'A'. Kluczowe dla zachowania granic alfabetycznych.

Funkcje Stringowe

str_split(), strlen() i konkatenacja stringów umożliwiają efektywne przetwarzanie tekstu. Nowoczesne PHP wspiera również funkcje mb_* dla Unicode.

Nowoczesna Implementacja PHP 8+

Wykorzystanie nowoczesnych funkcji PHP, w tym deklaracji typów, nazwanych argumentów i wyrażeń match:

<?php

declare(strict_types=1);

/**
 * Nowoczesna implementacja szyfru Cezara w PHP 8+
 */
function caesarCipher(string $text, int $shift): string
{
    $shift = (($shift % 26) + 26) % 26; // Normalizacja przesunięcia

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

// Przykład użycia z nowoczesnymi funkcjami
$message = "PHP jest potężny w rozwoju backendu!";
$encrypted = caesarCipher($message, 7);
$decrypted = caesarDecrypt($encrypted, 7);

echo "Oryginalny: $message\n";
echo "Zaszyfrowany: $encrypted\n";
echo "Odszyfrowany: $decrypted\n";

Integracja z Laravel

Stwórz klasę serwisu Laravel dla operacji szyfru Cezara z dependency injection i odpowiednią obsługą błędów:

<?php

namespace App\Services;

/**
 * Serwis Szyfru Cezara dla aplikacji Laravel
 */
class CaesarCipherService
{
    private int $shift;

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

    /**
     * Szyfruje tekst używając szyfru Cezara
     */
    public function encrypt(string $text): string
    {
        return $this->transform($text, $this->shift);
    }

    /**
     * Deszyfruje tekst używając szyfru Cezara
     */
    public function decrypt(string $text): string
    {
        return $this->transform($text, -$this->shift);
    }

    /**
     * Przekształca tekst z podanym przesunięciem
     */
    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;
    }

    /**
     * Ustawia nową wartość przesunięcia
     */
    public function setShift(int $shift): self
    {
        if ($shift < 0 || $shift > 25) {
            throw new \InvalidArgumentException(
                'Przesunięcie musi być między 0 a 25'
            );
        }

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

    /**
     * Pobiera aktualną wartość przesunięcia
     */
    public function getShift(): int
    {
        return $this->shift;
    }
}

Budowanie Endpointu RESTful API

Utwórz kontroler API Laravel, aby udostępnić funkcjonalność szyfru Cezara przez endpointy HTTP:

<?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
    ) {}

    /**
     * Szyfruje tekst używając szyfru Cezara
     *
     * @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' => 'Szyfrowanie nie powiodło się: ' . $e->getMessage()
            ], 500);
        }
    }

    /**
     * Deszyfruje tekst używając szyfru Cezara
     *
     * @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' => 'Deszyfrowanie nie powiodło się: ' . $e->getMessage()
            ], 500);
        }
    }
}

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

Zaawansowana Implementacja Oparta na Klasach

Dla aplikacji produkcyjnych kompleksowe podejście oparte na klasach zapewnia lepszą organizację, walidację i możliwość wielokrotnego użycia:

<?php

declare(strict_types=1);

/**
 * Kompleksowa implementacja Szyfru Cezara z zaawansowanymi funkcjami
 */
class CaesarCipher
{
    private int $shift;
    private string $alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';

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

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

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

    /**
     * Przekształca tekst z podanym przesunięciem
     */
    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;
    }

    /**
     * Atak brute force - wypróbuj wszystkie możliwe przesunięcia
     *
     * @param string $encryptedText Tekst do odszyfrowania
     * @return array Wszystkie 26 możliwych odszyfrowań
     */
    public function bruteForce(string $encryptedText): array
    {
        $results = [];

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

        return $results;
    }

    /**
     * Szyfruje/deszyfruje zawartość pliku
     */
    public function processFile(
        string $inputFile,
        string $outputFile,
        bool $encrypt = true
    ): bool {
        if (!file_exists($inputFile)) {
            throw new \RuntimeException("Plik wejściowy nie został znaleziony");
        }

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

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

    /**
     * Ustawia wartość przesunięcia z walidacją
     */
    public function setShift(int $shift): self
    {
        $this->shift = (($shift % 26) + 26) % 26;
        return $this;
    }

    /**
     * Pobiera aktualną wartość przesunięcia
     */
    public function getShift(): int
    {
        return $this->shift;
    }

    /**
     * ROT13 - Szyfr Cezara z przesunięciem 13
     */
    public static function rot13(string $text): string
    {
        return (new self(13))->encrypt($text);
    }

    /**
     * Sprawdza czy tekst jest prawdopodobnie zaszyfrowany szyfrem Cezara
     */
    public function isLikelyEncrypted(string $text): bool
    {
        // Prosta heurystyka: sprawdź rozkład częstotliwości liter
        $letterCount = preg_match_all('/[a-zA-Z]/', $text);
        if ($letterCount === 0) {
            return false;
        }

        // Policz częste polskie litery (A, E, I, O, Z, N)
        $commonLetters = preg_match_all('/[aeionzAEIONZ]/', $text);
        $ratio = $commonLetters / $letterCount;

        // Jeśli współczynnik jest bardzo niski, tekst może być zaszyfrowany
        return $ratio < 0.3;
    }
}

// Przykład użycia
$cipher = new CaesarCipher(5);

// Szyfrowanie
$message = "PHP jest świetny do rozwoju backendu!";
$encrypted = $cipher->encrypt($message);
echo "Oryginalny: $message\n";
echo "Zaszyfrowany: $encrypted\n";

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

// Atak brute force
$mysteryText = "Mjqqt Btwqi";
echo "\nWyniki brute force:\n";
foreach (array_slice($cipher->bruteForce($mysteryText), 0, 5) as $result) {
    echo "Przesunięcie {$result['shift']}: {$result['text']}\n";
}

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

Najlepsze Praktyki PHP

Nasza implementacja przestrzega nowoczesnych standardów i najlepszych praktyk PHP:

  • Deklaracje Typów: Używaj ścisłego typowania z declare(strict_types=1) dla większego bezpieczeństwa kodu
  • Komentarze PHPDoc: Jasna dokumentacja wyjaśniająca parametry, typy zwracane i wyjątki
  • Standard Kodowania PSR-12: Przestrzegaj standardów PHP-FIG dla spójnego stylu kodu
  • Obsługa Błędów: Używaj wyjątków dla warunków błędu zamiast kodów zwrotnych
  • Walidacja Danych Wejściowych: Zawsze waliduj i oczyszczaj dane wejściowe użytkownika, szczególnie w kontekście webowym
  • Dependency Injection: Używaj kontenera serwisów Laravel dla lepszej testowalności

Częste Błędy do Uniknięcia

Uważaj na te częste błędy podczas implementacji szyfru Cezara w PHP:

  • Problemy z Kodowaniem Znaków: Zawsze używaj kodowania UTF-8 i rozważ funkcje mb_* dla znaków międzynarodowych
  • Zapomnienie o Modulo: Bez % 26, kody znaków mogą przekroczyć poprawny zakres ASCII
  • Brak Normalizacji Przesunięcia: Obsługuj prawidłowo ujemne przesunięcia i wartości > 26
  • Wielkość Liter: Obsługuj wielkie i małe litery z różnymi wartościami bazowymi (65 dla A, 97 dla a)
  • Błędne Wyobrażenia o Bezpieczeństwie: Nigdy nie używaj szyfru Cezara do prawdziwego zabezpieczenia - jest tylko edukacyjny

Interfejs Wiersza Poleceń (CLI)

Skrypty PHP można uruchamiać z wiersza poleceń do przetwarzania wsadowego i automatyzacji:

<?php
// caesar-cli.php - Narzędzie wiersza poleceń dla szyfru Cezara

declare(strict_types=1);

require_once 'CaesarCipher.php';

function displayHelp(): void
{
    echo <<<HELP
    Narzędzie CLI Szyfru Cezara

    Użycie:
        php caesar-cli.php [operacja] [tekst] [przesunięcie]

    Operacje:
        encrypt    Szyfruje podany tekst
        decrypt    Deszyfruje podany tekst
        brute      Wypróbuj wszystkie przesunięcia (atak brute force)

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

    HELP;
}

// Przetwórz argumenty wiersza poleceń
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('Tekst jest wymagany');
            }
            $result = $cipher->encrypt($text);
            echo "Zaszyfrowany: $result\n";
            break;

        case 'decrypt':
            if (empty($text)) {
                throw new InvalidArgumentException('Tekst jest wymagany');
            }
            $result = $cipher->decrypt($text);
            echo "Odszyfrowany: $result\n";
            break;

        case 'brute':
            if (empty($text)) {
                throw new InvalidArgumentException('Tekst jest wymagany');
            }
            echo "Wyniki brute force:\n";
            foreach ($cipher->bruteForce($text) as $result) {
                printf(
                    "Przesunięcie %2d: %s\n",
                    $result['shift'],
                    $result['text']
                );
            }
            break;

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

Praktyczne Przypadki Użycia

Implementacje szyfru Cezara w PHP są idealne do:

Budowania edukacyjnych aplikacji webowych i API
Tworzenia usług backendowych dla narzędzi szyfrujących
Implementacji mechanik gier logicznych
Nauki podstaw kryptografii w PHP
Nauczania bezpiecznych praktyk kodowania
Przetwarzania wsadowego szyfrowania przez CLI

Rozważania dotyczące Wydajności

Implementacja ma złożoność czasową O(n), gdzie n to długość tekstu. Dla optymalnej wydajności w PHP:

  • Używaj str_split() i funkcji tablicowych zamiast iteracji znak po znaku
  • Rozważ cache'owanie zaszyfrowanych alfabetów dla operacji masowych
  • Używaj rozszerzenia mb_string do obsługi tekstu UTF-8
  • Dla dużych plików, przetwarzaj w kawałkach aby zarządzać użyciem pamięci
  • Włącz OPcache w produkcji dla cache'owania bytecode'u
  • Profiluj z Xdebug lub Blackfire dla możliwości optymalizacji

Testowanie Implementacji

Kompleksowe testy PHPUnit aby zweryfikować, że Twój szyfr Cezara działa poprawnie:

<?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 = 'Programowanie PHP';
        $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);
    }
}

Pomysły na Rozszerzenia

Rozszerz tę implementację o dodatkowe funkcje:

Dodaj obsługę niestandardowych alfabetów (znaki nielacińskie)
Zaimplementuj automatyczne wykrywanie języka
Stwórz komendy Laravel Artisan dla operacji CLI
Zbuduj RESTful API z limitowaniem częstotliwości
Dodaj przechowywanie w bazie danych historii szyfrowania
Zaimplementuj wizualizację analizy częstotliwości
Stwórz komponenty Laravel Blade dla UI
Dodaj obsługę kolejek dla przetwarzania wsadowego

Powiązane Zasoby

Kontynuuj swoją naukę kryptografii i PHP:

Podsumowanie

Nauczyłeś się implementować szyfr Cezara w PHP od podstawowych funkcji po integrację z Laravel i RESTful API. Omówiliśmy klasyczne implementacje, nowoczesną składnię PHP 8+, klasy serwisów, endpointy API i narzędzia wiersza poleceń. Ta wiedza stanowi podstawę do budowania bardziej zaawansowanych narzędzi szyfrujących po stronie serwera i zrozumienia kryptografii backendowej.

Ćwicz tworząc własny serwis Laravel, zbuduj kompletne API z autentykacją lub eksperymentuj z bardziej złożonymi algorytmami szyfrowania. Choć szyfr Cezara nie nadaje się do zabezpieczania wrażliwych danych, stanowi doskonałe wprowadzenie do koncepcji kryptograficznych i manipulacji stringów w PHP dla programistów backendowych.