根本原因是PHP未正确声明Content-Type且存在前置输出;必须在imagejpeg()前调用header('Content-Type: image/jpeg'),且确保无空格、BOM、echo等任何前置输出,文件须为UTF-8无BOM编码。

为什么直接用 imagejpeg() 输出验证码会失败
常见现象是浏览器显示一片空白,或者弹出下载对话框,而不是正常显示图片。根本原因是 PHP 脚本没有正确声明输出内容类型,浏览器不知道接收到的是 JPG 图片,于是按文本或未知类型处理。
必须在调用 imagejpeg() 前,用 header('Content-Type: image/jpeg') 明确告知浏览器 MIME 类型;且该 header() 不能有任何前置输出(包括空格、BOM、echo、print),否则会报 “Headers already sent” 错误。
- 确保 PHP 文件保存为 UTF-8 无 BOM 格式
- 文件开头不能有空行或
<?php前的任何字符 - 不要在
header()前做任何输出(含error_reporting(E_ALL)触发的警告)
生成带干扰线和扭曲字母的 JPG 验证码
PHP GD 库支持直接绘制文字和线条,但默认字体不支持中文,且纯 imagestring() 画出的字母太规整、易被 OCR 识别。需手动控制坐标、旋转和噪点。
关键操作顺序:创建画布 → 填充背景色 → 绘制干扰线 → 逐个写入随机字母(带小角度旋转)→ 添加少量噪点 → 输出 JPG。
立即学习“PHP免费学习笔记(深入)”;
session_start();
$width = 120;
$height = 40;
$image = imagecreatetruecolor($width, $height);
$bg = imagecolorallocate($image, 245, 245, 245);
imagefill($image, 0, 0, $bg);
// 干扰线
for ($i = 0; $i < 3; $i++) {
$line_color = imagecolorallocate($image, mt_rand(180, 220), mt_rand(180, 220), mt_rand(180, 220));
imageline($image, mt_rand(0, $width), mt_rand(0, $height), mt_rand(0, $width), mt_rand(0, $height), $line_color);
}
// 验证码字母(去掉易混淆的 I、O、0、l)
$chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789';
$code = '';
for ($i = 0; $i < 4; $i++) {
$char = $chars[mt_rand(0, strlen($chars)-1)];
$code .= $char;
$text_color = imagecolorallocate($image, mt_rand(50, 150), mt_rand(50, 150), mt_rand(50, 150));
// 小角度旋转,避免整齐排列
$angle = mt_rand(-15, 15);
imagettftext($image, 16, $angle, 25 + $i*22, 28, $text_color, 'arial.ttf', $char);
}
$_SESSION['captcha'] = $code;
header('Content-Type: image/jpeg');
imagejpeg($image);
imagedestroy($image);
注意:imagettftext() 依赖系统中存在 TrueType 字体(如 arial.ttf),Linux 下路径常为 /usr/share/fonts/truetype/dejavu/DejaVuSans.ttf,Windows 下可能是 C:/Windows/Fonts/arial.ttf;路径错误会导致文字不显示且无报错。
浏览器缓存导致验证码不刷新
用户点击“换一张”时,图片 URL 没变(比如固定为 /captcha.php),浏览器直接从缓存取旧图,看起来验证码没变化。
解决方法是在 img 标签的 src 后加时间戳或随机参数,强制绕过缓存:
<img src="captcha.php?r=<?php echo time(); ?>" alt="验证码">
或者前端用 JS 点击时动态更新:
document.getElementById('captcha-img').src = 'captcha.php?r=' + Math.random();
后端无需改逻辑,但务必确保 captcha.php 不输出任何额外字符(包括末尾空行),否则 JPG 数据流会被破坏,显示为损坏图片。
GD 扩展未启用或不支持 JPG
运行时出现 Call to undefined function imagejpeg(),说明 PHP 编译时未启用 GD 扩展,或启用了但禁用了 JPG 支持。
检查方式:
- 运行
php -m | grep gd看是否列出gd - 执行
php -r "var_dump(gd_info());",确认jpeg字段为true
常见修复路径:
- Ubuntu/Debian:
sudo apt install php-gd,然后重启 web 服务 - CentOS/RHEL:
sudo yum install php-gd或dnf install php-gd - Windows:取消
php.ini中;extension=gd的分号,并确认extension=php_gd2.dll存在且路径正确
如果服务器不允许开启 GD(如某些共享主机),只能改用 base64 内嵌 PNG(用 imagepng() + base64_encode()),但 JPG 在同等质量下体积更小,更适合验证码场景。



















