首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 高安全驗證碼生成類別:TrueType 字體、隨機扭曲、干擾元素完整實作

     編輯:PHP 相關知識

前言:高安全驗證碼的核心要素

現代驗證碼需同時滿足「人類易讀」與「機器難識」兩大目標。本文提供的高安全驗證碼類別採用 TrueType 字體渲染,結合字符隨機旋轉、基線抖動、多層干擾元素 (噪點、干擾字符)、隨機背景色等技術,大幅提升 OCR 識別難度,適用於登入、註冊、支付確認等高安全場景。

完整類別實作 (Captcha 類別)

<?php
/**
 * 高安全驗證碼生成類別
 * 需求: PHP GD2 擴充套件、FreeType 支援、.ttf 字體檔
 * 特色: TrueType 字體、字符隨機旋轉/位移、多層干擾、Session 儲存
 */
class HighSecurityCaptcha {
    // --- 可配置屬性 ---
    private $fontFile;        // 字體檔絕對路徑
    private $imgWidth = 130;  // 圖片寬度
    private $imgHeight = 40;  // 圖片高度
    private $fontSize = 18;   // 字體大小
    private $angleRange = 25; // 旋轉角度範圍 (±度)
    private $codeLength = 4;  // 驗證碼長度
    private $charset = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789'; // 字符集 (排除易混淆)
    private $sessionKey = 'hs_captcha_code'; // Session 儲存鍵名
    private $noiseChars = 20; // 干擾字符數量
    private $noisePoints = 100; // 噪點數量
    private $bgColorRange = [200, 255]; // 背景色範圍 (淺色系)
    private $textColorRange = [0, 120];  // 文字色範圍 (深色系)

    // --- 建構子 ---
    public function __construct(array $config = []) {
        foreach ($config as $key => $value) {
            if (property_exists($this, $key)) {
                $this->$key = $value;
            }
        }
        // 預設字體路徑檢查
        if (empty($this->fontFile)) {
            // 嘗試常見路徑
            $defaultFonts = [
                __DIR__ . '/fonts/DejaVuSans.ttf',
                '/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf', // Linux
                'C:/Windows/Fonts/arial.ttf', // Windows
            ];
            foreach ($defaultFonts as $font) {
                if (is_file($font)) {
                    $this->fontFile = $font;
                    break;
                }
            }
        }
        if (empty($this->fontFile) || !is_file($this->fontFile)) {
            throw new Exception('找不到 TrueType 字體檔,請設定 fontFile 參數');
        }
    }

    // --- 核心生成方法 ---
    public function generate(): string {
        // 1. 啟動 Session (若未啟動)
        if (session_status() === PHP_SESSION_NONE) {
            session_start();
        }

        // 2. 發送防快取標頭
        $this->sendHeaders();

        // 3. 生成隨機驗證碼
        $code = $this->generateCode();
        $_SESSION[$this->sessionKey] = strtolower($code); // 統一小寫驗證

        // 4. 建立真彩色畫布
        $image = imagecreatetruecolor($this->imgWidth, $this->imgHeight);

        // 5. 隨機背景色 (淺色系)
        $bgColor = $this->allocateRandomColor($image, $this->bgColorRange);
        imagefilledrectangle($image, 0, 0, $this->imgWidth - 1, $this->imgHeight - 1, $bgColor);

        // 6. 繪製干擾字符 (背景層)
        $this->drawNoiseChars($image);

        // 7. 繪製噪點
        $this->drawNoisePoints($image);

        // 8. 繪製驗證碼字符 (前景層)
        $this->drawCodeChars($image, $code);

        // 9. 輸出並銷毀
        imagepng($image);
        imagedestroy($image);

        return $code;
    }

    // --- 驗證方法 ---
    public static function verify(string $input, string $sessionKey = 'hs_captcha_code'): bool {
        if (session_status() === PHP_SESSION_NONE) session_start();
        $stored = $_SESSION[$sessionKey] ?? '';
        $valid = (strtolower(trim($input)) === $stored) && !empty($input);
        if ($valid) {
            unset($_SESSION[$sessionKey]); // 一次性使用
        }
        return $valid;
    }

    // --- 私有輔助方法 ---

    private function sendHeaders(): void {
        header('Content-Type: image/png');
        header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
        header('Cache-Control: post-check=0, pre-check=0', false);
        header('Pragma: no-cache');
        header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
    }

    private function generateCode(): string {
        $code = '';
        $len = strlen($this->charset) - 1;
        for ($i = 0; $i < $this->codeLength; $i++) {
            $code .= $this->charset[random_int(0, $len)];
        }
        return $code;
    }

    private function allocateRandomColor($image, array $range): int {
        return imagecolorallocate(
            $image,
            random_int($range[0], $range[1]),
            random_int($range[0], $range[1]),
            random_int($range[0], $range[1])
        );
    }

    private function drawNoiseChars($image): void {
        for ($i = 0; $i < $this->noiseChars; $i++) {
            $color = $this->allocateRandomColor($image, [150, 220]); // 中間色調
            $char = $this->charset[random_int(0, strlen($this->charset) - 1)];
            $x = random_int(-10, $this->imgWidth);
            $y = random_int(-10, $this->imgHeight);
            $size = random_int(10, 16);
            $angle = random_int(-30, 30);
            imagettftext($image, $size, $angle, $x, $y, $color, $this->fontFile, $char);
        }
    }

    private function drawNoisePoints($image): void {
        for ($i = 0; $i < $this->noisePoints; $i++) {
            $color = $this->allocateRandomColor($image, [100, 200]);
            imagesetpixel($image, random_int(0, $this->imgWidth), random_int(0, $this->imgHeight), $color);
        }
    }

    private function drawCodeChars($image, string $code): void {
        $charWidth = $this->imgWidth / $this->codeLength;
        $baseLine = $this->imgHeight * 0.7; // 基線位置 (約 70% 高度)

        for ($i = 0; $i < $this->codeLength; $i++) {
            $char = $code[$i];
            // 隨機顏色 (深色系)
            $color = $this->allocateRandomColor($image, $this->textColorRange);
            // 隨機旋轉角度
            $angle = random_int(-$this->angleRange, $this->angleRange);
            // X 座標: 字符區塊內隨機 + 微調
            $x = $i * $charWidth + random_int(5, 15);
            // Y 座標: 基線上下隨機抖動
            $y = $baseLine + random_int(-5, 5);

            imagettftext($image, $this->fontSize, $angle, $x, $y, $color, $this->fontFile, $char);
        }
    }
}

// --- 使用範例 (captcha.php) ---
/*
require_once 'HighSecurityCaptcha.php';

try {
    $captcha = new HighSecurityCaptcha([
        'fontFile' => __DIR__ . '/fonts/DejaVuSans.ttf', // 必須指定有效字體路徑
        'imgWidth' => 140,
        'imgHeight' => 45,
        'codeLength' => 5,
        'angleRange' => 30,
    ]);
    $captcha->generate();
} catch (Exception $e) {
    // 生產環境記錄錯誤日誌,回傳預設圖片或錯誤訊息
    error_log('Captcha Error: ' . $e->getMessage());
    header('Content-Type: image/png');
    // 可輸出一張預設錯誤圖片
}
*/
?>

前端整合與驗證流程

1. 表單頁面

<form action="verify.php" method="post">
    <div class="captcha-wrapper">
        <img id="captchaImg" src="captcha.php" alt="高安全驗證碼" title="點擊更換" style="cursor:pointer; vertical-align:middle;">
        <button type="button" id="refreshBtn" aria-label="更換驗證碼" style="vertical-align:middle;">🔄</button>
    </div>
    <input type="text" name="captcha" id="captchaInput" placeholder="請輸入驗證碼" required autocomplete="off">
    <button type="submit">提交</button>
</form>

<script>
document.getElementById('captchaImg').addEventListener('click', refreshCaptcha);
document.getElementById('refreshBtn').addEventListener('click', refreshCaptcha);

function refreshCaptcha() {
    const img = document.getElementById('captchaImg');
    const input = document.getElementById('captchaInput');
    img.src = 'captcha.php?' + Date.now(); // 強制重新請求
    input.value = '';
    input.focus();
}
</script>

2. 驗證處理 (verify.php)

<?php
require_once 'HighSecurityCaptcha.php';
session_start();

$input = $_POST['captcha'] ?? '';

if (HighSecurityCaptcha::verify($input)) {
    echo '✅ 驗證通過,執行業務邏輯...';
    // 登入、註冊、提交訂單等
} else {
    echo '❌ 驗證碼錯誤或已過期,請重試';
}
?>

部署關鍵點檢查清單

項目說明驗證方式
GD2 + FreeTypePHP 編譯需支援 --with-freetypephp -m | grep gd、gd_info()['FreeType Support']
字體檔權限.ttf 檔案需可被 PHP 進程讀取 (www-data 權限)ls -l fonts/、is_readable() 測試
Session 目錄可寫session.save_path 目錄需存在且可寫入session_start() 無警告
防快取標頭確保瀏覽器不快取驗證碼圖片開發者工具 Network 檢查 Response Headers
錯誤處理生產環境不可輸出 PHP 錯誤訊息到圖片流display_errors = Off、自訂錯誤處理器

進階擴充方向

  1. 幾何扭曲:參考 imagecopyresampled 實作正弦波扭曲,進一步干擾字符分割。
  2. 點擊驗證/滑塊驗證:前端交互式驗證 (如 Geetest、滑塊拼圖),安全性更高但實作複雜。
  3. 行為分析:結合滑鼠軌跡、點擊節奏、裝置指紋等無感驗證 (reCAPTCHA v3 模式)。
  4. 分散式 Session:叢集環境下使用 Redis/Memcached 儲存驗證碼,避免 Session 同步問題。

總結

本文提供的 HighSecurityCaptcha 類別採用現代 PHP 物件導向設計,封裝了 TrueType 字體渲染、隨機旋轉/位移、多層干擾元素、防快取標頭、一次性驗證等高安全特性。開發者只需提供有效的 .ttf 字體路徑即可快速整合。記住:驗證碼安全性取決於「干擾複雜度」與「字符變化度」的平衡,建議定期更新字體、調整干擾參數,並配合前端無感驗證、後端風控系統構建纏深度防禦體系。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved