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

PHP GD 生成中文驗證碼亂碼?mb_convert_encoding 轉 HTML 實體完美解決

     編輯:PHP 相關知識

問題現象

使用 imagettftext() 繪製中文驗證碼時,顯示亂碼或方塊字符。原因:GD 庫的 FreeType 引擎**不直接支持 UTF-8 字符串**,需將字符串轉為 **UCS-2BE** 或 **HTML 實體** 格式。

核心解決方案:UTF-8 → HTML 實體

<?php
header('Content-Type: image/jpeg');

// 1. 準備畫布
$img = imagecreatetruecolor(250, 60);
$bg  = imagecolorallocate($img, 255, 255, 255);
$fg  = imagecolorallocate($img, 0, 0, 0);
imagefill($img, 0, 0, $bg);

// 2. 字體文件(確保路徑正確、可讀)
$font = __DIR__ . '/fonts/NotoSansSC-Regular.otf'; // 推薦開源無襯線字體

// 3. 核心:將 UTF-8 中文轉為 HTML 實體(&#xxxx;)
$text = '中華人民共和國';
$text = mb_convert_encoding($text, 'HTML-ENTITIES', 'UTF-8');
// 結果:中和八开区八和国

// 4. 繪製
imagettftext($img, 24, 0, 20, 40, $fg, $font, $text);

// 5. 輸出
imagejpeg($img, null, 90);
imagedestroy($img);

為何選 HTML-ENTITIES?

  • imagettftext() 內部會解析 &#xxxx; 形式的 Unicode 碼點,繪製對應字形。
  • 避免了 iconv('UTF-8', 'UCS-2BE') 需處理字節序(BOM)、字體是否支持 UCS-2 的不確定性。
  • 代碼簡潔、跨平台穩定。

完整驗證碼類封裝(可直接生產使用)

<?php
class Captcha {
    private $width = 130;
    private $height = 40;
    private $length = 4;
    private $fontSize = 20;
    private $fontFile;
    private $charset = '23456789ABCDEFGHJKLMNPQRSTUVWXYZ'; // 去除易混淆字符

    public function __construct(string $fontFile) {
        $this->fontFile = $fontFile;
    }

    public function generate(): string {
        $code = '';
        for ($i = 0; $i < $this->length; $i++) {
            $code .= $this->charset[random_int(0, strlen($this->charset) - 1)];
        }

        $img = imagecreatetruecolor($this->width, $this->height);
        $bg = imagecolorallocate($img, 240, 240, 240);
        imagefill($img, 0, 0, $bg);

        // 干擾線
        for ($i = 0; $i < 5; $i++) {
            $color = imagecolorallocate($img, random_int(150, 200), random_int(150, 200), random_int(150, 200));
            imageline($img, random_int(0, $this->width), random_int(0, $this->height),
                      random_int(0, $this->width), random_int(0, $this->height), $color);
        }

        // 干擾點
        for ($i = 0; $i < 50; $i++) {
            $color = imagecolorallocate($img, random_int(100, 200), random_int(100, 200), random_int(100, 200));
            imagesetpixel($img, random_int(0, $this->width), random_int(0, $this->height), $color);
        }

        // 繪製文字(逐字符隨機角度/位置)
        $x = 10;
        for ($i = 0; $i < $this->length; $i++) {
            $char = mb_convert_encoding($code[$i], 'HTML-ENTITIES', 'UTF-8');
            $angle = random_int(-15, 15);
            $y = random_int($this->fontSize + 5, $this->height - 5);
            $color = imagecolorallocate($img, random_int(0, 100), random_int(0, 100), random_int(0, 100));
            imagettftext($img, $this->fontSize, $angle, $x, $y, $color, $this->fontFile, $char);
            $x += $this->fontSize + random_int(2, 6);
        }

        // 存入 Session
        session_start();
        $_SESSION['captcha_code'] = strtolower($code); // 不區分大小寫驗證

        header('Content-Type: image/png');
        imagepng($img);
        imagedestroy($img);
        return $code;
    }

    public static function verify(string $input): bool {
        session_start();
        return strtolower($input) === ($_SESSION['captcha_code'] ?? '');
    }
}

// 使用示例
// require 'Captcha.php';
// $captcha = new Captcha(__DIR__ . '/fonts/NotoSansSC-Regular.otf');
// $captcha->generate();

驗證端代碼

<?php
require 'Captcha.php';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    if (Captcha::verify($_POST['captcha'] ?? '')) {
        echo '驗證通過';
        // 進行業務邏輯
    } else {
        echo '驗證碼錯誤';
    }
}

常見坑點檢查表

現象排查方向
顯示方框/亂碼字體路徑錯誤、字體不支持該字符、未用 HTML-ENTITIES 轉換
字符重疊/位置異常逐字符繪製時 x 坐標累加邏輯錯誤
Session 驗證總失敗生成與驗證未同域、session_start() 位置、大小寫不一致
字體文件 403/404權限、路徑、open_basedir 限制

總結

mb_convert_encoding($str, 'HTML-ENTITIES', 'UTF-8') 是 GD 繪製中文驗證碼的「銀彈」。配合開源字體(Noto Sans SC、Source Han Sans)、逐字符隨機化繪製、Session 安全驗證,即可構建生產級中文驗證碼系統。

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