
本文介绍如何在 wordpress 的 php 环境中,通过 session 实现“仅放行特定 post 请求(如 captcha 验证),其余 get/post 请求暂存待命”的轻量级请求调度方案,无需修改 apache 配置或依赖外部锁服务。
本文介绍如何在 wordpress 的 php 环境中,通过 session 实现“仅放行特定 post 请求(如 captcha 验证),其余 get/post 请求暂存待命”的轻量级请求调度方案,无需修改 apache 配置或依赖外部锁服务。
在开发 WordPress CAPTCHA 插件时,一个关键需求是:必须确保用户提交的 CAPTCHA 验证请求(如 $_POST['myRequest'])被绝对优先、串行化处理,而其他并发的表单提交或页面请求应被“逻辑挂起”,待 CAPTCHA 验证成功后再按序恢复执行。由于 PHP 是无状态、每次请求独立运行的脚本环境,无法直接“暂停其他 HTTP 请求”——sleep() 只会阻塞当前请求线程,对其他用户或同一用户的其他请求完全无效。因此,真正的解法不是“阻塞”,而是“重定向 + 暂存 + 延迟重放”。
核心思路是:利用 PHP Session 作为跨请求协调媒介,构建一个轻量级的“请求队列守门员”机制:
- 当检测到 $_POST['myRequest'](即 CAPTCHA 提交)时,立即设置一个 Session 锁标记(如 $_SESSION['.my-request.lock']),并立即执行 CAPTCHA 验证逻辑;
- 若当前请求不是 myRequest,但已存在该锁标记,则说明 CAPTCHA 尚未完成——此时不执行业务逻辑,而是将当前完整的 $_REQUEST 数据序列化后暂存至 Session(如 $_SESSION['my-data.json']),然后返回一个轻量响应(如 202 Accepted 或前端轮询提示);
- CAPTCHA 验证成功后,清除锁标记,并检查是否存在待处理请求数据;如有,则反序列化并模拟原始请求上下文(需谨慎设计后续路由或回调),或更推荐的做法:重定向用户至原目标 URL 并附带一次性令牌,由主流程识别并恢复执行。
以下是可直接集成到 WordPress 插件入口或 functions.php 中的健壮实现(兼容 PHP 7.4 + Apache):
<?php
// ⚠️ 必须在任何输出前启动 Session(WordPress 中建议在 'init' 钩子后调用)
if (session_status() === PHP_SESSION_NONE) {
session_start();
}
// 定义锁键与数据键(以点开头避免与用户 Session 冲突)
$lock_key = '.captcha_request_lock';
$data_key = 'pending_request_data';
// 仅对非 AJAX、非 WP-Admin 的前台请求启用(根据实际场景调整)
if (!defined('DOING_AJAX') && !is_admin() && ($_SERVER['REQUEST_METHOD'] === 'POST' || $_SERVER['REQUEST_METHOD'] === 'GET')) {
// 场景1:CAPTCHA 请求已到达 → 获取锁并立即处理
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['myRequest'])) {
$_SESSION[$lock_key] = true;
// ✅ 执行你的 CAPTCHA 验证逻辑(例如:校验答案、防重放、记录日志)
$captcha_valid = validate_captcha($_POST['captcha_answer'] ?? '');
if ($captcha_valid) {
// 验证成功:清理锁,触发后续流程
unset($_SESSION[$lock_key]);
// 可选:恢复暂存的请求(见下方说明)
restore_pending_request();
// 返回成功响应(JSON 或重定向)
wp_send_json_success(['message' => 'CAPTCHA passed']);
} else {
wp_send_json_error(['message' => 'Invalid CAPTCHA']);
}
exit;
}
// 场景2:存在锁,但当前不是 CAPTCHA 请求 → 暂存并告知等待
if (isset($_SESSION[$lock_key])) {
// 序列化当前请求(排除敏感字段如密码,生产环境务必过滤!)
$safe_request = array_diff_key($_REQUEST, ['password', 'pwd', 'pass']);
$_SESSION[$data_key] = json_encode($safe_request);
// 返回轻量响应,避免阻塞连接(前端可轮询或显示“验证中”)
header('HTTP/1.1 202 Accepted');
echo json_encode(['status' => 'pending', 'reason' => 'captcha_validation_in_progress']);
exit;
}
}
/**
* 恢复暂存请求(供 CAPTCHA 成功后调用)
* 注意:此处不直接执行,而是建议重定向至原 URL + token,由主逻辑识别处理
*/
function restore_pending_request() {
global $data_key;
if (isset($_SESSION[$data_key])) {
$pending = json_decode($_SESSION[$data_key], true);
if ($pending) {
// 方案A(推荐):生成一次性 token,重定向到原路径
$token = bin2hex(random_bytes(16));
$_SESSION["restore_{$token}"] = $pending;
wp_safe_redirect(add_query_arg('restore_token', $token, $_SERVER['REQUEST_URI']));
exit;
}
unset($_SESSION[$data_key]);
}
}✅ 关键注意事项:
立即学习“PHP免费学习笔记(深入)”;
- Session 安全性:确保 session_start() 在输出前调用;生产环境应配置 session.cookie_httponly=1 和 session.cookie_secure=1(HTTPS 下);
- 数据清理:Session 中暂存的数据需设置过期时间(如 $_SESSION['expire_time'] = time() + 300),避免长期占用内存;
- 竞态规避:本方案基于 Session 锁,适用于单服务器部署;若为集群环境,需改用 Redis 或数据库分布式锁;
- 用户体验:前端应配合实现加载状态与超时重试(例如 30 秒未响应则提示“验证超时,请重试”);
- WordPress 集成建议:将上述逻辑封装为独立函数,在 template_redirect 或自定义 REST API endpoint 中调用,避免干扰核心流程。
该方案不修改 Web 服务器行为,纯 PHP 实现,兼顾安全性、可维护性与 WordPress 兼容性,是 CAPTCHA 类插件实现请求优先级控制的成熟实践路径。











