sql >> Databáze >  >> RDS >> Mysql

Jak uložím data relace PHP do databáze místo do systému souborů?

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é nastavit register_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 ...
  • Třída [vytvořená v mé otázce] musí implementovat SessionHandlerInterface . Viděl jsem průvodce (uvedené výše), které poskytují implementaci sessionHandler 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átit true nebo false 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.




  1. Sqlalchemy vrací zastaralé řádky?

  2. PostgreSQL VACUUM a ANALÝZA Tipy osvědčených postupů

  3. Postgresql extrahuje poslední řádek pro každé ID

  4. mysql pořadí podle vydání