session.cookie_domain не работает должным образом в приложении Plesk / PHP на 2 поддоменах - PullRequest
0 голосов
/ 16 января 2019

Изменить 29/1/2019 - на этот вопрос была назначена награда, но ни один из предоставленных ответов не имеет прямого отношения к проблеме. Если у вас есть ответ, который работает на основе того, что было задано, ответьте

У меня есть 2 домена, настроенные на одном физическом сервере:

app.example.com
help.app.example.com

Пользователи входят в систему https://app.example.com/, которая состоит из приложения PHP 5.5, которое сохраняет данные в массиве $_SESSION после успешного входа в систему.

Я хочу настроить https://help.app.example.com/, чтобы я мог читать данные сеанса, присутствующие в https://app.example.com/. Приложение на поддомене help представляет собой систему управления контентом, встроенную в PHP 7.

В Plesk я добавил следующее в «Дополнительные директивы конфигурации» для php.ini в и app.example.com и help.app.example.com:

session.cookie_domain = ".example.com"

Если я загружаю скрипт phpinfo() в help.app.example.com, он показывает следующее для session.cookie_domain:

  • Локальное значение: нет значения
  • Основное значение: .example.com

Если я затем запусту следующее в скрипте на help.app.example.com:

<?php
session_start();
var_dump($_SESSION);
die;
?>

Выводит пустой массив:

array(0) { }

Однако, если я запускаю эквивалент на app.example.com, он выводит массив данных сеанса, который показывает подробности вошедшего в систему пользователя (как и ожидалось):

array(15) {
   ["o_id"]=> (1) "1"
   ["u_id"]=> string(4) "1745"
   ...
}

Я ожидаю увидеть одинаковые результаты на обоих поддоменах. Почему это не работает?

Я прочитал Разрешить перенос сессий php на поддомены , но ни одна из них не решает проблему.

Ответы [ 2 ]

0 голосов
/ 25 января 2019

Почему это не работает?

по умолчанию сеансы сохраняются в локальных файлах на сервере, расположение которых указано в session.save_path файла php.ini, например session.save_path = /var/lib/php/sessions, если запущены app.example.com и help.app.example.com на 2 разных серверах с их собственной файловой системой, или даже если она работает в одной и той же файловой системе, но имеет разные директивы session.save_path в php.ini, они не будут использовать одну и ту же переменную $ _SESSION.

если вы хотите, чтобы 2 разных сервера использовали один и тот же $ _SESSION, возможные решения включают в себя создание базы данных общего хранилища сеансов с session_set_save_handler() (как приходит на ум MongoDB или MySQL) или создание сетевой файловой системы и установите session.save_path = /path/to/networked/filesystem/mountpoint в php.ini, но оба эти метода могут привести к значительному снижению производительности.

... поскольку файл cookie используется в обоих доменах, session_id() вернет одинаковое значение с обеих сторон, которое можно использовать в качестве идентификатора для базы данных сеанса, взгляните на http://php.net/manual/en/class.sessionhandlerinterface.php

(я бы написал пример класса, если бы у меня было больше времени, но у меня нет времени)

переключиться на хранилище сеансов с поддержкой sql-db (например, MariaDB, MySQL или PostgreSQL), например: схема:

CREATE TABLE sessions (
  id VARCHAR(255) ,
  atime BIGINT ,
  data BLOB
)

Реализация SessionHandlerInterface:

class MySqlSessionHandler implements SessionHandlerInterface
{
    protected $db;
    public function __construct(string $dsn, string $username, string $password)
    {
        $this->db = new PDO($dsn, $username, $password, array(
            PDO::ATTR_EMULATE_PREPARES => false,
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
        ));
    }
    protected function a(string $id) : bool
    {
        $ret = $this->db->query("UPDATE sessions SET atime = " . (time()) . " WHERE id = " . $this->db->quote($id));
        return ($ret->rowCount() > 0);
    }
    public function close() : bool
    {
        // TODO: implement locking/race-condition-free session handling?
        return true;
    }
    public function destroy(string $id) : bool
    {
        $this->db->query("DELETE FROM sessions WHERE id = " . $db->quote($id));
        return true;
    }
    public function gc(int $maxlifetime) : int
    {
        $this->db->query("DELETE FROM sessions WHERE atime < " . (time() - $maxlifetime));
        return 1; // ??? not sure what this return int is supposed to contain, docs doesn't say either
    }
    public function open(string $save_path, string $session_name) : bool
    {
        if (!$this->a($session_name)) {
            $stm = $this->db->prepare("INSERT INTO sessions (id,atime,data) VALUES(?,?,?);");
            $stm->execute(array($session_name, time(), serialize(null)));
        }
        return true;
    }
    public function read(string $session_id) : string
    {
        if (!$this->a($session_id)) {
            throw new \InvalidArgumentException("supplied session id does not exist.");
        }
        return $this->db->query("SELECT data FROM sessions WHERE id = " . $this->db->quote($session_id))->fetch(PDO::FETCH_ASSOC)['data'];
    }
    public function write(string $session_id, string $session_data) : bool
    {
        // optimization note: this function can be optimized to do everything in a single query, instead of using a() (which also use a query)
        if (!$this->a($session_id)) {
            throw new \InvalidArgumentException("supplied session id does not exist.");
        }
        $stm = $this->db->prepare("UPDATE sessions SET data = ? WHERE id = ?");
        $stm->execute(array($session_data, $session_id));
        return true;
    }
}

использование:

// for DSN documentation, check http://php.net/manual/en/ref.pdo-mysql.connection.php
$handler = new MySqlSessionHandler ('mysql:host=mydb.foo.com;dbname=sessions;charset=utf8mb4','MySqlUsername','MySqlPassword');
session_set_save_handler($handler, true);
session_start();
  • теперь они обязательно должны делиться сессиями ..
  • предупреждение: не проверено на момент написания, но это должно работать в теории.
0 голосов
/ 21 января 2019

Я просто пытаюсь повторить с:

  • Продукт: Plesk Onyx 17.8.11 Обновление № 37
  • PHP Версия 7.0.32-0ubuntu0.16.04.1

и работает довольно хорошо. Я получил значения в массиве _Session в обоих случаях, даже я просто сохраняю значения только в поддомене.

В моем наборе 'Дополнительные директивы конфигурации' для php.ini одинаковы для домена и субдомена.

...