这几天经常有不明来路的机器人注册账号,于是增加了注册时的验证码。
启用 Session 会话
WordPress 核心在未登录状态下通常不开启 PHP 原生 Session,但我们需要它来在服务器端存储生成的验证码,以便在提交表单时进行比对。
if (!session_id()) {
session_start();
}
初始化 $_SESSION 数组。
验证拦截
在数据写入数据库之前,必须拦截注册流程。如果验证码错误,阻止 register_new_user 函数的执行。
在 case ‘register’ : 代码块 if($http_post) 内,处理用户名和邮箱获取后。
if (!isset($_SESSION['wp_register_captcha']) || !isset($_POST['captcha_code']) || strtoupper($_POST['captcha_code']) != = $_SESSION['wp_register_captcha']) {
$errors = new WP_Error('captcha_error', __('<strong>Error</strong>: Incorrect verification code.'));
} else {
$errors = register_new_user($user_login, $user_email);
}
- 检查 $_SESSION[‘wp_register_captcha’] 是否存在。
- 检查用户提交的 $_POST[‘captcha_code’] 是否存在。
- 使用 strtoupper() 将用户输入转为大写,与 Session 中的验证码进行恒等比较。
- 如果比对失败,实例化一个新的 WP_Error 对象,错误代码为 captcha_error。这会中断后续流程,并将错误信息传回前端显示。
- 如果比对成功,才执行原有的 register_new_user( $user_login, $user_email )。
图片生成
直接在 wp-login.php 内部生成图片流,并以 Base64 编码内嵌到 HTML 中。
定义字符集 ABCDEFGHJKLMNPQRSTUVWXYZ23456789 ,移除了 0, O, 1, I 等容易混淆的字符,用 str_shuffle 打乱字符集,取前 5 位为验证码,将结果存入 $_SESSION[‘wp_register_captcha’] 。
用 PHP 的 GD 图形库绘制图片。
- 创建画布: imagecreatetruecolor(100, 36) 创建真彩色画布。
- 噪点与干扰线:
- 噪点: 循环 1000 次,随机在画布上画点 (imagesetpixel)。
- 干扰线: 循环 20 次,随机画横跨画布的线条 (imageline)。
- 文字写入: 使用 imagestring 将随机字符写入图片。
- 居中计算: 通过 imagefontwidth 和 imagefontheight 动态计算文字坐标 (x, y),确保文字居中。
$chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789';
$captcha_code = substr(str_shuffle($chars), 0, 5);
$_SESSION['wp_register_captcha'] = $captcha_code;
$captcha_image_html = '';
// 尝试使用 GD 库生成图片验证码
if (extension_loaded('gd') && function_exists('imagecreatetruecolor')) {
$width = 100;
$height = 36;
$im = imagecreatetruecolor($width, $height);
// 颜色定义
$bg = imagecolorallocate(
$im,
rand(230, 255),
rand(230, 255),
rand(230, 255));
$text_color = imagecolorallocate(
$im,
rand(100, 200),
rand(100, 200),
rand(100, 200));
$line_color = imagecolorallocate(
$im,
rand(150, 200),
rand(150, 200),
rand(150, 200));
$pixel_color = imagecolorallocate(
$im,
rand(180, 220),
rand(180, 220),
rand(180, 220));
imagefill($im, 0, 0, $bg);
// 干扰点
for ($i = 0; $i < 1000; $i++) {
imagesetpixel($im, rand(0, $width), rand(0, $height), $pixel_color);
}
// 干扰线
for ($i = 0; $i < 20; $i++) {
imageline($im, rand(0, $width), rand(0, $height), rand(0, $width), rand(0, $height), $line_color);
}
// 写入文字
$font_size = 5;
$x = ($width - (imagefontwidth($font_size) * strlen($captcha_code))) / 2;
$y = ($height - imagefontheight($font_size)) / 2;
imagestring($im, $font_size, $x, $y, $captcha_code, $text_color);
// 输出图片流并转为 Base64
ob_start();
imagepng($im);
$image_data = ob_get_clean();
imagedestroy($im);
$base64_src = 'data:image/png;base64,'.base64_encode($image_data);
$captcha_image_html = '<img src="'.$base64_src.'" alt="验证码" style="vertical-align:middle; border: 1px solid #ddd; cursor:pointer;" title="Verification Code" />';
} else {
// 如果不支持 GD 库
$captcha_image_html = '<span style="background:#eee; padding:5px 10px; font-weight:bold; letter-spacing: 3px; border:1px solid #ccc;">'.esc_html($captcha_code).'</span>';
}