sql >> Database teknologi >  >> RDS >> Mysql

Hvordan gemmer jeg PHP-sessionsdata til en database i stedet for i filsystemet?

Jeg har i løbet af adskillige timers fejlretning fundet ud af, at de refererede artikler fundet på adskillige Google-søgninger samt en betydelig undergruppe af Stack Overflow-svar såsom her , her og her alle giver ugyldige eller forældede oplysninger.

Ting, der kan forårsage [kritiske] problemer med at gemme sessionsdata i en database:

  • Mens alle eksemplerne online angiver, at du kan "fylde" session_set_save_handler , ingen af ​​dem angiver, at du også skal indstille register_shutdown_function('session_write_close') også (reference ).

  • Flere (ældre) vejledninger henviser til en forældet SQL-databasestruktur, og bør ikke blive brugt. Den databasestruktur, du skal bruge for at gemme sessionsdata i databasen, er:id /access /data . Det er det. intet behov for forskellige ekstra tidsstempelkolonner, som jeg har set på et par "vejledninger" og eksempler.

    • Flere af de ældre guider har også forældet MySQL-syntaks såsom DELETE * FROM ...
  • Klassen [lavet i mit spørgsmål] skal implementere SessionHandlerInterface . Jeg har set vejledninger (refereret ovenfor), der giver implementeringen af ​​sessionHandler hvilket ikke er en passende grænseflade. Måske havde tidligere versioner af PHP en lidt anden metode (sandsynligvis <5,4).

  • Sessionsklassemetoderne skal returnere de værdier, der er angivet i PHP-manualen. Igen, sandsynligvis arvet fra pre-5.4 PHP, men to guider jeg læste sagde, at class->open returnerer rækken, der skal læses, hvorimod PHP-manualen angiver at den skal returnere true eller false kun.

  • Dette er årsagen til mit oprindelige problem :Jeg brugte brugerdefinerede sessionsnavne (faktisk id'er som sessionsnavne og sessions-id'er er det samme! ) ifølge dette meget gode StackOverflow-indlæg og dette genererede et sessionsnavn på 128 tegn. Da sessionsnavnet er den eneste nøgle, der skal knækkes for at kompromittere en session og tage over med en kapring af sessioner så er et længere navn/id en meget god ting.

    • Men dette forårsagede et problem, fordi MySQL i det stille snittede sessions-id'et ned til kun 32 tegn i stedet for 128, så den var aldrig i stand til at finde sessionsdataene i databasen. Dette var et helt stille problem (måske på grund af min databaseforbindelsesklasse, der ikke kastede advarsler om sådanne ting). Men det er denne man skal passe på. Hvis du har problemer med at hente sessioner fra en database, skal du først kontrollere, at den fulde sessions-id kan gemmes i det angivne felt.

Så med alt det ude af vejen er der også nogle ekstra detaljer at tilføje:

PHP-manualsiden (linket ovenfor) viser en uegnet bunke linjer til et klasseobjekt:

Hvorimod det fungerer lige så godt, hvis du sætter dette i klassekonstruktøren:

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();
    }
...
}

Dette betyder, at det eneste, du behøver for at starte en session på din outputside, er:

<?php
require "path/to/sessionhandler.class.php"; 
new MySessionHandler();

//Bang session has been setup and started and works

Til reference er den komplette sessionskommunikationsklasse som følger, dette virker med PHP 5.6 (og sandsynligvis 7, men ikke testet på 7 endnu)

<?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();
    }

}

Brug:Som vist lige over klassekodeteksten.




  1. Access dataverse connector er nu tilgængelig for test

  2. Parsing af tabel- og kolonnenavne fra SQL/HQL Java

  3. Tilfældig registrering fra en databasetabel (T-SQL)

  4. hvordan man vælger tæller fra hovedforespørgsel til underforespørgsel