
在 wordpress 自定义插件中生成 captcha 图像时,直接使用 header('content-type: image/png') 会导致输出冲突(因 wordpress 已发送 http 头),本文提供安全、兼容的 base64 内联图像方案,无需外部 php 文件,避免 headers already sent 错误。
在 WordPress 环境中动态生成图像(如 CAPTCHA)时,绝不可通过独立 PHP 脚本(如 CAPTCHA-generate-image.php)配合 直接调用——这不仅破坏 WordPress 的请求生命周期,还会因未加载 WP 核心环境导致会话异常、路径错误、字体加载失败,更关键的是:WordPress 主题或插件可能已在图像脚本执行前输出了 HTML/空格/UTF-8 BOM,导致 headers already sent 错误,使 PNG 输出损坏,浏览器显示“破损图像”。
✅ 正确做法是:在插件方法内完成图像创建 → 写入内存缓冲区 → 编码为 Base64 → 内联嵌入 HTML 的 src 属性。全程不发送原始 HTTP 头,完全规避输出冲突。
以下是推荐的重构实现(整合进你的插件类中):
/**
* 生成 CAPTCHA 图像并返回 PNG 二进制数据(Base64 就绪)
*/
public function CAPTCHA_generate() {
session_start();
$permitted_chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ';
$string_length = 6;
$captcha_string = $this->generate_string($permitted_chars, $string_length);
$_SESSION['captcha_text'] = $captcha_string;
// 创建画布
$image = imagecreatetruecolor(200, 50);
imageantialias($image, true);
// 背景渐变色
$red = rand(125, 175);
$green = rand(125, 175);
$blue = rand(125, 175);
$colors = [];
for ($i = 0; $i < 5; $i++) {
$colors[] = imagecolorallocate($image, $red - 20 * $i, $green - 20 * $i, $blue - 20 * $i);
}
imagefill($image, 0, 0, $colors[0]);
// 绘制干扰矩形
for ($i = 0; $i < 10; $i++) {
imagesetthickness($image, rand(2, 10));
$line_color = $colors[rand(1, 4)];
imagerectangle($image, rand(-10, 190), rand(-10, 10), rand(-10, 190), rand(40, 60), $line_color);
}
// 文字颜色与字体
$black = imagecolorallocate($image, 0, 0, 0);
$white = imagecolorallocate($image, 255, 255, 255);
$textcolors = [$black, $white];
// ✅ 关键:确保字体路径为绝对路径(推荐放在插件目录下,如 /fonts/Acme.ttf)
$font_path = plugin_dir_path(__FILE__) . 'fonts/Acme.ttf';
if (!file_exists($font_path)) {
error_log('CAPTCHA font not found: ' . $font_path);
return '';
}
// 绘制验证码文字
for ($i = 0; $i < $string_length; $i++) {
$letter_space = 170 / $string_length;
$initial = 15;
imagettftext(
$image, 24, rand(-15, 15),
$initial + $i * $letter_space, rand(25, 45),
$textcolors[rand(0, 1)], $font_path, $captcha_string[$i]
);
}
// ✅ 核心修正:不输出 header,改用内存流生成 PNG 数据
ob_start();
imagepng($image);
$png_data = ob_get_clean();
imagedestroy($image);
return $png_data;
}
/**
* 辅助函数:生成随机字符串
*/
private function generate_string($input, $strength = 10) {
$input_length = strlen($input);
$random_string = '';
for ($i = 0; $i < $strength; $i++) {
$random_character = $input[mt_rand(0, $input_length - 1)];
$random_string .= $random_character;
}
return $random_string;
}
/**
* 短代码输出函数(含 CAPTCHA 图像)
*/
public function CAPTCHA_shortcode_function() {
ob_start();
$png_data = $this->CAPTCHA_generate();
if (empty($png_data)) {
echo 'CAPTCHA generation failed. Check font path and GD extension.';
} else {
?>
@@##@@"
alt="CAPTCHA verification code"
width="200" height="50">
? 关键注意事项与最佳实践:
- 禁止外部 PHP 图像脚本:CAPTCHA-generate-image.php 在 WordPress 中不可靠;它绕过 WP 生命周期,易引发会话失效(session_start() 位置错乱)、路径错误、安全风险(未校验 nonce 或权限)。
- 字体路径必须绝对且可读:使用 plugin_dir_path(__FILE__) . 'fonts/Acme.ttf',并提前验证文件存在(file_exists()),否则 imagettftext() 静默失败。
- GD 扩展必需启用:确保服务器已安装并启用 PHP GD 库(含 FreeType 支持),可通过 extension_loaded('gd') && function_exists('imagettftext') 检查。
- Base64 安全转义:务必使用 esc_attr() 包裹 base64_encode() 结果,防止 XSS(尽管 data URL 本身较安全,但属防御性编码规范)。
- 会话管理需统一:确保整个插件流程(生成、验证、销毁)均在 session_start() 后操作,并建议在插件激活时检查 session 是否可用。
-
移动端适配:为










