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

PHP 生成圖形驗證碼完整指南:GD 庫安裝、兩種實現方案與安全強化

     編輯:PHP 相關知識

環境準備:啟用 GD 擴展

# Linux 編譯
./configure --with-gd --with-freetype-dir --with-jpeg-dir --with-png-dir

# Windows php.ini
extension=php_gd2.dll  ; 取消註解
; 確認 phpinfo() 顯示 GD Support: enabled, FreeType Support: true

驗證:

<?php
if (extension_loaded('gd')) {
    echo "GD 版本: " . gd_info()['GD Version'] . "\n";
    print_r(gd_info());
} else {
    die('請啟用 php_gd2.dll');
}
?>

方案一:經典數字/字母驗證碼 (適合簡單場景)

<?php
/**
 * 生成驗證碼圖片並存入 Session
 * @param int $num 字元數
 * @param int $size 字體大小
 * @param int $width 圖片寬
 * @param int $height 圖片高
 */
function vCode($num = 4, $size = 20, $width = 0, $height = 0) {
    session_start();

    // 尺寸自適應
    !$width && $width = $num * $size * 4 / 5 + 10;
    !$height && $height = $size + 15;

    // 字元池 (排除易混淆: 0/O, 1/I/l)
    $chars = '23456789abcdefghjkmnpqrstuvwxyzABCDEFGHJKMNPQRSTUVWXYZ';
    $code = '';
    for ($i = 0; $i < $num; $i++) {
        $code .= $chars[mt_rand(0, strlen($chars) - 1)];
    }
    $_SESSION['verify_code'] = strtolower($code); // 統一小寫驗證

    // 建立真彩色圖片
    $im = imagecreatetruecolor($width, $height);

    // 顏色分配
    $bgColor = imagecolorallocate($im, 235, 236, 237); // 淺灰背景
    $borderColor = imagecolorallocate($im, 118, 151, 199); // 藍邊框
    $textColor = imagecolorallocate($im, mt_rand(0, 100), mt_rand(0, 100), mt_rand(0, 100)); // 深色文字

    // 填充背景
    imagefilledrectangle($im, 0, 0, $width, $height, $bgColor);
    // 畫邊框
    imagerectangle($im, 0, 0, $width - 1, $height - 1, $borderColor);

    // 干擾線 (5 條)
    for ($i = 0; $i < 5; $i++) {
        $lineColor = imagecolorallocate($im, mt_rand(0, 255), mt_rand(0, 255), mt_rand(0, 255));
        imageline($im,
            mt_rand(0, $width), mt_rand(0, $height),
            mt_rand(0, $width), mt_rand(0, $height),
            $lineColor
        );
    }

    // 干擾點 (50 個)
    for ($i = 0; $i < 50; $i++) {
        $dotColor = imagecolorallocate($im, mt_rand(0, 255), mt_rand(0, 255), mt_rand(0, 255));
        imagesetpixel($im, mt_rand(0, $width), mt_rand(0, $height), $dotColor);
    }

    // 繪製文字 (需 TTF 字體支援中文/特殊字體)
    // Windows 字體路徑範例: 'C:/Windows/Fonts/arial.ttf'
    // Linux: '/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf'
    $fontFile = 'C:/Windows/Fonts/arial.ttf'; // 請根據環境修改
    if (file_exists($fontFile)) {
        imagettftext($im, $size, mt_rand(-10, 10), 10, $size + 5, $textColor, $fontFile, $code);
    } else {
        // 回退內建字體 (不支援中文、無旋轉)
        imagestring($im, 5, 10, 5, $code, $textColor);
    }

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

// 使用:
vCode();
?>

方案二:W3C 標準風格驗證碼 (更美觀、可訪問性更好)

<?php
session_start();

$width = 120;
$height = 40;
$charCount = 6;
$font = __DIR__ . '/fonts/DejaVuSans.ttf'; // 需下載 TTF 字體

$chars = '23456789bcdfghjkmnpqrstvwxyz'; // 無易混淆字元
$code = '';
for ($i = 0; $i < $charCount; $i++) {
    $code .= $chars[mt_rand(0, strlen($chars) - 1)];
}
$_SESSION['captcha_code'] = strtolower($code);

$fontSize = $height * 0.75;
$im = imagecreatetruecolor($width, $height);

// 顏色 (十六進制轉 RGB)
function hex2rgb($hex) {
    $hex = ltrim($hex, '#');
    return [
        'r' => hexdec(substr($hex, 0, 2)),
        'g' => hexdec(substr($hex, 2, 2)),
        'b' => hexdec(substr($hex, 4, 2))
    ];
}

$bg = imagecolorallocate($im, 255, 255, 255);
$textCol = imagecolorallocate($im, ...array_values(hex2rgb('142864')));
$noiseCol = imagecolorallocate($im, ...array_values(hex2rgb('142864')));

// 干擾點
for ($i = 0; $i < 10; $i++) {
    imagefilledellipse($im, mt_rand(0, $width), mt_rand(0, $height), 2, 3, $noiseCol);
}

// 干擾線
for ($i = 0; $i < 20; $i++) {
    imageline($im, mt_rand(0, $width), mt_rand(0, $height), mt_rand(0, $width), mt_rand(0, $height), $noiseCol);
}

// 計算文字居中位置
$box = imagettfbbox($fontSize, 0, $font, $code);
$x = ($width - ($box[2] - $box[0])) / 2;
$y = ($height - ($box[5] - $box[3])) / 2;

imagettftext($im, $fontSize, 0, $x, $y, $textCol, $font, $code);

header('Content-Type: image/jpeg');
imagejpeg($im, null, 90);
imagedestroy($im);
?>

前端整合與驗證

<!-- HTML -->
<form action="login.php" method="post">
    <input type="text" name="captcha" placeholder="輸入驗證碼" required>
    <img id="captchaImg" src="captcha.php" alt="驗證碼" style="cursor:pointer;vertical-align:middle" title="點擊刷新">
    <script>
    document.getElementById('captchaImg').onclick = function() {
        this.src = 'captcha.php?' + Date.now(); // 防緩存
    };
    </script>
    <button type="submit">登入</button>
</form>
<?php
// login.php
session_start();
if (strtolower($_POST['captcha'] ?? '') !== ($_SESSION['captcha_code'] ?? '')) {
    die('驗證碼錯誤');
}
// 正常登入邏輯...
?>

安全強化清單

  1. 使用 random_int 替代 mt_rand (PHP 7+):防止種子預測
  2. Session 防固定:登入前 session_regenerate_id(true)
  3. 限制嘗試次數:Redis 記錄 IP + Session 失敗計數,超 5 次鎖定 15 分鐘
  4. 圖片無緩存 Header:`Cache-Control: no-store, no-cache, must-revalidate`
  5. 音頻驗證碼無障礙:為視障用戶提供語音播放選項
  6. 考慮現代替代方案:reCAPTCHA v3 (行為分析、無感驗證)、hCaptcha (隱私友好)

字體檔案獲取

方案一適合快速原型、內部系統;方案二視覺更專業,適合面向用戶的正式產品。現代項目建議優先評估 reCAPTCHA v3 / hCaptcha 等無感驗證方案。

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