簡體   English   中英

session.cookie_domain在2個子域中的Plesk / PHP應用程序中無法正常工作

[英]session.cookie_domain not working as expected in Plesk / PHP application on 2 subdomains

編輯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.comhelp.app.example.com

session.cookie_domain = ".example.com"

如果我將一個phpinfo()腳本上傳到help.app.example.com它會顯示以下session.cookie_domain

  • 本地價值:沒有價值
  • 主值: .example.com

如果我然后在help.app.example.com上的腳本中運行以下help.app.example.com

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

它輸出一個空數組:

array(0) { }

但是,如果我在app.example.com上運行等效app.example.com ,則會輸出一個會話數據數組,其中顯示了已登錄用戶的詳細信息(如預期的那樣):

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

我期待在兩個子域上看到相同的輸出。 為什么這不起作用?

我已閱讀允許php會話轉移到子域,但沒有一個解決問題。

為什么這不起作用?

默認情況下會話保存到服務器上的本地文件,其位置在php.ini的session.save_path指定,例如session.save_path = /var/lib/php/sessions ,如果是app.example.com和help.app .example.com運行在具有自己的文件系統的2個不同服務器上,或者即使它在同一文件系統上運行但在php.ini中具有不同的session.save_path指令,它們也不會共享相同的$ _SESSION。

如果您希望2個不同的服務器共享相同的$ _SESSION,可能的解決方案包括使用session_set_save_handler()創建共享會話存儲數據庫(如想到MongoDB或MySQL),或創建網絡文件系統並設置session.save_path = /path/to/networked/filesystem/mountpoint php.ini中的session.save_path = /path/to/networked/filesystem/mountpoint ,但這兩種方法都可能導致顯着的性能損失。

...由於cookie在兩個域之間共享, session_id()將在兩端返回相同的值,可以用作會話數據庫的id,請查看http://php.net/manual/ EN / class.sessionhandlerinterface.php

(如果我有更多時間,我會寫一個樣本課,但我沒時間)

切換到sql-db支持的會話存儲(如MariaDB,MySQL或PostgreSQL),例如:schema:

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();
  • 現在他們肯定應該分享會議..
  • 警告:在編寫時未經測試,但這應該在理論上有效。

我只是嘗試復制whit:

  • 產品:Plesk Onyx 17.8.11更新#37
  • PHP版本7.0.32-0ubuntu0.16.04.1

並且工作得很好。 在兩種情況下,我都在_Session數組中獲得了值,即使我只將值保存在子域中。

在我的集合中,php.ini的“附加配置指令”對於域和子域是相同的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM