PHP8.5环境下生成验证码出现乱码是开发中比较常见的问题,尤其是字体相关的乱码会直接影响用户识别,需要从多个维度排查原因并解决。

常见乱码原因分析
验证码乱码通常分为两类,一类是字符本身编码错误导致的乱码,另一类是字体加载异常导致的显示乱码,具体诱因如下:
- GD库未正确安装或者版本不兼容PHP8.5,导致绘图函数无法正常执行
- 指定的字体文件路径错误,或者字体文件本身损坏,PHP无法加载字体渲染字符
- 输出验证码的字符编码和HTML页面编码不一致,比如PHP输出UTF-8但页面是GBK编码
- PHP8.5对部分GD库函数的参数校验更严格,旧版代码未适配导致渲染异常
- 没有正确设置HTTP响应头,浏览器无法识别返回的内容是图片类型
基础验证码生成代码(无字体版)
先给出不使用自定义字体的基础验证码生成代码,这种方式如果还出现乱码,大概率是编码或者响应头的问题:
<?php
// 设置响应头为图片类型
header('Content-Type: image/png');
// 创建画布,宽120px,高40px
$img = imagecreatetruecolor(120, 40);
// 分配背景色(白色)
$bgColor = imagecolorallocate($img, 255, 255, 255);
// 填充背景
imagefill($img, 0, 0, $bgColor);
// 分配文字颜色(黑色)
$textColor = imagecolorallocate($img, 0, 0, 0);
// 生成4位随机验证码字符,使用内置字体
$code = '';
for ($i = 0; $i < 4; $i++) {
$code .= rand(0, 9);
}
// 将验证码存入session,方便后续验证
session_start();
$_SESSION['captcha'] = $code;
// 使用内置字体1绘制文字,位置x=20,y=10
imagestring($img, 1, 20, 10, $code, $textColor);
// 输出图片
imagepng($img);
// 销毁画布释放资源
imagedestroy($img);
?>
自定义字体验证码乱码解决方法
如果使用自定义字体后出现乱码,按照下面的步骤逐一排查:
1. 确认字体文件路径正确
首先要保证字体文件存在且路径可访问,推荐使用绝对路径,避免相对路径解析错误。如果是Windows环境,字体文件可以放在项目根目录的fonts文件夹下,比如simhei.ttf黑体文件。
2. 检查GD库是否支持TrueType字体
PHP需要开启gd扩展且支持TrueType字体,可以通过phpinfo()查看GD库的配置,确认FreeType Support显示为enabled。
3. 适配PHP8.5的参数要求
PHP8.5中imagettftext()函数的参数要求更严格,字体路径必须是字符串,且字符编码需要统一为UTF-8,下面是适配PHP8.5的自定义字体验证码代码:
<?php
// 开启session
session_start();
// 设置响应头为PNG图片
header('Content-Type: image/png');
// 画布尺寸
$width = 160;
$height = 50;
// 创建画布
$img = imagecreatetruecolor($width, $height);
// 背景色(浅灰色)
$bg = imagecolorallocate($img, 240, 240, 240);
imagefill($img, 0, 0, $bg);
// 生成4位随机验证码,包含数字和字母
$charList = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$code = '';
for ($i = 0; $i < 4; $i++) {
$code .= $charList[rand(0, strlen($charList) - 1)];
}
// 存储验证码到session
$_SESSION['captcha'] = $code;
// 字体文件路径,使用绝对路径,确保文件存在
$fontPath = __DIR__ . '/fonts/simhei.ttf';
// 检查字体文件是否存在
if (!file_exists($fontPath)) {
die('字体文件不存在');
}
// 绘制每个字符,避免字符重叠
for ($i = 0; $i < 4; $i++) {
// 随机文字颜色
$textColor = imagecolorallocate($img, rand(0, 120), rand(0, 120), rand(0, 120));
// 随机字体大小
$fontSize = rand(20, 28);
// 随机角度
$angle = rand(-15, 15);
// 字符x坐标,依次排列
$x = 20 + $i * 30;
// 字符y坐标,随机偏移
$y = rand(30, 40);
// 调用imagettftext绘制字符,注意字符编码为UTF-8
imagettftext($img, $fontSize, $angle, $x, $y, $textColor, $fontPath, $code[$i]);
}
// 添加干扰线
for ($i = 0; $i < 3; $i++) {
$lineColor = imagecolorallocate($img, rand(150, 255), rand(150, 255), rand(150, 255));
imageline($img, rand(0, $width), rand(0, $height), rand(0, $width), rand(0, $height), $lineColor);
}
// 添加干扰点
for ($i = 0; $i < 50; $i++) {
$pixelColor = imagecolorallocate($img, rand(0, 255), rand(0, 255), rand(0, 255));
imagesetpixel($img, rand(0, $width), rand(0, $height), $pixelColor);
}
// 输出图片
imagepng($img);
// 销毁画布
imagedestroy($img);
?>
4. 统一页面编码
调用验证码的HTML页面需要设置编码为UTF-8,避免浏览器解析编码错误:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>验证码测试</title>
</head>
<body>
<img src="captcha.php" alt="验证码">
</body>
</html>
其他注意事项
如果以上步骤都排查后还是乱码,可以尝试以下操作:
- 更换其他字体文件测试,排除字体文件本身损坏的问题
- 检查PHP8.5的错误日志,查看是否有GD库相关的报错信息
- 确认服务器上字体文件的读取权限,避免PHP没有权限读取字体文件
- 如果使用Docker等容器环境,需要确认容器内已经安装了对应的字体文件
注意:PHP8.5对部分废弃的GD库函数做了移除或者修改,尽量不要使用太旧的验证码生成代码,优先适配新版本的函数参数要求。