[PHP7] Problem (?) med SessionHandlerInterface och $_SESSION

Permalänk
Medlem

[PHP7] Problem (?) med SessionHandlerInterface och $_SESSION

Hej,

Jag har implementerat SessionHandlerInterface likt följande:

<?php class Session implements SessionHandlerInterface { protected $pdo; public function __construct() { $dsn = 'mysql:host=' . 'localhost' . ';dbname=' . 'bytewizards.se'; $options = array( PDO::ATTR_PERSISTENT => true, PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION ); try { $this->pdo = new PDO($dsn, '********', '********', $options); } catch(PDOException $exception) { echo $exception->getMessage(); } } public function open($save_path, $session_name) { if($this->pdo) { return true; } else { return false; } } public function close() { $this->pdo = null; return true; } public function read($session_id) { $statement = $this->pdo->prepare('SELECT data FROM sessions WHERE id = :session_id'); $statement->bindParam(':session_id', $session_id); $statement->execute(); return $statement->fetchColumn(); } public function write($session_id, $session_data) { $session_timestamp = time(); $statement = $this->pdo->prepare('REPLACE INTO sessions VALUES(:session_id, :session_timestamp, :session_data)'); $statement->bindParam(':session_id', $session_id); $statement->bindParam(':session_timestamp', $session_timestamp); $statement->bindParam(':session_data', $session_data); return $statement->execute(); } public function destroy($session_id) { $statement = $this->pdo->prepare('DELETE * FROM sessions WHERE id = :session_id'); $statement->bindParam(':session_id', $session_id); return $statement->execute(); } public function gc($maxlifetime) { $session_timestamp_timeout = time() - $maxlifetime; $statement = $this->pdo->prepare('DELETE * FROM sessions WHERE timestamp < :session_timestamp_timeout)'); $statement->bindParam(':session_timestamp', $session_timestamp_timeout); return $statement->execute(); } }

Dold text

och använder den likt följande:

[file1.php] <?php $session = new Session(); session_set_save_handler($session, true); session_start(); $_SESSION["SESSION_DATA"] = 663154; [file2.php] <?php $session = new Session(); session_set_save_handler($session, true); session_start(); echo $_SESSION["SESSION_DATA"]; // 663154

Dold text

och allting som jag har implementerat (open, read, write, gc) fungerar, men sessionen raderas inte på servern när jag stänger webläsaren. Anropar jag 'session_destroy()' manuellt så raderas sessionerna korrekt i databasen. Har jag missuppfattat hur $_SESSION fungerar eller har jag missat något?

Tack på förhand

Visa signatur

{|XSX|PS3|PS4|}

Permalänk
Medlem

Nu är inte jag så insatt i hur SessionHandlerInterface fungerar, men ett alternativ kan vara att du skapar en destruktor och därifrån kallar din destroy metod. När ditt objekt tas bort så kallas destruktorn.

Permalänk
Medlem

@noyce:

SessionHandlerInterface överlagrar de funktioner (read, write, gc, open, close, destroy, http://php.net/manual/en/class.sessionhandlerinterface.php( som används av $_SESSION så rent tekniskt fungerar det som vanliga fil- eller minnesbaserade sessioner.

Jag ska testa att använda destruktor-lösningen, men frågan är om det är -rätt- lösning eller om det är -en- lösning.

Visa signatur

{|XSX|PS3|PS4|}

Permalänk
Medlem

@Wixner:

Det är möjligt att det inte är en helt korrekt lösning, men den kanske fungerar. Snabbgooglade lite och de exemplen jag såg kallade alltid på session_destroy() manuellt. Men förhoppningsvis kan någon annan på detta forum ge lite mer klarhet idet hela!

Permalänk
Legendarisk
Skrivet av Wixner:

men sessionen raderas inte på servern när jag stänger webläsaren. Anropar jag 'session_destroy()' manuellt så raderas sessionerna korrekt i databasen.

Problemet är att servern aldrig får reda på att du stänger webbläsaren; det finns ingen aktiv anslutning mellan de två utan de skickar i princip lappar mellan varandra. Serverns roll är att vänta på en inkommande lapp (en request), att agera på denna och generera ett svar (ett response); den märker inte själv om klienten går och gör något annat, och klienten skickar ingen request för att informera. Sessionsdatan kommer alltså ligga kvar i serverns ände till dess att den fångas av SessionHandlerInterface::gc().

KLIENT | Request | | Request | | EXIT * -------------------∨--------------∧-----------∨------------∧ SERVER | (väntar) | Response | (väntar) | Response | (väntar)

Efter varje svar stänger PHP ner ditt script och anropar alla destruktorer som behövs, och nästa request börjar om från noll. Loggar du ut i sessionshanterarens destruktor så kommer det alltså försökas efter varje request / "sidvisning".

Visa signatur

Abstractions all the way down.

Permalänk
Medlem
Skrivet av Tunnelsork:

Problemet är att servern aldrig får reda på att du stänger webbläsaren; det finns ingen aktiv anslutning mellan de två utan de skickar i princip lappar mellan varandra. Serverns roll är att vänta på en inkommande lapp (en request), att agera på denna och generera ett svar (ett response); den märker inte själv om klienten går och gör något annat, och klienten skickar ingen request för att informera. Sessionsdatan kommer alltså ligga kvar i serverns ände till dess att den fångas av SessionHandlerInterface::gc().

KLIENT | Request | | Request | | EXIT * -------------------∨--------------∧-----------∨------------∧ SERVER | (väntar) | Response | (väntar) | Response | (väntar)

Efter varje svar stänger PHP ner ditt script och anropar alla destruktorer som behövs, och nästa request börjar om från noll. Loggar du ut i sessionshanterarens destruktor så kommer det alltså försökas efter varje request / "sidvisning".

Så att "stänga" sessioner på servern innefattas alltid av GC (eller manuella session_destroy() i samband med timeouts eller utloggningar)

Visa signatur

{|XSX|PS3|PS4|}

Permalänk
Legendarisk
Skrivet av Wixner:

Så att "stänga" sessioner på servern innefattas alltid av GC (eller manuella session_destroy() i samband med timeouts eller utloggningar)

Ja, men det är normalt sett inte ett problem. Om klienten har slängt uppgifterna i sin ände så ska inte sessionen användas igen utan bara rensas vid ett senare tillfälle, och de är ofta ganska små. Det brukar räcka att koppla samman klientens session med en användare eller liknande, och sedan hanterar man resten (som t.ex. kundvagnar) separat ($_SESSION bör varken användas som cache eller databas).

Ber användaren om att logga ut så kan du ju som du säger radera det manuellt, men om man av någon anledning måste radera uppgifterna så snart som möjligt så får man försöka arbeta runt det; ett par alternativ kan vara att flytta lagringen till klienten eller att ha väldigt låg timeout och att pinga servern för att indikera aktivitet.

Visa signatur

Abstractions all the way down.

Permalänk
Medlem
Skrivet av Tunnelsork:

Ja, men det är normalt sett inte ett problem. Om klienten har slängt uppgifterna i sin ände så ska inte sessionen användas igen utan bara rensas vid ett senare tillfälle, och de är ofta ganska små. Det brukar räcka att koppla samman klientens session med en användare eller liknande, och sedan hanterar man resten (som t.ex. kundvagnar) separat ($_SESSION bör varken användas som cache eller databas).

Ber användaren om att logga ut så kan du ju som du säger radera det manuellt, men om man av någon anledning måste radera uppgifterna så snart som möjligt så får man försöka arbeta runt det; ett par alternativ kan vara att flytta lagringen till klienten eller att ha väldigt låg timeout och att pinga servern för att indikera aktivitet.

Mina planer är bara att spara användarens id (krypterat) i $_SESSION så användaren kan använda samma session över flera webservrar med gemensamt databaskluster för lastfördelning och failover. All annan information kommer att sparas i databasen.

Verkar som att allting fungerar nu när jag manuellt triggar GC (för funktionstest) vid open.

Visa signatur

{|XSX|PS3|PS4|}