GD库生成验证码前必须确认三件事:GD扩展已启用且FreeType Support为true、中文支持所需libfreetype已加载、字体路径为服务器可读的绝对路径;否则90%以上会失败。

GD库生成验证码前必须确认的三件事
GD库没启用、中文支持缺失、字体文件路径错误——这三类问题占了90%以上的验证码失败案例。先执行 phpinfo() 查看 gd 模块是否启用,确认 FreeType Support 为 enabled;若需中文,还得检查 libfreetype 是否加载成功;字体路径必须用绝对路径,相对路径在Web环境下极易失效。
最简可用的数字验证码生成逻辑
不依赖session、不写入文件、直接输出PNG,适合快速验证GD是否正常工作:
<?php
header('Content-Type: image/png');
$im = imagecreatetruecolor(120, 40);
$bg = imagecolorallocate($im, 255, 255, 255);
imagefill($im, 0, 0, $bg);
$text = substr(str_shuffle('0123456789'), 0, 4);
$font_color = imagecolorallocate($im, 50, 50, 50);
// 注意:这里用系统自带的内置字体,避免路径问题
imagestring($im, 5, 10, 10, $text, $font_color);
imagepng($im);
imagedestroy($im);
?>
关键点:imagestring() 的第2个参数是字体大小(1–5),不能传字体文件路径;想换字体必须用 imagettftext(),但前提是FreeType已启用且字体路径正确。
使用imagettftext()显示中文或自定义字体时的坑
常见报错 Warning: imagettftext(): Could not find/open font 不一定是路径错,更可能是权限或编码问题:
立即学习“PHP免费学习笔记(深入)”;
- 字体文件路径必须是服务器可读的绝对路径,例如
/var/www/fonts/msyh.ttc,不能是./fonts/msyh.ttc - PHP进程用户(如www-data)需对字体文件有读取权限,
chmod 644比755更安全 - 中文字符串必须是UTF-8编码,若来自数据库或POST,先用
mb_convert_encoding($str, 'UTF-8', 'auto')转码 -
imagettftext()的Y坐标是基线位置,不是顶部,通常要设为字体大小的1.2–1.4倍才视觉居中
验证码与Session联动的实际写法
单纯生成图没用,得把验证码值存到Session供后续校验。注意两点:输出图像前不能有任何输出(包括空格、BOM),且Session必须提前开启:
<?php
session_start();
header('Content-Type: image/png');
$_SESSION['captcha'] = substr(str_shuffle('0123456789abcdefghijklmnopqrstuvwxyz'), 0, 4);
// 后续同上创建图像...
?>
容易被忽略的是:如果验证码页面被缓存(比如Nginx默认缓存图片),用户刷新时看到的还是旧图,但Session里已是新值。务必加缓存控制头:header('Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0'); 和 header('Pragma: no-cache');



















