Необходимо поделиться сеансом с ЛОКАЛЬНЫМ псевдосервером в том же домене в PHP через CURL

#php #session #curl

#php #сеанс #curl

Вопрос:

Я создаю приложение, используя локальный php-файл, который принимает post / get ввод и возвращает результаты JSON. Я делаю это, чтобы разделить работу интерфейса и серверной части, исходя из идеи, что в конечном итоге можно переместить серверную часть в другое место (и это здорово, потому что вы можете протестировать работу серверной части, используя только переменные браузера и URL.

Чтобы было ясно, у меня нет немедленных или даже долгосрочных планов по их фактическому разделению: прямо сейчас они находятся на одном сервере в одной папке даже — у меня просто есть один backend.php файл, притворяющийся удаленным сервером, чтобы я мог практиковать развязку. Победа в этой проблеме означает вызов CURL и получение бэкэндом сеанса, бэкэнд может изменять / обновлять / добавлять к сеансу, а интерфейс видит все изменения (в основном ОДИН сеанс для передней и задней части).

Проблема в том, что я постоянно борюсь за то, чтобы сеанс работал между ними. Когда я делаю AJAX-запросы с помощью Javascript, сеанс работает нормально, потому что страница загружается на тот же сервер, поэтому session_start() просто работает. Но когда я выполняю CURL, данные сеанса не передаются.

Я боролся с этим в течение нескольких месяцев, поэтому моя функция 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) amp;amp; $_SESSION['users'][$emailorid])
            return $_SESSION['users'][$emailorid];

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

Поэтому, если я вызову «get_user» в любом месте спереди, он перейдет на задний план, запустит запросы к БД и сбросит все это в JSON, который возвращается мне в ассоциативных массивах значений. Это работает нормально, но данные сеанса не сохраняются должным образом, и это вызывает проблемы.

Я даже некоторое время пробовал сеансы DB, но это тоже не соответствовало. У меня заканчиваются идеи, и, возможно, придется создать какую-то альтернативную возможность сеанса с помощью db и пользовательских функций, но я ожидаю, что это МОЖЕТ сработать… Я просто еще не понял, как это сделать.

Комментарии:

1. Просто чтобы убедиться, ваша проблема заключается в совместном использовании сеанса PHP между двумя серверами?

2. Нет. Я хотел бы, возможно, рассмотреть это в конечном итоге, но прямо сейчас файлы внешнего интерфейса и серверной части находятся в одной папке на одном сервере. Я пытаюсь убедиться, что сеанс не теряется в CURL.

Ответ №1:

Вы можете сохранить хранилище файловой системы и совместно использовать каталог файлов, в котором хранится сеанс, с NFS, если ваши серверные веб-серверы находятся на разных серверах.

Вы также можете использовать http://www.php.net/manual/en/function.session-set-save-handler.php чтобы установить другой обработчик сохранения для вашего сеанса, но я не уверен, что сохранение их в базе данных было бы хорошей идеей для ввода-вывода.

Комментарии:

1. Я согласен, что хранилище БД для сеанса — это болото, и я хочу этого избежать. И интерфейс, и серверная часть находятся на одном сервере в одной папке в данный момент и в обозримом будущем. Если я смогу найти хороший ответ для решения насущной проблемы, этого будет достаточно на данный момент

Ответ №2:

После проб и ошибок методом перебора это, похоже, работает:

     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);
}