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

PHP 物件導向驗證碼類別完整實作:支援干擾線、雜點、Session 驗證

     編輯:PHP 綜合知識

類別設計目標

  • 封裝 GD 圖形繪製邏輯,提供簡潔介面
  • 可配置寬高、字體大小、干擾線/點數量、驗證碼長度
  • 自動存入 Session,提供靜態驗證方法
  • 支援多實例不同配置共存

完整原始碼

<?php
/**
 * 驗證碼產生與驗證類別
 * 需求:PHP GD 擴充套件、Session 支援
 */
class Captcha {
    // 可配置屬性
    private int $width;
    private int $height;
    private int $fontSize;
    private int $pixels;   // 干擾點數量
    private int $lines;    // 干擾線數量
    private int $strLen;   // 驗證碼字元數

    // 錯誤訊息靜態屬性
    public static string $error = '';

    /**
     * 建構子:支援陣列配置覆蓋預設值
     * @param array $config ['width'=>120, 'height'=>40, 'fontSize'=>5, 'pixels'=>50, 'lines'=>3, 'strLen'=>4]
     */
    public function __construct(array $config = []) {
        $defaults = [
            'width'    => 120,
            'height'   => 40,
            'fontSize' => 5,
            'pixels'   => 50,
            'lines'    => 3,
            'strLen'   => 4,
        ];
        $cfg = array_merge($defaults, $config);

        $this->width    = $cfg['width'];
        $this->height   = $cfg['height'];
        $this->fontSize = $cfg['fontSize'];
        $this->pixels   = $cfg['pixels'];
        $this->lines    = $cfg['lines'];
        $this->strLen   = $cfg['strLen'];
    }

    /**
     * 產生並輸出驗證碼圖片 (PNG)
     * 直接輸出 HTTP 標頭與圖片二進位資料
     * @return bool 成功 true,失敗 false
     */
    public function generate(): bool {
        // 1. 建立真彩色畫布
        $img = imagecreatetruecolor($this->width, $this->height);
        if (!$img) {
            self::$error = '建立畫布失敗';
            return false;
        }

        // 2. 填充背景色 (淺色系)
        $bgColor = imagecolorallocate($img,
            mt_rand(200, 255), mt_rand(200, 255), mt_rand(200, 255)
        );
        imagefill($img, 0, 0, $bgColor);

        // 3. 繪製干擾線
        $this->drawLines($img);

        // 4. 繪製干擾點
        $this->drawPixels($img);

        // 5. 產生隨機驗證碼字串
        $captchaStr = $this->generateCode();

        // 6. 繪製文字
        $textColor = imagecolorallocate($img,
            mt_rand(0, 100), mt_rand(0, 100), mt_rand(0, 100)
        );
        // 計算文字起始座標 (置中)
        $charWidth  = imagefontwidth($this->fontSize);
        $charHeight = imagefontheight($this->fontSize);
        $totalWidth = $this->strLen * $charWidth * 1.2; // 字元間距
        $startX = (int)(($this->width - $totalWidth) / 2);
        $startY = (int)(($this->height - $charHeight) / 2);

        // 逐字元繪製並加入隨機偏移/旋轉 (進階版可用 imagettftext)
        $codeWithSpaces = implode(' ', str_split($captchaStr));
        $result = imagestring($img, $this->fontSize, $startX, $startY, $codeWithSpaces, $textColor);

        if (!$result) {
            self::$error = '文字繪製失敗';
            imagedestroy($img);
            return false;
        }

        // 7. 輸出圖片
        header('Content-Type: image/png');
        header('Cache-Control: no-store, no-cache, must-revalidate');
        header('Pragma: no-cache');
        imagepng($img);
        imagedestroy($img);
        return true;
    }

    /**
     * 靜態驗證方法:比對使用者輸入與 Session 儲存值
     * @param string $input 使用者提交的驗證碼
     * @return bool 不區分大小寫
     */
    public static function check(string $input): bool {
        if (!isset($_SESSION['captcha'])) {
            self::$error = 'Session 中無驗證碼';
            return false;
        }
        return strtolower($input) === strtolower($_SESSION['captcha']);
    }

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

    /** 產生隨機字串並存入 Session */
    private function generateCode(): string {
        $chars = array_merge(range('a', 'z'), range('A', 'Z'), range(2, 9)); // 排除 0,1,o,l 易混淆字元
        $code = '';
        $max = count($chars) - 1;
        for ($i = 0; $i < $this->strLen; $i++) {
            $code .= $chars[mt_rand(0, $max)];
        }
        $_SESSION['captcha'] = $code;
        return $code;
    }

    /** 繪製干擾線 */
    private function drawLines($img): void {
        for ($i = 0; $i < $this->lines; $i++) {
            $color = imagecolorallocate($img,
                mt_rand(150, 200), mt_rand(150, 200), mt_rand(150, 200)
            );
            imageline($img,
                mt_rand(0, $this->width), mt_rand(0, $this->height),
                mt_rand(0, $this->width), mt_rand(0, $this->height),
                $color
            );
        }
    }

    /** 繪製干擾點 */
    private function drawPixels($img): void {
        for ($i = 0; $i < $this->pixels; $i++) {
            $color = imagecolorallocate($img,
                mt_rand(100, 150), mt_rand(100, 150), mt_rand(100, 150)
            );
            imagesetpixel($img,
                mt_rand(0, $this->width), mt_rand(0, $this->height),
                $color
            );
        }
    }
}

使用範例

1. 產生驗證碼頁面 (captcha.php)

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

$captcha = new Captcha([
    'width'    => 130,
    'height'   => 50,
    'fontSize' => 5,
    'pixels'   => 80,
    'lines'    => 4,
    'strLen'   => 5,
]);
$captcha->generate(); // 直接輸出圖片,程式結束
?>

2. 表單頁面

<form action="verify.php" method="post">
  <img src="captcha.php" id="captchaImg" alt="驗證碼" style="vertical-align:middle; cursor:pointer" onclick="this.src='captcha.php?'+Date.now()">
  <a href="javascript:void(0)" onclick="document.getElementById('captchaImg').src='captcha.php?'+Date.now()">看不清?換一張</a>
  <br>
  <input type="text" name="captcha" required placeholder="請輸入驗證碼">
  <button type="submit">送出</button>
</form>

3. 驗證處理 (verify.php)

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

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $input = $_POST['captcha'] ?? '';
    if (Captcha::check($input)) {
        echo "驗證通過!";
        // 清除已使用的驗證碼,防止重複使用
        unset($_SESSION['captcha']);
        // 進行後續業務邏輯...
    } else {
        echo "驗證碼錯誤:" . Captcha::$error;
    }
}
?>

進階強化建議

  1. 使用 TTF 字體 + 旋轉/扭曲:將 imagestring 替換為 imagettftext,每字元隨機旋轉 ±15°、隨機顏色、隨機 Y 軸偏移,大幅提升機器識別難度。
  2. 加入幾何干擾:繪製隨機圓弧、貝茲曲線、多邊形。
  3. 限流與快取:同一 IP 短時間內請求驗證碼次數限制;圖片可快取 30 秒 (同一 Session)。
  4. 無障礙支援:提供音訊驗證碼選項 (文字轉語音)。
  5. Session 安全:session_start(['cookie_httponly' => true, 'cookie_secure' => true, 'use_strict_mode' => true])。

常見問題排查

現象原因解決
圖片顯示破圖輸出前有空白/BOM/錯誤訊息檔案儲存為 UTF-8 無 BOM;確保 generate() 前無任何 echo/var_dump
Session 驗證總是失敗session_start() 未在兩端呼叫captcha.php 和 verify.php 開頭皆需 session_start()
中文系統顯示亂碼字體不支援中文驗證碼僅用英數字;若需中文請用 TTF 字體
GD 函式未定義未安裝 php-gdapt install php-gd 或 yum install php-gd 後重啟 PHP-FPM

此 Captcha 類別結構清晰、配置靈活、易於擴充,適合中小型專案直接引入使用。

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