PHP 图像验证码的实现完全基于GD 库,它是 PHP 官方内置的图像处理扩展,提供了画布创建、颜色分配、文本绘制、图形渲染、图片输出等全能力,是 PHP 图像处理的行业标准方案。
开启 GD 扩展
- Windows 环境:打开
php.ini,去掉extension=gd前的分号注释,重启 Web 服务(Apache/Nginx/PHP-FPM) - Linux 环境:编译 PHP 时添加
--with-gd参数,或通过包管理器安装php-gd扩展(如yum install php-gd/apt install php-gd),重启服务生效
生成验证码
第一步:开启Session与配置
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, // 干扰线数量
'pixel_num' => 100, // 噪点数量
// 安全配置
'expire' => 300, // 验证码有效期,单位秒,默认5分钟
'session_key' => 'captcha_code', // Session存储的key
];
第二步:创建画布+分配基础颜色
// 创建真彩色画布 $img = imagecreatetruecolor($captchaConfig['width'], $captchaConfig['height']); // 分配背景色:浅色系背景,提升文字辨识度(240-255区间) $bgColor = imagecolorallocate($img, 245, 245, 245); // 分配文字颜色:深色系,随机生成避免固定色值被OCR识别 $textColor = imagecolorallocate($img, rand(10, 50), rand(10, 50), rand(10, 50)); // 填充画布背景 imagefill($img, 0, 0, $bgColor);
| API 函数 | 核心作用 |
|---|---|
imagecreatetruecolor(int $width, int $height) |
创建真彩色的图像画布,是验证码的载体 |
imagecolorallocate(resource $image, int $red, int $green, int $blue) |
为画布分配 RGB 颜色,用于背景、文字、干扰项绘制 |
imagefill(resource $image, int $x, int $y, int $color) |
为画布填充背景色,从坐标 (x,y) 开始填充 |
第三步:生成随机验证码字符串
$code = ''; $charsetLen = strlen($captchaConfig['charset']); for ($i = 0; $i
第四步:绘制干扰元素(先画干扰项,再画文字,避免文字被遮挡)
// 绘制随机干扰线 for ($i = 0; $i
-
imageline(resource $image, int $x1, int $y1, int $x2, int $y2, int $color)绘制直线,多用于添加干扰线,增加机器自动识别难度 -
imagesetpixel(resource $image, int $x, int $y, int $color)绘制单个像素点,用来生成噪点干扰,强化验证码防破解效果
第五步:绘制验证码字符到画布
// 计算单个字符的宽度,均匀分布在画布上 $singleWidth = $captchaConfig['width'] / $captchaConfig['length']; for ($i = 0; $i
imagettftext(resource $image, float $size, float $angle, int $x, int $y, int $color, string $font_file, string $text)写入 TrueType 字体文本,是绘制验证码字符的核心,支持自定义字体、字号、文字旋转角度
第六步:存储验证码到Session,完成服务端持久化
// 存储加密后的验证码+过期时间,生产环境建议加密存储,避免Session泄露
$_SESSION[$captchaConfig['session_key']] = [
'code' => strtolower($code), // 转小写,实现不区分大小写校验,提升用户体验
'expire_time' => time() + $captchaConfig['expire'] // 过期时间戳
];
第七步:输出图片到浏览器
// 声明响应头为PNG图片,禁止浏览器缓存
header('Content-Type: image/png');
header('Cache-Control: no-cache, no-store, must-revalidate');
header('Pragma: no-cache');
// 输出图片
imagepng($img);
// 销毁画布资源,释放内存
imagedestroy($img);
-
imagepng(resource $image)以 PNG 格式输出图像,可直接推送到浏览器,也能保存为图片文件 -
imagedestroy(resource $image)销毁画布图像资源,释放服务器内存,是代码收尾必备操作 -
header(string $header)设置 HTTP 响应头,告知浏览器返回内容为图片格式,避免页面出现乱码
校验验证码
'captcha_code',
];
// 3. 封装校验函数,可全局复用
function checkCaptcha(string $userInput): array
{
global $captchaConfig;
// 3.1 先判断用户是否输入了验证码
if (empty($userInput)) {
return ['status' => false, 'msg' => '请输入验证码'];
}
// 3.2 判断服务端是否存在验证码Session
if (!isset($_SESSION[$captchaConfig['session_key']])) {
return ['status' => false, 'msg' => '验证码已过期,请刷新重试'];
}
// 3.3 取出Session中的验证码数据
$captchaData = $_SESSION[$captchaConfig['session_key']];
// 3.4 校验验证码是否过期
if (time() > $captchaData['expire_time']) {
// 过期后立即销毁,防止复用
unset($_SESSION[$captchaConfig['session_key']]);
return ['status' => false, 'msg' => '验证码已过期,请刷新重试'];
}
// 3.5 校验验证码是否正确(统一转小写,不区分大小写)
if (strtolower(trim($userInput)) !== $captchaData['code']) {
// 校验失败立即销毁,防止破解
unset($_SESSION[$captchaConfig['session_key']]);
return ['status' => false, 'msg' => '验证码错误,请刷新重试'];
}
// 3.6 校验成功,立即销毁当前验证码,防止重放攻击(单次有效)
unset($_SESSION[$captchaConfig['session_key']]);
return ['status' => true, 'msg' => '验证码校验通过'];
}
// 4. 调用示例(用户POST提交表单时)
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// 获取用户输入的验证码
$userCaptcha = $_POST['captcha'] ?? '';
// 执行校验
$checkResult = checkCaptcha($userCaptcha);
if (!$checkResult['status']) {
// 校验失败,返回错误信息
echo json_encode(['code' => 400, 'msg' => $checkResult['msg']]);
exit;
}
// 校验通过,执行后续业务逻辑(登录、注册、发送短信等)
echo json_encode(['code' => 200, 'msg' => '操作成功']);
exit;
}
生产环境注意事项与安全规范
必须使用 HTTPS 传输:验证码接口和表单提交接口必须通过 HTTPS 传输,防止中间人窃取验证码图片和提交内容,规避重放攻击。
验证码存储安全:
- 生产环境严禁将验证码原始字符串返回给前端,必须仅存储在服务端 Session/Redis 中;
- 高并发场景建议使用 Redis 存储验证码,替代原生 Session,提升性能和分布式系统兼容性;
- 建议对存储的验证码进行不可逆加密,避免 Session/Redis 泄露导致验证码被破解。
用户体验与安全平衡:
- 字符集必须剔除易混淆的
0和O、1和l、2和Z等字符,减少用户输入错误; - 干扰线和噪点数量需合理,避免过度干扰导致用户无法识别;
- 必须实现不区分大小写校验,降低用户输入门槛。
防破解规范:
- 验证码必须单次有效,无论校验成功或失败,立即销毁,禁止重复使用;
- 同一 IP 短时间内多次获取验证码,需进行频率限制,防止验证码被批量抓取;
- 校验失败 3 次以上,必须强制刷新验证码,避免暴力枚举。
字体与资源规范:
- 必须使用开源免费字体,避免商用字体导致的版权风险;
- 建议使用多种字体随机切换,每个字符使用不同字体,大幅提升 OCR 识别难度;
- 字体文件路径建议使用绝对路径,避免相对路径导致的绘制失败。
输出规范:
- 必须设置禁止缓存的响应头,防止浏览器、CDN 缓存验证码图片,导致校验失败;
- 输出图片前必须清空输出缓冲区,避免框架输出的多余内容导致图片乱码;
- 图片输出后必须执行
imagedestroy()销毁画布资源,避免服务器内存泄漏。
严禁存储敏感信息:验证码仅用于人机校验,禁止在其中嵌入用户 ID、密码等敏感信息。
到此这篇关于使用PHP创建图像验证码的示例代码的文章就介绍到这了,更多相关PHP图像验证码内容请搜索IT俱乐部以前的文章或继续浏览下面的相关文章希望大家以后多多支持IT俱乐部!
