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.