使用PHP創(chuàng)建圖像驗證碼的示例代碼
PHP 圖像驗證碼的實現(xiàn)完全基于GD 庫,它是 PHP 官方內(nèi)置的圖像處理擴(kuò)展,提供了畫布創(chuàng)建、顏色分配、文本繪制、圖形渲染、圖片輸出等全能力,是 PHP 圖像處理的行業(yè)標(biāo)準(zhǔn)方案。
開啟 GD 擴(kuò)展
- Windows 環(huán)境:打開
php.ini,去掉extension=gd前的分號注釋,重啟 Web 服務(wù)(Apache/Nginx/PHP-FPM) - Linux 環(huán)境:編譯 PHP 時添加
--with-gd參數(shù),或通過包管理器安裝php-gd擴(kuò)展(如yum install php-gd/apt install php-gd),重啟服務(wù)生效
生成驗證碼
第一步:開啟Session與配置
<?php
// 開啟Session,用于存儲驗證碼校驗值(必須在輸出前執(zhí)行,無任何前置空格)
session_start();
// 引入驗證碼配置
$captchaConfig = [
// 基礎(chǔ)尺寸配置
'width' => 150, // 驗證碼圖片寬度
'height' => 50, // 驗證碼圖片高度
// 字符配置
'length' => 4, // 驗證碼字符長度,常用4-6位
'charset' => '23456789ABCDEFGHJKLMNPQRSTUVWXYZ', // 字符集:去掉易混淆的0/O、1/l,提升用戶體驗
'font_size' => 24, // 字體字號
'font_file' => './fonts/arial.ttf', // TTF字體文件路徑,必須填寫正確,否則無法繪制文字
// 干擾項配置(平衡安全性與識別度)
'line_num' => 6, // 干擾線數(shù)量
'pixel_num' => 100, // 噪點數(shù)量
// 安全配置
'expire' => 300, // 驗證碼有效期,單位秒,默認(rèn)5分鐘
'session_key' => 'captcha_code', // Session存儲的key
];第二步:創(chuàng)建畫布+分配基礎(chǔ)顏色
// 創(chuàng)建真彩色畫布 $img = imagecreatetruecolor($captchaConfig['width'], $captchaConfig['height']); // 分配背景色:淺色系背景,提升文字辨識度(240-255區(qū)間) $bgColor = imagecolorallocate($img, 245, 245, 245); // 分配文字顏色:深色系,隨機(jī)生成避免固定色值被OCR識別 $textColor = imagecolorallocate($img, rand(10, 50), rand(10, 50), rand(10, 50)); // 填充畫布背景 imagefill($img, 0, 0, $bgColor);
| API 函數(shù) | 核心作用 |
|---|---|
imagecreatetruecolor(int $width, int $height) | 創(chuàng)建真彩色的圖像畫布,是驗證碼的載體 |
imagecolorallocate(resource $image, int $red, int $green, int $blue) | 為畫布分配 RGB 顏色,用于背景、文字、干擾項繪制 |
imagefill(resource $image, int $x, int $y, int $color) | 為畫布填充背景色,從坐標(biāo) (x,y) 開始填充 |
第三步:生成隨機(jī)驗證碼字符串
$code = '';
$charsetLen = strlen($captchaConfig['charset']);
for ($i = 0; $i < $captchaConfig['length']; $i++) {
// 從字符集中隨機(jī)取一個字符,拼接成最終驗證碼
$code .= $captchaConfig['charset'][rand(0, $charsetLen - 1)];
}
第四步:繪制干擾元素(先畫干擾項,再畫文字,避免文字被遮擋)
// 繪制隨機(jī)干擾線
for ($i = 0; $i < $captchaConfig['line_num']; $i++) {
// 隨機(jī)生成線條顏色(淺色系,不搶文字視覺)
$lineColor = imagecolorallocate($img, rand(100, 200), rand(100, 200), rand(100, 200));
// 隨機(jī)生成線條起點和終點,貫穿整個畫布
imageline(
$img,
rand(0, $captchaConfig['width']),
rand(0, $captchaConfig['height']),
rand(0, $captchaConfig['width']),
rand(0, $captchaConfig['height']),
$lineColor
);
}
// 繪制隨機(jī)噪點
for ($i = 0; $i < $captchaConfig['pixel_num']; $i++) {
// 隨機(jī)生成噪點顏色
$pixelColor = imagecolorallocate($img, rand(50, 150), rand(50, 150), rand(50, 150));
// 隨機(jī)生成噪點位置
imagesetpixel($img, rand(0, $captchaConfig['width']), rand(0, $captchaConfig['height']), $pixelColor);
}
imageline(resource $image, int $x1, int $y1, int $x2, int $y2, int $color)繪制直線,多用于添加干擾線,增加機(jī)器自動識別難度imagesetpixel(resource $image, int $x, int $y, int $color)繪制單個像素點,用來生成噪點干擾,強化驗證碼防破解效果
第五步:繪制驗證碼字符到畫布
// 計算單個字符的寬度,均勻分布在畫布上
$singleWidth = $captchaConfig['width'] / $captchaConfig['length'];
for ($i = 0; $i < $captchaConfig['length']; $i++) {
// 每個字符隨機(jī)旋轉(zhuǎn)-10到10度,防止機(jī)器識別
$angle = rand(-10, 10);
// 計算字符的x坐標(biāo),左右留邊距,均勻分布
$x = $singleWidth * $i + rand(5, 10);
// 計算字符的y坐標(biāo),垂直居中(基線對齊,避免文字下沉)
$y = $captchaConfig['height'] / 2 + $captchaConfig['font_size'] / 3;
// 寫入單個字符到畫布
imagettftext(
$img,
$captchaConfig['font_size'],
$angle,
$x,
$y,
$textColor,
$captchaConfig['font_file'],
$code[$i]
);
}
imagettftext(resource $image, float $size, float $angle, int $x, int $y, int $color, string $font_file, string $text)寫入 TrueType 字體文本,是繪制驗證碼字符的核心,支持自定義字體、字號、文字旋轉(zhuǎn)角度
第六步:存儲驗證碼到Session,完成服務(wù)端持久化
// 存儲加密后的驗證碼+過期時間,生產(chǎn)環(huán)境建議加密存儲,避免Session泄露
$_SESSION[$captchaConfig['session_key']] = [
'code' => strtolower($code), // 轉(zhuǎn)小寫,實現(xiàn)不區(qū)分大小寫校驗,提升用戶體驗
'expire_time' => time() + $captchaConfig['expire'] // 過期時間戳
];
第七步:輸出圖片到瀏覽器
// 聲明響應(yīng)頭為PNG圖片,禁止瀏覽器緩存
header('Content-Type: image/png');
header('Cache-Control: no-cache, no-store, must-revalidate');
header('Pragma: no-cache');
// 輸出圖片
imagepng($img);
// 銷毀畫布資源,釋放內(nèi)存
imagedestroy($img);
imagepng(resource $image)以 PNG 格式輸出圖像,可直接推送到瀏覽器,也能保存為圖片文件imagedestroy(resource $image)銷毀畫布圖像資源,釋放服務(wù)器內(nèi)存,是代碼收尾必備操作header(string $header)設(shè)置 HTTP 響應(yīng)頭,告知瀏覽器返回內(nèi)容為圖片格式,避免頁面出現(xiàn)亂碼
校驗驗證碼
<?php
// 1. 開啟Session,與生成端保持一致
session_start();
// 2. 配置項,必須與生成端保持一致
$captchaConfig = [
'session_key' => 'captcha_code',
];
// 3. 封裝校驗函數(shù),可全局復(fù)用
function checkCaptcha(string $userInput): array
{
global $captchaConfig;
// 3.1 先判斷用戶是否輸入了驗證碼
if (empty($userInput)) {
return ['status' => false, 'msg' => '請輸入驗證碼'];
}
// 3.2 判斷服務(wù)端是否存在驗證碼Session
if (!isset($_SESSION[$captchaConfig['session_key']])) {
return ['status' => false, 'msg' => '驗證碼已過期,請刷新重試'];
}
// 3.3 取出Session中的驗證碼數(shù)據(jù)
$captchaData = $_SESSION[$captchaConfig['session_key']];
// 3.4 校驗驗證碼是否過期
if (time() > $captchaData['expire_time']) {
// 過期后立即銷毀,防止復(fù)用
unset($_SESSION[$captchaConfig['session_key']]);
return ['status' => false, 'msg' => '驗證碼已過期,請刷新重試'];
}
// 3.5 校驗驗證碼是否正確(統(tǒng)一轉(zhuǎn)小寫,不區(qū)分大小寫)
if (strtolower(trim($userInput)) !== $captchaData['code']) {
// 校驗失敗立即銷毀,防止破解
unset($_SESSION[$captchaConfig['session_key']]);
return ['status' => false, 'msg' => '驗證碼錯誤,請刷新重試'];
}
// 3.6 校驗成功,立即銷毀當(dāng)前驗證碼,防止重放攻擊(單次有效)
unset($_SESSION[$captchaConfig['session_key']]);
return ['status' => true, 'msg' => '驗證碼校驗通過'];
}
// 4. 調(diào)用示例(用戶POST提交表單時)
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// 獲取用戶輸入的驗證碼
$userCaptcha = $_POST['captcha'] ?? '';
// 執(zhí)行校驗
$checkResult = checkCaptcha($userCaptcha);
if (!$checkResult['status']) {
// 校驗失敗,返回錯誤信息
echo json_encode(['code' => 400, 'msg' => $checkResult['msg']]);
exit;
}
// 校驗通過,執(zhí)行后續(xù)業(yè)務(wù)邏輯(登錄、注冊、發(fā)送短信等)
echo json_encode(['code' => 200, 'msg' => '操作成功']);
exit;
}生產(chǎn)環(huán)境注意事項與安全規(guī)范
必須使用 HTTPS 傳輸:驗證碼接口和表單提交接口必須通過 HTTPS 傳輸,防止中間人竊取驗證碼圖片和提交內(nèi)容,規(guī)避重放攻擊。
驗證碼存儲安全:
- 生產(chǎn)環(huán)境嚴(yán)禁將驗證碼原始字符串返回給前端,必須僅存儲在服務(wù)端 Session/Redis 中;
- 高并發(fā)場景建議使用 Redis 存儲驗證碼,替代原生 Session,提升性能和分布式系統(tǒng)兼容性;
- 建議對存儲的驗證碼進(jìn)行不可逆加密,避免 Session/Redis 泄露導(dǎo)致驗證碼被破解。
用戶體驗與安全平衡:
- 字符集必須剔除易混淆的
0和O、1和l、2和Z等字符,減少用戶輸入錯誤; - 干擾線和噪點數(shù)量需合理,避免過度干擾導(dǎo)致用戶無法識別;
- 必須實現(xiàn)不區(qū)分大小寫校驗,降低用戶輸入門檻。
防破解規(guī)范:
- 驗證碼必須單次有效,無論校驗成功或失敗,立即銷毀,禁止重復(fù)使用;
- 同一 IP 短時間內(nèi)多次獲取驗證碼,需進(jìn)行頻率限制,防止驗證碼被批量抓??;
- 校驗失敗 3 次以上,必須強制刷新驗證碼,避免暴力枚舉。
字體與資源規(guī)范:
- 必須使用開源免費字體,避免商用字體導(dǎo)致的版權(quán)風(fēng)險;
- 建議使用多種字體隨機(jī)切換,每個字符使用不同字體,大幅提升 OCR 識別難度;
- 字體文件路徑建議使用絕對路徑,避免相對路徑導(dǎo)致的繪制失敗。
輸出規(guī)范:
- 必須設(shè)置禁止緩存的響應(yīng)頭,防止瀏覽器、CDN 緩存驗證碼圖片,導(dǎo)致校驗失??;
- 輸出圖片前必須清空輸出緩沖區(qū),避免框架輸出的多余內(nèi)容導(dǎo)致圖片亂碼;
- 圖片輸出后必須執(zhí)行
imagedestroy()銷毀畫布資源,避免服務(wù)器內(nèi)存泄漏。
嚴(yán)禁存儲敏感信息:驗證碼僅用于人機(jī)校驗,禁止在其中嵌入用戶 ID、密碼等敏感信息。
到此這篇關(guān)于使用PHP創(chuàng)建圖像驗證碼的示例代碼的文章就介紹到這了,更多相關(guān)PHP圖像驗證碼內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
php小經(jīng)驗:解析preg_match與preg_match_all 函數(shù)
本篇文章是對php中的preg_match函數(shù)與preg_match_all函數(shù)進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-06-06
PHP實現(xiàn)將上傳圖片自動縮放到指定分辨率,并保持清晰度封裝類示例
這篇文章主要介紹了PHP實現(xiàn)將上傳圖片自動縮放到指定分辨率,并保持清晰度封裝類,涉及php針對jpeg、png、gif等格式圖片的縮放與輸出相關(guān)操作技巧,需要的朋友可以參考下2019-06-06
PHP laravel實現(xiàn)配置使用多數(shù)據(jù)庫
有的時候,我們在開發(fā)的過程中需要連接多個數(shù)據(jù)庫。Laravel框架中早已為我們想到了這樣的需求。這篇文章主要為大家介紹了laravel配置使用多數(shù)據(jù)庫的方法,需要的可以參考一下2022-10-10
PHP對MongoDB[NoSQL]數(shù)據(jù)庫的操作
PHP對MongoDB[NoSQL]數(shù)據(jù)庫的操作,需要的朋友可以參考一下2013-03-03

