PHP的Session機制解析 1


一、php的默認session機制


php默認用磁盤文件來實現session
在php.ini中session.save_handler = files定義session機制
session.save_path="D:\dev\xampp\tmp" 定義session的存儲位置

1.1、啟動session
session_start()。
sesson_start()函數是啟動session的開始,session默認存放在文件中,且具有一定概率觸發session的垃圾回收機制。
php自身的垃圾回收對session是無效的,因為默認session是存放在文件中的。
session的垃圾回收概率是根據
session.gc_probability =1
session.gc_divisor =1000
session.gc_maxlifetime =1440//過期時間 默認24分鍾
這三個參數去計算的。
計算規則為:
觸發概率 = session.gc_probability / session.gc_divisor; 結果 1/1000,

1.2、配置session.save_path
session.save_path在php.ini中提供了不同的配置方式:
session.save_path="D:\dev\xampp\tmp"
session.save_path="N;D:\dev\xampp\tmp"
其中N為正整數,表示目錄分級存放:
若N=2,假設此時sessionId為 63f2k77g4r0ls06g3p93t0cpkd
那么,session信息的存放格式為:
D:\dev\xampp\tmp\6\3\sess_63f2k77g4r0ls06g3p93t0cpkd
使用分級存放時,session的垃圾回收機制將會無效,需要自己寫腳本處理過期session文件。
且子目錄php不會自己創建,需要手動去創建6/3/目錄。
如果分2級存放,可以通過腳本去事先創建好:

function createSessionDir ()
{
    $basePath = trim(explode(';', session_save_path())[1], '/\\');
    $str = '0123456789abcdefghijklmnopqrstuvwxyz';
    $len = strlen($str);
    for ($i = 0; $i < $len; $i++) {
        for ($j = 0; $j < $len; $j++) {
            $path = $basePath . DIRECTORY_SEPARATOR . $str[$i] . DIRECTORY_SEPARATOR . $str[$j];
            if (!@file_exists($path)) {
                mkdir($basePath . DIRECTORY_SEPARATOR . $str[$i] . DIRECTORY_SEPARATOR . $str[$j]);
            }

        }
    }
}

1.3、sessionId
$_COOKIE[session_name()];中存放了當前session的sessionId信息。
其中session_name()取的是php.ini中的session.name = PHPSESSID 的值。

如果不存在會生成一個sessionId,然后將id作為cookie的值傳遞到客戶端。
相當於執行setcookie()函數:

setcookie(session_name(),
    session_id(),
    session.cookie_lifetime,//默認0
    session.cookie_path,//默認'/',當前程序跟目錄下都有效
    session.cookie_domain,//默認為空
)

按照php手冊里的說明,使用setcookie()之前不能有任何輸出,但是我測試時,在函數之前echo了內容是不會報錯的。
原因是php5.3版本以下時,php.ini有一項配置output_buffering,此配置項,在php5.3以下是默認為0,在5.3以上則默認是4096。
因為使用的版本大於5.3,所以在測試的時候,默認是開啟output_buffering的。
開啟output_buffering的時候,無論是echo,還是var_dump,print_r,任何輸出,都會在php腳本結束時,統一隨着http響應返回給客戶端,(超過4096大小時,可能會分段返回)。所以不會報錯。

1.4、session賦值
添加一個session值:$_SESSION['name]='zhangsan',此時這個值會在內存中存在,當腳本執行完畢時,會將其寫入到指定sessionId的文件中,然后關閉資源。
如網頁的匿名用戶存在一個session,當登錄后需要更換session:

//刪除舊的session信息
if (isset($_COOKIE[session_name()])) {
    setcookie(session_name(), '', time() - 86400);
}
session_regenerate_id();//重新生成sessionId

1.5、銷毀session信息
cookie中攜帶的session信息為即時cookie,保存在瀏覽器中,當瀏覽器關閉后,才會過期。
但是一般我們在用戶退出登錄時,就需要銷毀其cookie和session信息,銷毀的方式:

a、setcookie(session_name(), session_id(), time() - 86400);//退出登錄前執行
b、unset($_SESSION);//會刪除所有的$_SESSION數據,刷新后,有COOKIE傳過來,但是沒有數據
c、session_destroy();//徹底刪除$_SESSION並刪除session文件和sessionId

當不關閉瀏覽器的情況下,再次刷新,b和c都會有COOKIE傳過來,但是找不到數據。

二、用戶自定義處理機制
php.ini中配置session.save_handler = user 就會觸發自定義處理機制其中user字符是隨意的,不固定。
自 PHP 5.4 開始,可以使用下面的方式來注冊自定義會話存儲函數:
session_set_save_handler ( object $sessionhandler [, bool $register_shutdown = TRUE ] ) : bool
sessionhandler為實現了 SessionHandlerInterface接口的對象

MySession.php
<?php
/**
 * Desc: 自定義session處理機制,>5.4
 * Class: Session
 * User: zb
 * Date: 2019/6/14 18:32
 */

class MySession implements SessionHandlerInterface
{
    private $savePath;

    public function close ()
    {
        return true;
    }

    public function destroy ($sessionId)
    {
        $file = $this->savePath . '/sess_' . $sessionId;
        if (file_exists($file)) {
            @unlink($file);
        }
        return true;
    }

    public function gc ($maxlifetime)
    {
        $sessionFiles = glob($this->savePath . '/sess_*');
        foreach ($sessionFiles as $file) {
            if (file_exists($file) && filemtime($file) + $maxlifetime < time()) {
                @unlink($file);
            }
        }
        return true;
    }

    public function open ($savePath, $sessionName)
    {
        $this->savePath = $savePath;
        if (!is_dir($this->savePath)) {
            mkdir($this->savePath, 0777);
        }

        return true;
    }

    public function read ($sessionId)
    {
        return (string)@file_get_contents($this->savePath . '/sess_' . $sessionId);
    }

    public function write ($sessionId, $sessionData)
    {
        return @file_put_contents($this->savePath . '/sess_' . $sessionId, $sessionData) === false ? false : true;
    }
}

使用自定義session機制:

index.php
<?php
/**
 * Desc: xxx
 * User: zb
 * Date: 2019/6/14 18:32
 */
include 'MySession.php';
$mySession = new MySession();
session_set_save_handler($mySession, true);
session_start();
if (!empty($_GET) && $_GET['user'] && $_GET['passwd']) {
    $_SESSION['user'] = $_GET['user'];
    $_SESSION['passwd'] = $_GET['passwd'];
    printInfo($_SESSION, 'allSessionData');
    printInfo($_COOKIE[session_name()], 'sessionId');
} else {
    printInfo('get無數據');
}

function printInfo ($val, $key = '')
{
    header('Content-Type', 'text/html; charset=UTF-8');
    $val = var_export($val, true);
    if ($key) {
        $val = $key . ' => ' . $val;
    }
    echo $val;
    echo "<br>";
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM