1. 程式人生 > >PHP存儲Session

PHP存儲Session

primary div bool efault sqli 保存數據 link server call

一 Redis

方法一: 配置文件php.ini,修改為下面內容,保存並重啟服務

session.save_handler = redis
session.save_path = "tcp://127.0.0.1:6379"

方法二: 直接在代碼中加入以下內容:

<?php  
ini_set("session.save_handler", "redis");
ini_set("session.save_path", "tcp://127.0.0.1:6379");
?>

如果redis配置文件redis.conf裏設置了連接密碼requirepass,save_path需要這樣寫tcp://127.0.0.1:6379?auth=

連接密碼

二 Memcache

方式一: php.ini 文件,修改下面兩個參數:

session.save_handler = memcache  
session.save_path = "tcp://Mem服務器1:端口號,tcp://Mem服務器2:端口號..."

方式二: 在 php 文件中使用 ini_set 函數

<?php  
ini_set("session.save_handler", "memcache");  
ini_set("session.save_path", "tcp://Mem服務器1:端口號,tcp://Mem服務器2:端口號...");  
?>

如果安裝的PECL是memcached(使用libmemcache庫的那個),則配置應為:

ini_set("session.save_handler", "memcached"); // 不是memcache
ini_set("session.save_path", "127.0.0.1:11211"); // 不要tcp:

三 回調函數方式

bool session_set_save_handler ( callable $open , callable $close , callable $read , callable $write , callable $destroy
, callable $gc , callable $create_sid )

  • open
    自動開始會話或者通過調用 session_start() 手動開始會話之後第一個被調用的回調函數。 成功返回 TRUE,反之返回 FALSE

  • close
    回調函數類似於類的析構函數。腳本執行完成調用 session_write_close() session_destroy() 時被執行,即在所有session操作完後被執行。

  • read
    會話讀取數據,read 回調函數必須返回將會話 數據編碼(序列化)後的字符串。 如果會話中沒有數據,read 回調函數返回空字符串。 在調用 read 之前,PHP 會調用 open 回調函數。read 回調返回的序列化之後的字符串格式必須與 write 回調函數保存數據時的格式完全一致。 PHP 會自動反序列化返回的字符串並填充 $_SESSION 超級全局變量。 雖然數據看起來和 serialize() 函數很相似, 但是需要提醒的是,它們是不同的。 請參考: session.serialize_handler。

  • write
    會話保存數據。 此回調函數接收當前會話 ID 以及 $_SESSION 中數據序列化之後的字符串作為參數。 序列化會話數據的過程由 PHP 根據 session.serialize_handler 設定值來完成。PHP 會在腳本執行完畢或調用 session_write_close() 函數之後調用此回調函數。 註意,在調用完此回調函數之後,PHP 內部會調用 close 回調函數。
    PHP 會在輸出流寫入完畢並且關閉之後 才調用 write 回調函數, 所以在 write 回調函數中的調試信息不會輸出到瀏覽器中。 如果需要在 write 回調函數中使用調試輸出, 建議將調試輸出寫入到文件。

  • destroy
    當調用 session_destroy()函數, 或者調用session_regenerate_id()函數並且設置 destroy 參數為 TRUE 時, 會調用此回調函數。

  • gc
    清理會話中的舊數據,PHP 會不時的調用垃圾收集回調函數。 調用周期由 session.gc_probability session.gc_divisor參數控制。 傳入到此回調函數的 lifetime 參數由 session.gc_maxlifetime 設置。

  • create_sid
    當需要新的會話 ID 時被調用的回調函數。

<?php 


class FileSessionHandler { 
    
    private $savePath;  
    //啟動session
    function open($savePath, $sessionName) { 
        $this->savePath = $savePath; 
        if (!is_dir($this->savePath)) { 
            mkdir($this->savePath, 0777); 
        } 
        return true;
    } 
    
    //關閉session 
    function close() { 
        return true;
    } 
    
    //讀取session 
    function read($id) { 
        return (string)@file_get_contents("$this->savePath/sess_$id"); 
    } 
    
    //寫入session 
    function write($id, $data) { 
        return file_put_contents("$this->savePath/sess_$id", $data) === false ? false : true; 
    } 

    //銷毀session 
    function destroy($id) { 
        $file = "$this->savePath/sess_$id"; 
        if (file_exists($file)) { 
            unlink($file); 
        } 
        return true; 
    } 

    //銷毀session 
    function gc($maxlifetime) { 
        foreach (glob("$this->savePath/sess_*") as $file) { 
            if (filemtime($file) + $maxlifetime < time() && file_exists($file)) { 
                unlink($file); 
            } 
        } 
        return true; 
    } 

} 

$handler = new FileSessionHandler(); 

session_set_save_handler( 
    array($handler, open), 
    array($handler, close), 
    array($handler, read), 
    array($handler, write), 
    array($handler, destroy), 
    array($handler, gc)
); 
// 下面這行代碼可以防止使用對象作為會話保存管理器時可能引發的非預期行為
// 腳本執行完畢之後,內部會清除對象,有可能不調用 write 和 close 回調函數。
register_shutdown_function(session_write_close); 
session_start(); 
// 現在可以使用 $_SESSION 保存以及獲取數據了

四 會話類處理類

使用sessionhandler添加加密PHP內部保存處理程序。

<?php 

/** decrypt AES 256 
 * @param data $edata 
 * @param string $password 
 * @return decrypted data 
 */ 

function decrypt($edata, $password) { 
    $data = base64_decode($edata); 
    $salt = substr($data, 0, 16); 
    $ct = substr($data, 16); 
    $rounds = 3; 
    // depends on key length 
    $data00 = $password.$salt; 
    $hash = array(); 
    $hash[0] = hash(sha256, $data00, true); 
    $result = $hash[0]; 
    for ($i = 1; $i < $rounds; $i++) { 
        $hash[$i] = hash(sha256, $hash[$i - 1].$data00, true); 
        $result .= $hash[$i]; 
    } 
    $key = substr($result, 0, 32); 
    $iv = substr($result, 32,16); 
    return openssl_decrypt($ct, AES-256-CBC, $key, true, $iv); 
} 

/** 
 * crypt AES 256 
 * @param data $data
 * @param string $password
 * @return base64 encrypted data
 */
function encrypt($data, $password) { 
    // Set a random salt 
    $salt = openssl_random_pseudo_bytes(16); 
    $salted = ‘‘; $dx = ‘‘; 
    // Salt the key(32) and iv(16) = 48 
    while (strlen($salted) < 48) { 
        $dx = hash(sha256, $dx.$password.$salt, true); 
        $salted .= $dx; 
    } 
    $key = substr($salted, 0, 32); 
    $iv = substr($salted, 32,16); 
    $encrypted_data = openssl_encrypt($data, AES-256-CBC, $key, true, $iv); 
    return base64_encode($salt . $encrypted_data); 
} 


class EncryptedSessionHandler extends SessionHandler { 
    private $key; 
    
    public function __construct($key) { 
        $this->key = $key; 
    } 

    public function read($id) { 
        $data = parent::read($id); 
        if (!$data) { 
            return ""; 
        } else { 
            return decrypt($data, $this->key); 
        } 
    } 

    public function write($id, $data) { 
        $data = encrypt($data, $this->key); 
        return parent::write($id, $data); 
    } 
} 

ini_set(session.save_handler, files); 
$key = secret_string; 
$handler = new EncryptedSessionHandler($key); 
session_set_save_handler($handler, true); 
session_start();

五 會話管理器接口

PHP > 5.4

//Database 
CREATE TABLE `Session` ( 
    `Session_Id` varchar(255) COLLATE utf8_unicode_ci NOT NULL,             
    `Session_Expires` datetime NOT NULL, 
    `Session_Data` text COLLATE utf8_unicode_ci, 
    PRIMARY KEY (`Session_Id`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 
SELECT * FROM mydatabase.Session;
<?php 

class SysSession implements SessionHandlerInterface { 
    private $link; 
    //開啟session 
    public function open($savePath, $sessionName) { 
        $link = mysqli_connect("server","user","pwd","mydatabase"); 
        if($link){ 
            $this->link = $link; 
            return true; 
        }else{ 
            return false; 
        } 
    } 

    //關閉session 
    public function close() { 
        mysqli_close($this->link); 
        return true; 
    } 

    //讀取session 
    public function read($id) { 
        $sql = "SELECT Session_Data FROM Session WHERE Session_Id = ‘".$id."‘ AND Session_Expires > ‘".date(Y-m-d H:i:s).""; 
        $result = mysqli_query($this->link,$sql); 
        if($row = mysqli_fetch_assoc($result)){ 
            return $row[Session_Data]; 
        }else{ 
            return ""; 
        } 
    } 

    //寫入session 
    public function write($id, $data) { 
        $DateTime = date(Y-m-d H:i:s); 
        $NewDateTime = date(Y-m-d H:i:s,strtotime($DateTime. + 1 hour)); 
        $sql = "REPLACE INTO Session SET Session_Id = ‘".$id."‘, Session_Expires = ‘".$NewDateTime."‘, Session_Data = ‘".$data.""; 
        $result = mysqli_query($this->link,$sql ); 
        if($result){ 
            return true; 
        }else{ 
            return false; 
        } 
    } 

    //銷毀session 
    public function destroy($id) { 
        $sql = "DELETE FROM Session WHERE Session_Id =‘".$id.""; 
        $result = mysqli_query($this->link,$sql); 
        if($result){ 
            return true; 
        }else{ 
            return false; 
        } 
    } 

    //回收session 
    public function gc($maxlifetime) { 
        $sql = "DELETE FROM Session WHERE ((UNIX_TIMESTAMP(Session_Expires) + ".$maxlifetime.") < ".$maxlifetime.")"; 
        $result = mysqli_query($this->link,$sql); 
        if($result){ 
            return true; 
        }else{ 
            return false; 
        } 
    } 

} 


$handler = new SysSession(); 
// 下面這行代碼可以防止使用對象作為會話保存管理器時可能引發的非預期行為 
session_set_save_handler($handler, true);

PHP存儲Session