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

Trädvy Permalänk
Medlem
Plats
Hudiksvall
Registrerad
Jul 2001

[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

{ Supermicro X10SRi-F | Intel Xeon E5-2620v3 | 64GiB DDR4 | LSI 9207-8i | 4x250GiB Samsung 840 EVO } @ Supermicro CSE216E16-R1200LPB

Trädvy Permalänk
Medlem
Registrerad
Sep 2014

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.

Trädvy Permalänk
Medlem
Plats
Hudiksvall
Registrerad
Jul 2001

@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.

{ Supermicro X10SRi-F | Intel Xeon E5-2620v3 | 64GiB DDR4 | LSI 9207-8i | 4x250GiB Samsung 840 EVO } @ Supermicro CSE216E16-R1200LPB

Trädvy Permalänk
Medlem
Registrerad
Sep 2014

@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!

Trädvy Permalänk
Webbutvecklare
Moderator
Plats
::1
Registrerad
Dec 2002
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".

Abstractions all the way down.

Trädvy Permalänk
Medlem
Plats
Hudiksvall
Registrerad
Jul 2001
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)

{ Supermicro X10SRi-F | Intel Xeon E5-2620v3 | 64GiB DDR4 | LSI 9207-8i | 4x250GiB Samsung 840 EVO } @ Supermicro CSE216E16-R1200LPB

Trädvy Permalänk
Webbutvecklare
Moderator
Plats
::1
Registrerad
Dec 2002
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.

Abstractions all the way down.

Trädvy Permalänk
Medlem
Plats
Hudiksvall
Registrerad
Jul 2001
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.

{ Supermicro X10SRi-F | Intel Xeon E5-2620v3 | 64GiB DDR4 | LSI 9207-8i | 4x250GiB Samsung 840 EVO } @ Supermicro CSE216E16-R1200LPB