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

PHP GD 庫生成動態驗證碼完整實現:從圖像處理基礎到生產級驗證機制

     編輯:PHP 相關知識

驗證碼(CAPTCHA)是區分人機的關鍵防線。本文從 PHP GD 圖像處理基礎入手,逐步構建完整的動態驗證碼系統:圖像生成、干擾元素、Session 驗證、AJAX 刷新、前端整合,提供可直接部署的生產級代碼。

PHP GD 圖像處理基礎流程

  1. header('Content-Type: image/png') — 設定輸出 MIME
  2. imagecreatetruecolor($w, $h) — 建立真彩色畫布
  3. imagecolorallocate($im, $r, $g, $b) — 分配顏色
  4. imagefill($im, 0, 0, $color) — 填充背景
  5. 繪製圖形/文字:imageline、imagestring、imagettftext(TTF)
  6. imagepng($im) — 輸出 PNG 二進制流
  7. imagedestroy($im) — 釋放記憶體

核心驗證碼類實現

<?php
/**
 * Captcha 類:支援配置寬高、字元數、字體、干擾線、噪點、邊框
 */
class Captcha
{
    private $width = 120;
    private $height = 40;
    private $length = 4;
    private $fontSize = 20;
    private $fontFile = ''; // TTF 字體路徑,空則用內建字體
    private $charset = '23456789abcdefghjkmnpqrstuvwxyzABCDEFGHJKMNPQRSTUVWXYZ'; // 排除易混淆字元
    private $useNoise = true;
    private $useLines = true;
    private $useBorder = false;
    private $sessionKey = 'captcha_code';

    public function __construct(array $config = [])
    {
        foreach ($config as $k => $v) {
            if (property_exists($this, $k)) $this->$k = $v;
        }
    }

    public function generate(): string
    {
        $code = $this->generateCode();
        $_SESSION[$this->sessionKey] = strtolower($code); // 不區分大小寫驗證

        $im = imagecreatetruecolor($this->width, $this->height);
        
        // 背景色(淺色)
        $bg = imagecolorallocate($im, mt_rand(220, 255), mt_rand(220, 255), mt_rand(220, 255));
        imagefill($im, 0, 0, $bg);

        // 干擾線
        if ($this->useLines) {
            for ($i = 0; $i < 6; $i++) {
                $color = imagecolorallocate($im, mt_rand(50, 180), mt_rand(50, 180), mt_rand(50, 180));
                imageline($im, mt_rand(0, $this->width), mt_rand(0, $this->height), mt_rand(0, $this->width), mt_rand(0, $this->height), $color);
            }
        }

        // 噪點
        if ($this->useNoise) {
            for ($i = 0; $i < 80; $i++) {
                $color = imagecolorallocate($im, mt_rand(150, 255), mt_rand(150, 255), mt_rand(150, 255));
                imagesetpixel($im, mt_rand(0, $this->width), mt_rand(0, $this->height), $color);
            }
        }

        // 繪製驗證碼字元
        $x = 10;
        for ($i = 0; $i < $this->length; $i++) {
            $char = $code[$i];
            $color = imagecolorallocate($im, mt_rand(0, 80), mt_rand(0, 80), mt_rand(0, 80));
            $angle = mt_rand(-15, 15);
            $y = mt_rand($this->height / 3, $this->height * 2 / 3);
            
            if ($this->fontFile && file_exists($this->fontFile)) {
                imagettftext($im, $this->fontSize, $angle, $x, $y, $color, $this->fontFile, $char);
                $x += $this->fontSize + 2;
            } else {
                imagestring($im, 5, $x, $y, $char, $color);
                $x += imagefontwidth(5) + 2;
            }
        }

        // 邊框
        if ($this->useBorder) {
            $borderColor = imagecolorallocate($im, 0, 0, 0);
            imagerectangle($im, 0, 0, $this->width - 1, $this->height - 1, $borderColor);
        }

        // 輸出
        header('Content-Type: image/png');
        header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
        header('Pragma: no-cache');
        imagepng($im);
        imagedestroy($im);
        
        return $code;
    }

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

    public static function verify(string $input, string $sessionKey = 'captcha_code'): bool
    {
        if (empty($_SESSION[$sessionKey])) return false;
        $valid = strtolower($input) === $_SESSION[$sessionKey];
        // 驗證後可選擇銷毀,防止重放
        // unset($_SESSION[$sessionKey]);
        return $valid;
    }
}

使用範例

1. 生成驗證碼圖片:captcha.php

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

$captcha = new Captcha([
    'width' => 130,
    'height' => 45,
    'length' => 5,
    'fontFile' => __DIR__ . '/fonts/arial.ttf', // 可選
    'useNoise' => true,
    'useLines' => true,
]);
$captcha->generate();

2. 表單頁面:login.php

<?php session_start(); ?>
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>登入</title>
    <style>
        .captcha-img { cursor: pointer; vertical-align: middle; border: 1px solid #ddd; }
        .captcha-input { width: 100px; }
    </style>
</head>
<body>
    <form method="POST" action="verify.php">
        <div>
            <label>帳號:<input name="username" required></label>
        </div>
        <div>
            <label>密碼:<input name="password" type="password" required></label>
        </div>
        <div>
            <label>驗證碼:
                <input name="captcha" class="captcha-input" required maxlength="5">
                <img class="captcha-img" id="captchaImg" src="captcha.php" alt="點擊刷新" title="點擊刷新">
            </label>
        </div>
        <button type="submit">登入</button>
    </form>
    <script>
        document.getElementById('captchaImg').onclick = function() {
            this.src = 'captcha.php?' + Date.now(); // 時間戳防快取
        };
    </script>
</body>
</html>

3. 驗證處理:verify.php

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

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $captchaInput = $_POST['captcha'] ?? '';
    if (!Captcha::verify($captchaInput)) {
        die(json_encode(['success' => false, 'msg' => '驗證碼錯誤']));
    }
    // 驗證通過,進行業務邏輯
    $username = $_POST['username'] ?? '';
    // ... 登入邏輯
    echo json_encode(['success' => true, 'msg' => '登入成功']);
}

進階強化方案

方向實現方式
TTF 字體反辨識使用變形、扭曲、隨機角度的 imagettftext,載入多種手寫體字體
中文驗證碼字元集改為常用漢字,imagettftext 渲染,需支援中文字體
點選/滑塊驗證前端 Canvas 交互,後端驗證軌跡/座標,安全性更高
Redis 儲存驗證碼分散式部署時,Session 替換為 Redis,設定 TTL 60-120 秒
速率限制同一 IP/Session 限制生成頻率(如 10 次/分鐘)
無障礙支援提供音頻驗證碼選項(語音朗讀字元)

安全性檢查清單

  • ✅ 字元集排除 0/O, 1/I/l, 8/B, 5/S, 2/Z 等易混淆字元
  • ✅ 驗證碼大小寫不敏感,降低用戶挫折感
  • ✅ 圖片輸出設定 Cache-Control: no-store 防止瀏覽器快取
  • ✅ 驗證後可選銷毀 Session,防止重放攻擊
  • ✅ 生成端與驗證端分離,便於微服務架構
  • ⚠️ 純圖形驗證碼已可被 AI 高精度識別,高安全場景建議遷移至行為驗證(滑塊、點選、無感驗證)

現代替代方案推薦

  • Google reCAPTCHA v3:無感分數式,最佳用戶體驗
  • hCaptcha:隱私優先,支援中文
  • Turnstile (Cloudflare):免費、無感、易整合
  • Geetest / NetEase Captcha:國內主流行為驗證服務

自建 GD 驗證碼適合學習、內部系統、低風險場景。面向公網的關鍵業務(登入、註冊、支付),**強烈建議接入成熟的第三方行為驗證服務**,兼顧安全性與用戶體驗。

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