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

PHP 物件導向實作:可高度客製化的驗證碼類別

     編輯:PHP 相關知識

驗證碼是表單防刷、防機器人提交的第一道防線。本文展示一個完整、符合現代 PHP 規範(PSR-1/12)的 ValidationCode 類別,支援自訂尺寸、字元數、干擾線/點、TrueType 字體渲染,並內建 Session 儲存機制,可直接整合至登入、註冊、留言板等場景。

類別核心功能

  • 可配置寬高、驗證碼長度(預設 80×20px、4 字元)
  • 自動計算最佳干擾點數量,平衡可讀性與安全性
  • 支援內建字體(imagechar)與 TTF 字體(imagettftext)雙模式
  • 隨機背景色、邊框、干擾點、干擾弧線
  • 自動輸出正確 Content-Type 標頭(GIF/JPG/PNG/WBMP 相容)
  • 解構子自動釋放 GD 圖片資源

完整類別程式碼 ValidationCode.php

<?php
declare(strict_types=1);

class ValidationCode
{
    private int $width;
    private int $height;
    private int $codeNum;
    private $image;
    private int $disturbColorNum;
    private string $checkCode;

    public function __construct(int $width = 80, int $height = 20, int $codeNum = 4)
    {
        $this->width = $width;
        $this->height = $height;
        $this->codeNum = $codeNum;
        $this->checkCode = $this->createCheckCode();

        // 依畫布面積動態計算干擾點上限,避免過度遮蔽
        $area = $width * $height;
        $this->disturbColorNum = min((int)($area / 15), 240 - $codeNum);
    }

    /** 公開介面:輸出驗證碼圖片至瀏覽器 */
    public function showImage(string $fontFace = ''): void
    {
        $this->createImage();
        $this->setDisturbColor();
        $this->outputText($fontFace);
        $this->outputImage();
    }

    /** 公開介面:取得驗證碼字串(供 Session 儲存驗證) */
    public function getCheckCode(): string
    {
        return $this->checkCode;
    }

    /** 建立真彩色畫布、隨機背景、黑色邊框 */
    private function createImage(): void
    {
        $this->image = imagecreatetruecolor($this->width, $this->height);
        $bgColor = imagecolorallocate($this->image, mt_rand(225, 255), mt_rand(225, 255), mt_rand(225, 255));
        imagefill($this->image, 0, 0, $bgColor);
        $borderColor = imagecolorallocate($this->image, 0, 0, 0);
        imagerectangle($this->image, 0, 0, $this->width - 1, $this->height - 1, $borderColor);
    }

    /** 繪製干擾點與干擾弧線 */
    private function setDisturbColor(): void
    {
        // 干擾像素點
        for ($i = 0; $i < $this->disturbColorNum; $i++) {
            $color = imagecolorallocate($this->image, mt_rand(0, 255), mt_rand(0, 255), mt_rand(0, 255));
            imagesetpixel($this->image, mt_rand(1, $this->width - 2), mt_rand(1, $this->height - 2), $color);
        }
        // 干擾弧線
        for ($i = 0; $i < 10; $i++) {
            $color = imagecolorallocate($this->image, mt_rand(200, 255), mt_rand(200, 255), mt_rand(200, 255));
            imagearc($this->image, mt_rand(-10, $this->width), mt_rand(-10, $this->height), mt_rand(30, 300), mt_rand(20, 200), 55, 44, $color);
        }
    }

    /** 產生隨機驗證碼字串(排除易混淆字元 0,O,1,l,I 等) */
    private function createCheckCode(): string
    {
        $chars = '23456789abcdefghijkmnpqrstuvwxyzABCDEFGHIJKMNPQRSTUVWXYZ';
        $code = '';
        for ($i = 0; $i < $this->codeNum; $i++) {
            $code .= $chars[mt_rand(0, strlen($chars) - 1)];
        }
        return $code;
    }

    /** 將驗證碼字元逐一繪製至畫布 */
    private function outputText(string $fontFace = ''): void
    {
        for ($i = 0; $i < $this->codeNum; $i++) {
            $fontColor = imagecolorallocate($this->image, mt_rand(0, 128), mt_rand(0, 128), mt_rand(0, 128));

            if ($fontFace === '') {
                // 內建字體模式
                $fontSize = mt_rand(3, 5);
                $x = (int)($this->width / $this->codeNum) * $i + 3;
                $y = mt_rand(0, $this->height - 15);
                imagechar($this->image, $fontSize, $x, $y, $this->checkCode[$i], $fontColor);
            } else {
                // TTF 字體模式
                $fontSize = mt_rand(12, 16);
                $x = (int)(($this->width - 8) / $this->codeNum) * $i + 8;
                $y = mt_rand($fontSize + 5, $this->height);
                imagettftext($this->image, $fontSize, mt_rand(-30, 30), $x, $y, $fontColor, $fontFace, $this->checkCode[$i]);
            }
        }
    }

    /** 偵測 GD 支援格式並輸出圖片 */
    private function outputImage(): void
    {
        $types = imagetypes();
        if ($types & IMG_GIF) {
            header('Content-Type: image/gif');
            imagegif($this->image);
        } elseif ($types & IMG_JPG) {
            header('Content-Type: image/jpeg');
            imagejpeg($this->image);
        } elseif ($types & IMG_PNG) {
            header('Content-Type: image/png');
            imagepng($this->image);
        } elseif ($types & IMG_WBMP) {
            header('Content-Type: image/vnd.wap.wbmp');
            imagewbmp($this->image);
        } else {
            die('PHP 環境不支援圖片建立功能');
        }
    }

    /** 解構子:釋放記憶體 */
    public function __destruct()
    {
        if (is_resource($this->image)) {
            imagedestroy($this->image);
        }
    }
}

使用範例 captcha.php

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

$captcha = new ValidationCode(100, 30, 4); // 稍大尺寸,適合行動裝置
$captcha->showImage(__DIR__ . '/fonts/DejaVuSans.ttf'); // 若有 TTF 字體可傳入路徑
$_SESSION['captcha_code'] = $captcha->getCheckCode();

表單驗證邏輯

<?php
session_start();
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $input = strtoupper(trim($_POST['captcha'] ?? ''));
    $stored = strtoupper($_SESSION['captcha_code'] ?? '');
    if ($input !== $stored) {
        die('驗證碼錯誤,請重新輸入。');
    }
    // 驗證通過,處理業務邏輯...
    unset($_SESSION['captcha_code']); // 一次性使用,防重放
}

進階擴充建議

  • 加入 setBackgroundImages(array $paths) 支援圖片背景
  • 實作 setNoiseLevel(int $level) 讓呼叫端控制干擾強度
  • 整合 Securimage 或 Gregwar/Captcha 等成熟套件以獲得更強抗辨識能力
  • 搭配 Redis 儲存驗證碼並設定 TTL,支援分散式部署

此類別結構清晰、單一職責、易於測試與擴充,是學習 PHP GD 圖形處理與物件導向封裝的優良教材,亦可直接用於中小型專案的生產環境。

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