PHP存储Session

一 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_probabilitysession.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);
?>


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,755评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,369评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,799评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,910评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,096评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,159评论 3 411
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,917评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,360评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,673评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,814评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,509评论 4 334
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,156评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,882评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,123评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,641评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,728评论 2 351

推荐阅读更多精彩内容

  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,603评论 18 399
  • 参考: Session Handling Session Functions (一)session session...
    咚门阅读 1,648评论 0 7
  • php.ini设置,上传大文件: post_max_size = 128Mupload_max_filesize ...
    bycall阅读 6,744评论 3 64
  • 从三月份找实习到现在,面了一些公司,挂了不少,但最终还是拿到小米、百度、阿里、京东、新浪、CVTE、乐视家的研发岗...
    时芥蓝阅读 42,218评论 11 349
  • 十八年前的一把伞,摆渡了两个人,一个布政史,一个按察使。这把伞,十八年前,摆渡的是友谊小义,十八年后,摆渡的是天下...
    小兵写作业阅读 337评论 2 6