需要通过 CURL 将会话共享到 PHP 中同一域中的本地伪服务器

Need to share session to LOCAL psuedo server on same domain in PHP through CURL

我正在使用本地 php 文件构建一个应用程序,该文件接受 post/get 输入和 returns JSON 结果。我这样做是为了分离前端和后端操作,因为它可能最终将后端移动到其他地方(而且它很简洁,因为您可以仅使用浏览器和 URL 变量来测试后端操作。

明确地说,我没有立即甚至长期的计划来实际分离它们:现在它们在同一服务器上的同一文件夹中,甚至 - 我只有一个 backend.php 文件伪装成一个远程服务器,这样我就可以练习解耦了。这个问题的胜利意味着调用 CURL 并让后端接收会话,后端可以 change/update/addto 会话,前端看到所有更改(基本上是前端和后端的一个会话)。

问题是我一直在努力让会话在两者之间工作。当我使用 Javascript 发出 AJAX 请求时,会话工作正常,因为它是在同一台服务器上加载的页面,所以 session_start() 正常工作。但是当我CURL的时候,session数据没有传输。

几个月来我一直在为此苦苦挣扎,所以我的 curl 函数非常混乱,但我想不出使它起作用的神奇组合。在这种情况下,我无法始终如一地找到任何 SO 问题或在线指南:

        // Call the backend using the provided URL and series of name/value vars (in an array)
    function backhand($data,$method='POST') {

        $url = BACKEND_URL;
        // Make sure the backend knows which session in the db to connect to
        //$data['session_id'] = session_id();
        // Backend will send this back in session so we can see the the connection still works.
        //$data['session_test'] = rand();
    
        $ch = curl_init();

        if ('POST' == $method) {
            curl_setopt($ch, CURLOPT_POST, 1);
            curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
        }
        $get_url = sprintf("%s?%s", $url, http_build_query($data));
        $_SESSION['diag']['backend-stuff'][] = $get_url;

        if ('GET' == $method) {
            curl_setopt($ch, CURLOPT_PUT, 1);
            $url = $get_url;
        }
    
        // Optional Authentication:
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_HEADER, 0);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
#       curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
#       curl_setopt($ch, CURLOPT_VERBOSE, 1);
#       curl_setopt($ch, CURLOPT_USERAGENT,$_SERVER['HTTP_USER_AGENT']);

        // Retrieving session ID 
        // $strCookie = 'PHPSESSID=' . $_COOKIE['PHPSESSID'] . '; path=/';    
        $cookieFile = "cookies.txt";
        if(!file_exists($cookieFile)) {
            $fh = fopen($cookieFile, "w");
            fwrite($fh, $_SESSION);
            fclose($fh);
        }

#curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
#curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
#curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json'));
curl_setopt($ch, CURLOPT_COOKIEFILE, $cookieFile); // Cookie aware
curl_setopt($ch, CURLOPT_COOKIEJAR, $cookieFile); // Cookie aware

        // We pass the sessionid of the browser within the curl request
        curl_setopt( $ch, CURLOPT_COOKIEFILE, $strCookie ); 
#       session_write_close();

        // Have to pause the session or the backend wipes the front
        if (!$result = curl_exec($ch)) {
            pre_r(curl_getinfo($ch));
            echo 'Cerr: '.curl_error($ch);
        }

        curl_close($ch);
#       session_start();

        // "true" makes it return an array
        return json_decode($result,true);
    }

我从前端这样调用函数从后端获取结果:

    // Get user by email or ID
    function get_user($emailorid) {
        // If it's not an email, see if they've been cached. If so, return them
        if (is_numeric($emailorid) && $_SESSION['users'][$emailorid])
            return $_SESSION['users'][$emailorid];

        return backhand(['get_user'=>$emailorid]);
    }

所以如果我在前面的任何地方调用“get_user”,它会跳到后面,运行 数据库查询并将它全部转储到返回的 JSON在值的关联数组中对我来说。这工作正常,但会话数据不能正确保留并且会导致问题。

我什至尝试了一段时间的数据库会话,但这也不一致。我 运行 没有想法,可能必须通过使用数据库和自定义函数来构建某种备用会话功能,但我希望这个 CAN 可以工作......我只是还没有弄清楚如何。

如果您的后端 Web 服务器位于不同的服务器上,您可以保留文件系统存储并与 NFS 共享存储会话的文件目录。

您也可以使用 http://www.php.net/manual/en/function.session-set-save-handler.php 为会话设置不同的保存处理程序,但我不确定将它们存储在数据库中对 I/O.[=11 是个好主意=]

经过 brute-force 反复试验,这似乎可行:

    function backhand($data,$method='POST') {

    $url = BACKEND_URL;
    // Make sure the backend knows which session in the db to connect to
    //$data['session_id'] = session_id();
    // Backend will send this back in session so we can see the the connection still works.
    $data['session_test'] = rand();

    $ch = curl_init();

    if ('POST' == $method) {
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
    }
    $get_url = sprintf("%s?%s", $url, http_build_query($data));
    $_SESSION['diag']['backend-stuff'][] = $get_url;

    if ('GET' == $method) {
        curl_setopt($ch, CURLOPT_HTTPGET, 1);
        $url = $get_url;
    }

    // Optional Authentication:
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_HEADER, 0);
    // required or it writes the data directly into document instead of putting it in a var below
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);         
    #curl_setopt($ch, CURLOPT_USERAGENT,$_SERVER['HTTP_USER_AGENT']); 

    // Retrieving session ID 
    $strCookie = 'PHPSESSID=' . $_COOKIE['PHPSESSID'] . '; path=/';    

    // We pass the sessionid of the browser within the curl request
    curl_setopt( $ch, CURLOPT_COOKIE, $strCookie );  
    curl_setopt($ch, CURLOPT_COOKIEJAR, 'somefile'); 
    curl_setopt($ch, CURLOPT_COOKIEFILE, APP_ROOT.'/cookie.txt'); 
    curl_setopt($ch, CURLOPT_TIMEOUT_MS, 5000); 

    // Have to pause the session or the backend wipes the front
    session_write_close();
    if (!$result = curl_exec($ch)) {
        pre_r(curl_getinfo($ch));
        echo 'Cerr: '.curl_error($ch);
    }

    @session_start();

    curl_close($ch);

    // "true" makes it return an array
    return json_decode($result,true);
}