Mysql
 sql >> Teknologi Basis Data >  >> RDS >> Mysql

Bagaimana cara menyimpan data sesi PHP ke database alih-alih di sistem file?

Saya telah menemukan selama beberapa jam debugging bahwa artikel yang direferensikan ditemukan di banyak pencarian Google serta sebagian besar jawaban Stack Overflow seperti di sini , di sini dan di sini semuanya memberikan informasi yang tidak valid atau ketinggalan zaman.

Hal-hal yang dapat menyebabkan masalah [kritis] dengan menyimpan data sesi ke database:

  • Sementara semua contoh online menyatakan bahwa Anda dapat "mengisi" session_set_save_handler , tidak satupun dari mereka menyatakan bahwa Anda juga harus mengatur register_shutdown_function('session_write_close') juga (referensi ).

  • Beberapa panduan (lama) mengacu pada struktur Database SQL yang sudah ketinggalan zaman, dan seharusnya tidak digunakan. Struktur database yang Anda perlukan untuk menyimpan data sesi ke database adalah:id /access /data . Itu dia. tidak perlu berbagai kolom stempel waktu tambahan seperti yang saya lihat di beberapa "panduan" dan contoh.

    • Beberapa panduan lama juga memiliki sintaks MySQL yang sudah ketinggalan zaman seperti DELETE * FROM ...
  • Kelas [dibuat dalam pertanyaan saya] harus diimplementasikan SessionHandlerInterface . Saya telah melihat panduan (direferensikan di atas) yang memberikan implementasi sessionHandler yang bukan antarmuka yang cocok. Mungkin versi PHP sebelumnya memiliki metode yang sedikit berbeda (mungkin <5.4).

  • Metode kelas sesi harus mengembalikan nilai yang ditetapkan oleh manual PHP. Sekali lagi, mungkin diwarisi dari PHP pra-5.4 tetapi dua panduan yang saya baca menyatakan bahwa class->open mengembalikan baris yang akan dibaca, sedangkan manual PHP menyatakan bahwa itu perlu mengembalikan true atau false saja.

  • Inilah penyebab Masalah Asli saya :Saya menggunakan nama sesi khusus (sebenarnya id sebagai nama sesi dan id sesi adalah hal yang sama! ) sesuai postingan StackOverflow yang sangat bagus ini dan ini menghasilkan nama sesi yang panjangnya 128 karakter. Karena nama sesi adalah satu-satunya kunci yang perlu dipecahkan untuk mengkompromikan sesi dan mengambil alih dengan pembajakan sesi maka nama/id yang lebih panjang adalah hal yang sangat bagus.

    • Namun, ini menyebabkan masalah karena MySQL secara diam-diam memotong id sesi hingga hanya 32 karakter, bukan 128, jadi tidak pernah dapat menemukan data sesi dalam database. Ini adalah masalah yang benar-benar sunyi (mungkin karena kelas koneksi database saya tidak memberikan peringatan tentang hal-hal seperti itu). Tapi ini yang harus diwaspadai. Jika Anda memiliki masalah dengan mengambil sesi dari database, periksa dulu apakah penuh id sesi dapat disimpan di kolom yang disediakan.

Jadi dengan semua itu, ada beberapa detail tambahan untuk ditambahkan juga:

Halaman manual PHP (ditautkan di atas) menunjukkan tumpukan garis yang tidak sesuai untuk objek kelas:

Padahal itu berfungsi dengan baik jika Anda meletakkan ini di konstruktor kelas:

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

Ini artinya untuk memulai sesi di halaman keluaran Anda, yang Anda butuhkan hanyalah:

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

//Bang session has been setup and started and works

Untuk referensi, kelas komunikasi Sesi lengkap adalah sebagai berikut, ini berfungsi dengan PHP 5.6 (dan mungkin 7 tetapi belum diuji pada 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();
    }

}

Penggunaan:Seperti yang ditunjukkan tepat di atas teks kode kelas.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Cloud 9 IDE tidak dapat terhubung ke database

  2. Cara Mengubah Direktori Data MySQL/MariaDB Default di Linux

  3. ssh dulu dengan mysqldb di python

  4. Menggunakan Pernyataan IF dalam kueri MySQL SELECT

  5. Bagaimana cara mengabaikan parameter dalam kueri mysqli yang disiapkan di PHP?