skip to Main Content

Edit 29/1/2019 – this question was eligible for a bounty but none of the provided answers directly address the issue. If you have an answer that works based on what’s been asked please respond

I have 2 domains configured on the same physical server:

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

Users login to https://app.example.com/ which consists of PHP 5.5 application which stores some data in the $_SESSION array after a successful login.

I want to configure https://help.app.example.com/ so that I can read the session data present on https://app.example.com/. The application on the help subdomain is a content management system built in PHP 7.

In Plesk I have added the following to ‘Additional configuration directives’ for php.ini under both app.example.com and help.app.example.com:

session.cookie_domain = ".example.com"

If I upload a phpinfo() script to help.app.example.com it is showing the following for session.cookie_domain:

  • Local value: no value
  • Master value: .example.com

If I then run the following in a script on help.app.example.com:

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

It is outputting an empty array:

array(0) { }

However, if I run the equivalent on app.example.com it is outputting an array of session data which shows details of the logged-in user (as expected):

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

I’m expecting to see the same output on both sub-domains. Why is this not working?

I have read Allow php sessions to carry over to subdomains but none of that resolves the problem.

2

Answers


  1. I just try to replicate whit:

    • Product: Plesk Onyx 17.8.11 Update #37
    • PHP Version 7.0.32-0ubuntu0.16.04.1

    and works pretty fine. I got values in _Session array in both cases, even I just save the values only in the subdomain.

    In my set, the ‘Additional configuration directives’ for php.ini is the same for the domain and the subdomain.

    Login or Signup to reply.
  2. Why is this not working?

    by default sessions are saved to local files on the server, location of which is specified in php.ini’s session.save_path, for example session.save_path = /var/lib/php/sessions, if app.example.com and help.app.example.com are running on 2 different servers with their own filesystem, or even if it’s running on the same filesystem but have different session.save_path directives in php.ini, they won’t share the same $_SESSION.

    if you want 2 different servers to share the same $_SESSION, possible solutions include creating a shared session store database with session_set_save_handler() (like MongoDB or MySQL comes to mind), or creating a networked filesystem and set session.save_path = /path/to/networked/filesystem/mountpoint in php.ini, but both of these methods may incur a significant performance penalty..

    … since the cookie is shared across both domains, session_id() will return the same value on both sides, that could be used as an id for a session database, take a look at http://php.net/manual/en/class.sessionhandlerinterface.php

    (i’d write a sample class if i had more time but i’m out of time)

    switch to a sql-db-backed session store (like MariaDB, MySQL, or PostgreSQL), for example:
    schema:

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

    SessionHandlerInterface implementation:

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

    usage:

    // 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();
    
    • now they should definitely share sessions..
    • warning: untested as of writing, but this should work in theory.
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search