C++ & WordPress: 使用C++与PHP完成WordPress站点的用户密码校验

C++ & WordPress: 使用C++与PHP完成WordPress站点的用户密码校验

来自AI助手的总结
在WordPress站点中,通过创建一个PHP服务器与C++客户端实现用户密码验证,保障数据库安全和用户信息的正确性。

方案:

在WordPress站点(后文简称:WP站点),如果想使用C++进行用户的验证的话,需要去复原加密算法,才能尝试去匹配数据库中的密码哈希值。

在6.8版本后的WP,密码加密算法被更新了,所以博主设计了一下方案:

思路:

使用TCP协议,创建一个PHP Server,数据交互使用JSON进行。PHP Server来负责验证用户,且端口可以不对外开放,保证了安全。

C++部分,同样也使用TCP协议。但是作为客户端,将数据铭文转发到PHP Server即可。再将PHP Server回送的数据解析就行。

实现:

PHP:

#!/usr/bin/env php
<?php
/**
 * WordPress 密码验证 TCP 服务器
 * 用法: php wp_auth_server.php [port] [wordpress_path]
 * 示例: php wp_auth_server.php 9001 /www/wwwroot/wordpress
 */

set_time_limit(0);
error_reporting(E_ERROR);
ini_set('display_errors', 'stderr');

// 配置
$port = $argv[1] ?? 9001;
$wp_path = $argv[2] ?? findWordPress();
$bind_address = '0.0.0.0';

if (!$wp_path || !file_exists($wp_path . '/wp-load.php')) {
    die("错误: 无法找到 WordPress 目录,请指定路径\n用法: php {$argv[0]} [port] [/path/to/wordpress]\n");
}

echo "正在启动 WordPress 密码验证服务器...\n";
echo "WordPress 路径: $wp_path\n";
echo "监听地址: $bind_address:$port\n";

// 加载 WordPress(不加载主题,加速启动)
define('WP_USE_THEMES', false);
require_once $wp_path . '/wp-load.php';
echo "WordPress 加载完成 (版本: " . get_bloginfo('version') . ")\n";

// 创建 socket
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if (!$socket) {
    die("Socket 创建失败: " . socket_strerror(socket_last_error()) . "\n");
}

// 允许地址重用
socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1);

// 绑定地址
if (!socket_bind($socket, $bind_address, $port)) {
    die("绑定失败: " . socket_strerror(socket_last_error($socket)) . "\n");
}

// 监听
if (!socket_listen($socket, 10)) {
    die("监听失败: " . socket_strerror(socket_last_error($socket)) . "\n");
}

echo "服务器已启动,等待连接...\n";

// 信号处理(优雅关闭)
if (function_exists('pcntl_signal')) {
    pcntl_signal(SIGTERM, function() use ($socket) {
        echo "\n收到关闭信号,正在停止...\n";
        socket_close($socket);
        exit(0);
    });
    pcntl_signal(SIGINT, function() use ($socket) {
        echo "\n收到中断信号,正在停止...\n";
        socket_close($socket);
        exit(0);
    });
}

// 查找 WordPress 的辅助函数
function findWordPress() {
    $current = getcwd();
    // 向上查找 5 层目录
    for ($i = 0; $i < 5; $i++) {
        if (file_exists($current . '/wp-load.php')) {
            return $current;
        }
        if (file_exists($current . '/wordpress/wp-load.php')) {
            return $current . '/wordpress';
        }
        if (file_exists($current . '/www/wwwroot/wordpress/wp-load.php')) {
            return $current . '/www/wwwroot/wordpress';
        }
        $current = dirname($current);
    }
    return null;
}

// 验证用户
function verifyUser($username, $password) {
    $user = get_user_by('login', $username);
    if (!$user) {
        $user = get_user_by('email', $username);
    }
    
    if (!$user) {
        return ['success' => false, 'error' => '用户不存在'];
    }
    
    // 使用 WordPress 的验证函数(自动处理 $wp$ 前缀)
    $valid = wp_check_password($password, $user->user_pass, $user->ID);
    
    if ($valid) {
        return [
            'success' => true,
            'user_id' => $user->ID,
            'user_login' => $user->user_login,
            'user_email' => $user->user_email,
            'display_name' => $user->display_name
        ];
    } else {
        return ['success' => false, 'error' => '密码错误'];
    }
}

// 主循环
while (true) {
    // 处理信号(如果可用)
    if (function_exists('pcntl_signal_dispatch')) {
        pcntl_signal_dispatch();
    }
    
    // 接受连接
    $client = socket_accept($socket);
    if (!$client) {
        continue;
    }
    
    // 读取数据
    $input = '';
    while ($buf = socket_read($client, 2048, PHP_NORMAL_READ)) {
        $input .= $buf;
        if (strpos($input, "\n") !== false) break;
    }
    
    $input = trim($input);
    
    if (empty($input)) {
        socket_write($client, json_encode(['error' => '空请求']) . "\n");
        socket_close($client);
        continue;
    }
    
    // 解析 JSON
    $request = json_decode($input, true);
    if (!$request || !isset($request['action'])) {
        $response = ['error' => '无效请求格式'];
    } else {
        // 处理请求
        switch ($request['action']) {
            case 'verify':
                if (empty($request['username']) || empty($request['password'])) {
                    $response = ['success' => false, 'error' => '缺少用户名或密码'];
                } else {
                    $response = verifyUser($request['username'], $request['password']);
                }
                break;
                
            case 'ping':
                $response = ['status' => 'ok', 'wordpress_version' => get_bloginfo('version')];
                break;
                
            default:
                $response = ['error' => '未知操作: ' . $request['action']];
        }
    }
    
    // 发送响应
    $output = json_encode($response) . "\n";
    socket_write($client, $output);
    socket_close($client);
}

socket_close($socket);

c++:

头文件:

#pragma once

/*
# 使用
 - 先获取一个实例指针
 - 启动WPAuthClient(startWPAuthClient客户端)
 - 停止客户端调用:stopWPAuthClient()函数
 - 验证用户必须使用账户名验证,参数参阅实现的.Cpp文件

*/
#include "../../nlohmann/json.hpp"
#include "../../log4cpp/log4mini.h"

#include <iostream>
#include <string>
#include <cstring>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>
#include <future>
#include <atomic>
#include <utility>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>



class WPAuthClient {

public:
    // 获取单例
    static WPAuthClient* getInstance(const std::string& host = "127.0.0.1", int port = 9001);
    
    // 启动WPAuth客户端
    void startWPAuthClient();
    
    // 停止WPAuth客户端
    void stopWPAuthClient();
    
    // 验证用户与密码
    bool verifyUserPassword(const std::string& username, const std::string& password, nlohmann::json& userInfo);

private:

    // 构造函数
    WPAuthClient() = default;
    
    WPAuthClient(const std::string& host, int port);

    // 析构函数
    ~WPAuthClient();

    // 禁用拷贝
    WPAuthClient(const WPAuthClient&) = delete;
    WPAuthClient& operator=(const WPAuthClient&) = delete;

    // 工作循环
    void workerLoop();
    
    // 确保连接
    bool ensureConnected();
    
    // 验证执行
    nlohmann::json doVerify(const nlohmann::json& request);

private:

    static WPAuthClient* instance_;     // 获取实例
    static std::mutex instance_mutex_;  // 实例锁
    
    std::string m_host; // 主机地址
    int m_port;         // 监听端口
    int m_sock;         // socket
    std::mutex m_sock_mutex;  // 保护 socket 操作
    
    std::thread m_worker_thread;    // 工作线程
    std::queue<std::pair<nlohmann::json, std::promise<nlohmann::json> > > m_task_queue;   // 任务队列
    std::mutex m_queue_mutex;                   // 队列锁,保护队列
    std::condition_variable m_cv;               // 条件变量
    std::atomic<bool> m_is_running{false};      // 原子类型,判断线程是否在运行
};

源文件:

#include "WPAuth.h"
// 静态成员定义
WPAuthClient* WPAuthClient::instance_ = nullptr;
std::mutex WPAuthClient::instance_mutex_;

/*
 ============================================================================
 Function: getInstance
 Description: 获取WPAuthClient单例
 Parameters:
     - std::string: 主机信息
     - int: 监听地址
 Return: 返回一个WPAuthClient指针
 ============================================================================
*/
WPAuthClient* WPAuthClient::getInstance(const std::string& host, int port)
{
    if (instance_ == nullptr) 
    {
        std::lock_guard<std::mutex> lock(instance_mutex_);
        if (instance_ == nullptr) 
        {
            instance_ = new WPAuthClient(host, port);
        }
    }
    return instance_;
}

/*
 ============================================================================
 Function: startWPAuthClient
 Description: 启动WPAuth客户端
 Parameters:
     - 无参数: 无释义
 Return: 无返回值
 ============================================================================
*/
void WPAuthClient::startWPAuthClient()
{
    if(this->m_is_running)
    {
        Log4Warn("WPAuthClient is already running");
        return;
    }

    // 设置运行状态
    this->m_is_running = true;
    this->m_worker_thread = std::thread(&WPAuthClient::workerLoop, this);
    
    return;
}

/*
 ============================================================================
 Function: stopWPAuthClient
 Description: 停止WPAuth客户端
 Parameters:
     - 无参数: 无释义
 Return: 无返回值
 ============================================================================
*/
void WPAuthClient::stopWPAuthClient()
{
    if(this->m_is_running)
    {
        this->m_is_running = false;
        this->m_cv.notify_all();
        if (this->m_worker_thread.joinable()) 
        {
            this->m_worker_thread.join();
        }
        if (this->m_sock >= 0) 
        {
            close(this->m_sock);
            this->m_sock = -1;
        }
    }
}

/*
 ============================================================================
 Function: verifyUserPassword
 Description: 验证用户密码
 Parameters:
     - const std::string&: 一个字符串,用户名
     - const std::string&: 一个字符串,用户密码明文
     - nlohmann::json&: 作为返回值使用,记录错误信息或者是用户信息
 Return: 用户密码正确返回true,否则返回false,且参数三用于记录验证的详细信息
 ============================================================================
*/
bool WPAuthClient::verifyUserPassword(const std::string& username, const std::string& password, nlohmann::json& userInfo)
{
    nlohmann::json request = {
        {"action", "verify"},
        {"username", username},
        {"password", password}
    };
        
    // 创建 promise-future 用于获取异步结果
    std::promise<nlohmann::json> promise;
    std::future<nlohmann::json> future = promise.get_future();
    
    {
        std::lock_guard<std::mutex> lock(this->m_queue_mutex);
        this->m_task_queue.emplace(request, std::move(promise));
    }

    // 唤醒工作线程
    this->m_cv.notify_one();
    
    // 等待结果(超时10s)
    if (future.wait_for(std::chrono::seconds(10)) == std::future_status::timeout) 
    {
        return false;
    }

    nlohmann::json response = future.get();
    userInfo = response;
    if (response.value("success", false))
    {
        return true;
    }
    return false;
}

/*
 ============================================================================
 Function: PAuthClient
 Description: 构造函数
 Parameters:
     - const std::string&: 一个字符串,主机地址
     - int: 监听端口
 Return: 无返回值
 ============================================================================
*/
WPAuthClient::WPAuthClient(const std::string& host, int port) : 
    m_host(host),
    m_port(port),
    m_sock(-1)
{
}

/*
 ============================================================================
 Function: ~WPAuthClient
 Description: 析构函数
 Parameters:
     - 无参数: 无释义
 Return: 无返回值
 ============================================================================
*/
WPAuthClient::~WPAuthClient()
{
    WPAuthClient::stopWPAuthClient();
}

/*
 ============================================================================
 Function: workerLoop
 Description: 工作循环
 Parameters:
     - 无参数: 无释义
 Return: 无返回值
 ============================================================================
*/
void WPAuthClient::workerLoop()
{
    while (this->m_is_running) 
    {
        std::unique_lock<std::mutex> lock(this->m_queue_mutex);

        // 等待任务队列非空
        this->m_cv.wait(lock, [this] { 
            return !this->m_task_queue.empty() || !this->m_is_running; 
        });
        
        if (!this->m_is_running) 
            break;
        
        std::pair<nlohmann::json, std::promise<nlohmann::json> > task = std::move(this->m_task_queue.front());
        this->m_task_queue.pop();
        lock.unlock();
        
        // 执行验证
        nlohmann::json result = doVerify(task.first);
        task.second.set_value(result);
    }
}

/*
 ============================================================================
 Function: ensureConnected
 Description: 确认是否已经连接验证服务器
 Parameters:
     - 无参数: 无释义
 Return: 连接状态返回true,否则返回false
 ============================================================================
*/
bool WPAuthClient::ensureConnected()
{
    std::lock_guard<std::mutex> lock(this->m_sock_mutex);
    if (this->m_sock >= 0) 
        return true;  // 已连接
    
    // 创建监听套接字
    this->m_sock = socket(AF_INET, SOCK_STREAM, 0);
    if (this->m_sock < 0) 
        return false;
    
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(this->m_port);
    inet_pton(AF_INET, this->m_host.c_str(), &addr.sin_addr);
    
    // 设置连接超时
    struct timeval tv;
    tv.tv_sec = 3;
    tv.tv_usec = 0;
    setsockopt(this->m_sock, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
    
    if (connect(this->m_sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) 
    {
        // 连接失败关闭套接字
        close(this->m_sock);
        this->m_sock = -1;
        return false;
    }
    
    // 设置发送/接收超时
    tv.tv_sec = 5;
    setsockopt(this->m_sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
    
    return true;
}

/*
 ============================================================================
 Function: doVerify
 Description: 验证执行器 - 发送请求到验证服务器并解析JSON
 Parameters:
     - const nlohmann::json&: 一个用于请求的json
 Return: 返回一个nlohmann::json,验证的内容
 ============================================================================
*/
nlohmann::json WPAuthClient::doVerify(const nlohmann::json& request)
{
    if (!ensureConnected()) 
    {
        return std::move(nlohmann::json({
            {"success", false}, 
            {"error", "Unable to connect to the authentication server"}
        }));
    }
    
    std::string req_str = request.dump() + "\n";
    
    {
        std::lock_guard<std::mutex> lock(this->m_sock_mutex);
        if (send(this->m_sock, req_str.c_str(), req_str.length(), 0) < 0) 
        {
            // 发送失败,标记连接断开,下次重连
            close(this->m_sock);
            this->m_sock = -1;
            return std::move(nlohmann::json({
                {"success", false}, 
                {"error", "Sending failed, connection has been disconnected"}
            }));
        }
    }
    
    // 接收响应
    char buffer[8192];
    memset(buffer, 0, sizeof(buffer));
    int bytes = recv(this->m_sock, buffer, sizeof(buffer) - 1, 0);
    
    if (bytes <= 0) 
    {
        std::lock_guard<std::mutex> lock(this->m_sock_mutex);
        close(this->m_sock);
        this->m_sock = -1;
        return std::move(nlohmann::json({
            {"success", false}, 
            {"error", "接收失败或超时"}
        }));
    }
    
    try 
    {
        // 关闭连接,下次需要再连接
        {
            std::lock_guard<std::mutex> lock(this->m_sock_mutex);
            close(this->m_sock);
            this->m_sock = -1;
        }

        // 解析json
        return nlohmann::json::parse(std::string(buffer, bytes));
    } 
    catch (const std::exception& e) 
    {
        return std::move(nlohmann::json({
            {"success", false}, 
            {"error", std::string("JSON parsing failed: ") + e.what()}
        }));
    }
    return std::move(nlohmann::json({
        {"success", false}, 
        {"error", std::string("unknown state")}
    }));
}

代码解析:

C++:

持续验证请求的完整执行流程:

假设主线程不断调用 verifyUserPassword(),工作线程在循环处理:

时刻 T0: 启动
├─ 主线程:调用 startWPAuthClient()
└─ 工作线程:启动,进入 workerLoop()

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

时刻 T1: 第1次验证请求到达
├─ 主线程:
│  ├─ 创建 request = {"action": "verify", "username": "ta01", "password": "Wsz123456."}
│  ├─ 创建 promise p1
│  ├─ 创建 future f1 = p1.get_future()
│  ├─ 加锁 m_queue_mutex
│  │  └─ m_task_queue.emplace(request, std::move(p1))  ← p1 所有权转移到队列
│  ├─ 解锁 m_queue_mutex
│  ├─ m_cv.notify_one()  ← 唤醒工作线程
│  └─ f1.wait_for(10s)   ← 主线程阻塞在这里,等待结果
│
└─ 工作线程:
   ├─ 在 m_cv.wait() 被唤醒
   ├─ 加锁 m_queue_mutex
   ├─ 检查队列:不为空 ✓
   ├─ task = m_task_queue.front()  ← 取出 (request, p1)
   ├─ m_task_queue.pop()
   ├─ 解锁 m_queue_mutex
   ├─ 执行:result = doVerify(request)
   │  ├─ ensureConnected() → 创建新 socket,连接 PHP 服务器
   │  ├─ send(request) → 发送 JSON
   │  ├─ recv(buffer) → 接收 JSON
   │  └─ parse JSON → 返回结果
   │
   ├─ task.second.set_value(result)  ← 承诺兑现!
   │  └─ f1 被激活(从 wait_for 返回)
   │
   └─ 回到 while 循环开始,继续等待下一个任务

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

时刻 T2: 工作线程刚兑现承诺,主线程收到结果
├─ 主线程:
│  ├─ future.get() 返回 result
│  ├─ 检查 result["success"] 是否为 true
│  └─ 返回 true/false
│
└─ 工作线程:
   └─ 继续循环,进入 m_cv.wait() 睡眠状态

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

时刻 T3: 第2次验证请求到达(比如 ta001)
├─ 主线程:
│  ├─ 创建 promise p2
│  ├─ 创建 future f2
│  ├─ 加锁 m_queue_mutex
│  │  └─ m_task_queue.emplace(request2, std::move(p2))
│  ├─ 解锁 m_queue_mutex
│  ├─ m_cv.notify_one()  ← 唤醒工作线程
│  └─ f2.wait_for(10s)   ← 主线程再次阻塞
│
└─ 工作线程:
   ├─ 再次被唤醒
   ├─ 取出 (request2, p2)
   ├─ 执行:result2 = doVerify(request2)
   │  ├─ ensureConnected()
   │  │  ├─ 检查 m_sock >= 0?
   │  │  ├─ 如果还是第一次的 socket → 假设已关闭 → 返回 false ❌
   │  │  │  或者
   │  │  ├─ 创建新 socket → 连接 PHP 服务器
   │  │  └─ 返回 true ✓
   │  ├─ send(request2)
   │  ├─ recv(buffer)
   │  └─ parse JSON
   │
   └─ task.second.set_value(result2)  ← p2 兑现

(重复 T3 的流程...)

核心数据结构

// 任务队列的定义(在 .h 文件)
std::queue<std::pair<nlohmann::json, std::promise<nlohmann::json>>> m_task_queue;
                       ↑                 ↑
                    请求             承诺对象

队列中存储的内容:

┌─────────────────────────────────┐
│ 任务队列 (m_task_queue)          │
├─────────────────────────────────┤
│ [0] (request1, promise1)         │  ← 等待被处理
│ [1] (request2, promise2)         │  ← 等待被处理
│ [2] (request3, promise3)         │  ← 等待被处理
└─────────────────────────────────┘

线程同步机制:

主线程                          工作线程
  │                               │
  ├─ 创建 promise ──────────┐      │
  │                        └──→ 存入队列
  │                               │
  ├─ notify_one() ────────────→ 唤醒 ← m_cv.wait()
  │                               │
  ├─ future.wait_for(10s) ← ┐      │
  │  (阻塞)                  └─── set_value(result)
  │                               │
  └─ 继续执行                  继续循环
© 版权声明
THE END
喜欢就支持一下吧
点赞11 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容