Během několika hodin ladění jsem zjistil, že odkazované články byly nalezeny v četných vyhledáváních Google a také významná podmnožina odpovědí Stack Overflow, jako je zde , zde a zde všechny poskytují neplatné nebo zastaralé informace.
Věci, které mohou způsobit [kritické] problémy s ukládáním dat relace do databáze:
-
Zatímco všechny příklady online uvádějí, že můžete „vyplnit“
session_set_save_handler
, žádný z nich neuvádí, že musíte také nastavitregister_shutdown_function('session_write_close')
také (odkaz ). -
Několik (starších) příruček odkazuje na zastaralou strukturu databáze SQL a nemělo by být použit. Struktura databáze, kterou potřebujete pro ukládání dat relace do databáze, je:
id
/access
/data
. A je to. není potřeba různých dalších sloupců časových razítek, jak jsem viděl na několika "průvodcích" a příkladech.- Několik starších příruček má také zastaralou syntaxi MySQL, jako je
DELETE * FROM ...
- Několik starších příruček má také zastaralou syntaxi MySQL, jako je
-
Třída [vytvořená v mé otázce] musí implementovat
SessionHandlerInterface
. Viděl jsem průvodce (uvedené výše), které poskytují implementacisessionHandler
což není vhodné rozhraní. Možná předchozí verze PHP měly trochu jinou metodu (pravděpodobně <5.4). -
Metody třídy relace musí vrátit hodnoty stanovené manuálem PHP. Opět pravděpodobně zděděno z PHP před verzí 5.4, ale dva příručky, které jsem četl, uváděly, že
class->open
vrátí řádek ke čtení, zatímco příručka PHP uvádí že potřebuje vrátittrue
nebofalse
pouze. -
Toto je příčina mého původního vydání :Používal jsem vlastní názvy relací (ve skutečnosti jsou id jako názvy relací a id relace jsou totéž! ) podle tohoto velmi dobrého příspěvku StackOverflow a toto generovalo název relace, který byl dlouhý 128 znaků. Protože název relace je jediný klíč, který je potřeba prolomit, aby bylo možné relaci kompromitovat a převzít kontrolu pomocí únos relace pak je delší jméno/id velmi dobrá věc.
- To však způsobilo problém, protože MySQL tiše rozdělovala ID relace na pouhých 32 znaků místo 128, takže nikdy nebyl schopen najít data relace v databázi. Toto byl zcela tichý problém (možná kvůli tomu, že moje třída připojení k databázi neházela varování o takových věcech). Ale na tohle je třeba si dát pozor. Pokud máte nějaké problémy s načítáním relací z databáze, nejprve zkontrolujte, zda je úplná ID relace lze uložit do poskytnutého pole.
Takže s tím vším je potřeba přidat i nějaké další detaily:
Manuálová stránka PHP (odkaz výše) zobrazuje nevhodnou hromadu řádků pro objekt třídy:
Zatímco to funguje stejně dobře, pokud to vložíte do konstruktoru třídy:
class MySessionHandler implements SessionHandlerInterface {
private $database = null;
public function __construct(){
$this->database = new Database(whatever);
// Set handler to overide SESSION
session_set_save_handler(
array($this, "open"),
array($this, "close"),
array($this, "read"),
array($this, "write"),
array($this, "destroy"),
array($this, "gc")
);
register_shutdown_function('session_write_close');
session_start();
}
...
}
Toto znamená, že k zahájení relace na výstupní stránce potřebujete pouze:
<?php
require "path/to/sessionhandler.class.php";
new MySessionHandler();
//Bang session has been setup and started and works
Pro srovnání je kompletní komunikační třída Session následující, funguje to s PHP 5.6 (a pravděpodobně 7, ale zatím netestováno na 7)
<?php
/***
* Created by PhpStorm.
***/
class MySessionHandler implements SessionHandlerInterface {
private $database = null;
public function __construct($sessionDBconnectionUrl){
/***
* Just setting up my own database connection. Use yours as you need.
***/
require_once "class.database.include.php";
$this->database = new DatabaseObject($sessionDBconnectionUrl);
// Set handler to overide SESSION
session_set_save_handler(
array($this, "open"),
array($this, "close"),
array($this, "read"),
array($this, "write"),
array($this, "destroy"),
array($this, "gc")
);
register_shutdown_function('session_write_close');
session_start();
}
/**
* Open
*/
public function open($savepath, $id){
// If successful
$this->database->getSelect("SELECT `data` FROM sessions WHERE id = ? LIMIT 1",$id,TRUE);
if($this->database->selectRowsFoundCounter() == 1){
// Return True
return true;
}
// Return False
return false;
}
/**
* Read
*/
public function read($id)
{
// Set query
$readRow = $this->database->getSelect('SELECT `data` FROM sessions WHERE id = ? LIMIT 1', $id,TRUE);
if ($this->database->selectRowsFoundCounter() > 0) {
return $readRow['data'];
} else {
return '';
}
}
/**
* Write
*/
public function write($id, $data)
{
// Create time stamp
$access = time();
// Set query
$dataReplace[0] = $id;
$dataReplace[1] = $access;
$dataReplace[2] = $data;
if ($this->database->noReturnQuery('REPLACE INTO sessions(id,access,`data`) VALUES (?, ?, ?)', $dataReplace)) {
return true;
} else {
return false;
}
}
/**
* Destroy
*/
public function destroy($id)
{
// Set query
if ($this->database->noReturnQuery('DELETE FROM sessions WHERE id = ? LIMIT 1', $id)) {
return true;
} else {
return false;
}
}
/**
* Close
*/
public function close(){
// Close the database connection
if($this->database->dbiLink->close){
// Return True
return true;
}
// Return False
return false;
}
/**
* Garbage Collection
*/
public function gc($max)
{
// Calculate what is to be deemed old
$old = time() - $max;
if ($this->database->noReturnQuery('DELETE FROM sessions WHERE access < ?', $old)) {
return true;
} else {
return false;
}
}
public function __destruct()
{
$this->close();
}
}
Použití:Jak je znázorněno těsně nad textem kódu třídy.