You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WordPress自定义插件PHP Session报错:干扰REST API及回环请求

解决WordPress插件PHP Session与REST API冲突问题

问题根源

当前代码在init全局钩子中启动Session,导致所有请求(包括REST API、后台loopback请求)都会创建Session,触发冲突报错。而使用read_and_close参数会直接关闭Session,无法保留表单步骤数据。

解决方案

1. 精准控制Session启动时机

只在前端表单页面和插件自身AJAX请求中启动Session,排除REST API、后台、无关AJAX请求。

修改插件主类代码:

class WP_Oscar
{
    public function __construct()
    {
        require_once XHE_HCV_DIR . 'includes/class-email.php';
        require_once XHE_HCV_DIR . 'includes/class-ajax.php';
        require_once XHE_HCV_DIR . 'includes/class-register-users.php';
        
        // 移除全局init钩子的session_start,改为按需启动
        // add_action('init', array( $this, 'session_start' )  );
        
        add_action( 'wp_logout', array( $this, 'session_end' ) );
        add_action( 'wp_login',array( $this,  'session_end' ) );
        
        // 保留其他钩子
        add_shortcode( 'oscar_appointment', array($this, 'display_shortcode') );
        add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_scripts' ), 999 );
        add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts_admin' ), 999 );
        add_action('admin_menu', array($this, 'admin_menu'));
        add_action('admin_init', array($this, 'register_settings'));
        
        // 添加请求结束时关闭Session的钩子
        add_action('shutdown', array($this, 'session_close'));
    }
    
    // 新增判断是否为REST请求的辅助方法
    private function is_rest_request() {
        return defined('REST_REQUEST') && REST_REQUEST;
    }

    public function session_start() {
        // 仅在非后台、非REST、非无关AJAX的场景下启动Session
        if (session_status() == PHP_SESSION_NONE && !headers_sent()) {
            // 场景1:前端表单页面(包含插件短码)
            if (!is_admin() && !$this->is_rest_request() && !wp_doing_ajax()) {
                global $post;
                if (is_a($post, 'WP_Post') && has_shortcode($post->post_content, 'oscar_appointment')) {
                    session_start();
                }
            }
            // 场景2:插件自身的AJAX请求(替换为你的AJAX动作名)
            if (wp_doing_ajax()) {
                $allowed_ajax_actions = array('oscar_form_step_submit', 'oscar_get_available_times'); // 示例动作名
                if (isset($_POST['action']) && in_array($_POST['action'], $allowed_ajax_actions)) {
                    session_start();
                }
            }
        }
    }

    public function session_end() {
        if (session_status() == PHP_SESSION_ACTIVE) {
            session_destroy();
        }
    }
    
    public function session_close() {
        if (session_status() == PHP_SESSION_ACTIVE) {
            session_write_close();
        }
    }

    private function display_form() {
        // 进入表单页面时主动启动Session
        $this->session_start();
        
        // 原display_form代码保持不变
        $steps = array(
            'init' => XHE_HCV_DIR . 'templates/html-init.php',
            'register' => XHE_HCV_DIR . 'templates/html-new-client.php',
            'hin' => XHE_HCV_DIR . 'templates/html-hin.php',
            'email' => XHE_HCV_DIR . 'templates/html-email.php',
            'booking_time' => XHE_HCV_DIR . 'templates/html-booking-time.php',
            'confirm' => XHE_HCV_DIR . 'templates/html-confirm.php'
        );

        echo '<script src="https://www.google.com/recaptcha/api.js" async defer></script>';

        $xhe_hcv_term_pageid = $this->get_option_value('oscar_emr_plugin_options', 'oa_oscar_emr_xhe_hcv_term_pageid');

        if( $xhe_hcv_term_pageid ) {
            $term_page = get_post( absint($xhe_hcv_term_pageid) );

            if( ! empty($term_page->post_content) ) {
                printf(
                    '<div id="openTermModal" class="venobox-modal">%s</div>',
                    $term_page->post_content
                );
            }
        }
        // ... 后续代码
    }

    // 其他方法保持不变
}

2. 表单提交后清理Session

在表单最终确认提交的处理逻辑中,完成数据存储后主动销毁Session,避免残留:

// 示例:在确认提交的函数中添加
public function process_booking_confirm() {
    // 处理表单数据存储逻辑...
    
    // 清理Session
    $this->session_end();
}

3. AJAX请求中的Session处理

在class-ajax.php中,处理插件AJAX动作时,确保Session正确读写:

// 示例AJAX处理函数
public function handle_form_step() {
    // 先启动Session
    if (session_status() == PHP_SESSION_NONE && !headers_sent()) {
        session_start();
    }
    
    // 处理表单步骤数据,写入Session
    $_SESSION['form_step_data']['current_step'] = $_POST['step'];
    $_SESSION['form_step_data']['selected_time'] = $_POST['time'];
    
    // 完成后关闭Session
    session_write_close();
    
    // 返回响应
    wp_send_json_success('步骤保存成功');
}

关键说明

  • 避免全局启动Session,仅在需要的场景初始化,从根源解决REST API冲突
  • 使用shutdown钩子在请求结束时统一关闭Session,释放资源
  • AJAX请求需单独判断动作,确保只有插件自身的AJAX才启动Session
  • 表单完成后及时销毁Session,避免用户数据残留

内容的提问来源于stack exchange,提问作者ysq74

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 09:30:45