专栏首页仙士可博客php session基本原理解析

php session基本原理解析

该类实现了php session的基本原理操作

由于session比较简单,直接封装出了session的基本操作

<?php
/**
 * Created by PhpStorm.
 * User: 10671
 * Date: 2018/6/22
 * Time: 23:48
 */

class SessionHandle
{

    private static $_instance;

    private $config = array(
        'cookie_name' => 'session_id',
        'cookie_path' => '',
        'cookie_domain' => '',
        'cookie_secure' => false,

        'save_path' => __DIR__ . DIRECTORY_SEPARATOR . 'runtime' . DIRECTORY_SEPARATOR,//保存路径
        'save_path_num' => 5,//保存目录数(以免造成一个目录太多session文件,0则保存在当前目录)

        'cache_expire' => 30 * 60,//过期时间
        'session_handler' => null,
        'gc_probability' => 1//触发垃圾回收概率1/100
    );

    public $path_dictionary = array(
        'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
    );

    public function __construct($config = array())
    {
        foreach ($config as $key => $value) {
            if (isset($this->config[$key])) {
                $this->config[$key] = $value;
            }
        }
        
    }
    
        public function __destruct()
        {
            $this->saveSession();
        }


    /**
     * 单例
     * @return SessionHandle
     */
    public static function getInstance($config=array())
    {
        if (!(self::$_instance instanceof self)) {
            self::$_instance = new static($config); //new static和new self区别可查看http://www.jb51.net/article/54167.htm
        }
        return self::$_instance;
    }

    /**
     * 开始设置session
     */
    public function startSession($session_id = null)
    {
        if (is_callable($this->config['session_handler'])) {
            return $this->config['session_handler']('start_session');
        }
        if (mt_rand(1, 100) <= $this->config['gc_probability']) {
            $this->gc();
        }
        if (!isset($_COOKIE[$this->config['cookie_name']])) {
            $session_id === null && $session_id = $this->getSessionId();
            $this->setCookie($session_id);
            $this->saveSessionData($session_id, array());
        } else {
            $session_id = $_COOKIE[$this->config['cookie_name']];
        }
        return $data = $_SESSION = $this->getSessionData($session_id);
    }

    /**
     * 设置
     * @param $session_id
     * @param $name
     * @param $value
     */
    public function setSession($name, $value, $session_id = null)
    {
        $session_id === null && $session_id = $this->getSessionId();
        $data = $this->getSessionData($session_id);
        if (empty($name)) {
            return false;
        }
        if ($value == null) {
            unset($data[$name]);
        }
        $data[$name] = $value;
        $result = $this->saveSessionData($session_id, $data);
        if ($result === false) {
            return $result;
        }
        return $_SESSION = $data;
    }

    /**
     * 保存数据到文件
     * @param null $session_id
     * @param null $data
     * @return bool|int|null
     */
    public function saveSession($session_id=null,$data=null){
        $session_id === null && $session_id = $this->getSessionId();
        $data === null && $data = $_SESSION;
        if (is_callable($this->config['session_handler'])) {
            return $this->config['session_handler']('save_session', $session_id);
        }
        $result = $this->saveSessionData($session_id, $data);
        if ($result === false) {
            return $result;
        }
        return $_SESSION = $data;
    }

    /**
     * 删除
     * @param null $session_id
     * @return bool
     */
    public function deleteSession($session_id = null)
    {
        $session_id === null && $session_id = $this->getSessionId();
        $result = $this->deleteSessionData($session_id);
        $this->setCookie('');
        $_SESSION = array();
        return $result;
    }

    /**
     * 设置cookie
     * @param $session_id
     */
    public function setCookie($session_id)
    {
        setcookie($this->config['cookie_name'], $session_id, time() + $this->config['cache_expire'], $this->config['cookie_path'], $this->config['cookie_domain'], $this->config['cookie_secure']);
    }

    /**
     * 获取session_id
     * @param $session_id
     * @return mixed
     */
    public function getSessionData($session_id)
    {
        if (is_callable($this->config['session_handler'])) {
            return $this->config['session_handler']('read', $session_id);
        }
        $this->updateSessionIndex($session_id);
        $data = serialize(array());
        if (file_exists($this->getSessionIDPath($session_id))) {
            $data = file_get_contents($this->getSessionIDPath($session_id));
        }
        return unserialize($data);
    }

    /**
     * 修改保存
     * @param $session_id
     * @param $data
     * @return bool|int
     */
    public function saveSessionData($session_id, $data)
    {
        if (is_callable($this->config['session_handler'])) {
            return $this->config['session_handler']('save', $session_id, $data);
        }
        $this->updateSessionIndex($session_id);
        $result = file_put_contents($this->getSessionIDPath($session_id), serialize($data));
        return $result;
    }

    /**
     * 删除文件
     * @param $session_id
     * @return bool
     */
    public function deleteSessionData($session_id)
    {
        if (is_callable($this->config['session_handler'])) {
            return $this->config['session_handler']('delete', $session_id);
        }
        return unlink($this->getSessionIDPath($session_id));
    }

    /**
     * 设置session处理
     * @param callable $function
     */
    public function setSessionHandler(callable $function)
    {
        $this->config['session_handler'] = $function;
    }

    /**
     * 获取sessionid的路径
     * @param $session_id
     * @return string
     */
    public function getSessionIDPath($session_id)
    {
        if (abs($this->config['save_path_num']) == 0) {
            $path = $this->config['save_path'];
        } else {
            $path = $this->config['save_path'] . $this->path_dictionary[$this->time33($session_id) % $this->config['save_path_num']] . DIRECTORY_SEPARATOR;
        }
        if (!is_dir($path)) {
            @mkdir($path);
        }
        return $path . $session_id;
    }

    /**
     * 垃圾回收
     * @return bool|int
     */
    public function gc()
    {
        if (is_callable($this->config['session_handler'])) {
            return $this->config['session_handler']('gc');
        }
        if ($this->config['cache_expire'] <= 0) {
            return true;
        }
        $session_index_path = $this->config['save_path'] . 'index';
        $session_index = unserialize(file_get_contents($session_index_path));
        foreach ($session_index as $session_id => $value) {
            if ($value + $this->config['cache_expire'] < time()) {
                unset($session_index[$session_id]);
                @unlink($this->deleteSessionData($session_id));
            }
        }
        $result = file_put_contents($session_index_path, serialize($session_index));
        return $result;
    }

    /**
     * 更新session索引
     * @param null $session_id
     */
    public function updateSessionIndex($session_id = null)
    {
        if (is_callable($this->config['session_handler'])) {
            return $this->config['session_handler']('update_session_index', $session_id);
        }
        if ($this->config['cache_expire'] <= 0) {
            return true;
        }
        $session_id === null && $session_id = $this->getSessionId();
        $session_index_path = $this->config['save_path'] . 'index';
        $session_index = array();
        if (file_exists($session_index_path)) {
            $session_index = unserialize(file_get_contents($session_index_path));
        }
        $session_index[$session_id] = time();
        $result = file_put_contents($session_index_path, serialize($session_index));
        return $result;
    }

    /**
     * 生成一个尽量唯一的字符串
     */
    public function getSessionId()
    {
        $session_id = null;
        if (isset($_COOKIE[$this->config['cookie_name']])) {
            $session_id = $_COOKIE[$this->config['cookie_name']];
        }
        if (empty($session_id)) {
            if (is_callable($this->config['session_handler'])) {
                return $this->config['session_handler']('create_session_id');
            }
            $key = uniqid(mt_rand(100000, 999999));
            $session_id = $this->md5($key);
        }
        return $session_id;
    }

    public function md5($str)
    {
        $hash = md5($str);
        return $hash;
    }

    public function time33($str)
    {
        $hash = 0;
        $s = md5($str);
        $len = 32;
        for ($i = 0; $i < $len; $i++) {
            $hash = ($hash * 33 + ord($s{$i})) & 0x7FFFFFFF;
        }
        return $hash;
    }
}

该类实现了php基本的session原理

调用方法:

include 'SessionHandle.php';

$session_handle = SessionHandle::getInstance();
//var_dump($session_handle);
$session_handle->startSession();
//$session_handle->deleteSession();
//$session_handle->setSession('name','ncl');
var_dump($_SESSION);

本文为仙士可原创文章,转载无需和我联系,但请注明来自仙士可博客www.php20.cn

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • PHP设置Redis储存Session

    我们在之前的文章已经讲到了session是将数据储存在本地文件中,并且将session_id返回给客户端(浏览器会储存在cookies里)。

    仙士可
  • 深入了解session的执行步骤

    第一次访问php,则会随机生成一个session文件发送header头,等待浏览器第二次请求携带cookie,进行判断session_id,我们可以通过上面已经...

    仙士可
  • windows php关于session临时文件的一个坑

    在windows服务器上,php的session默认保存在C:\WINDOWS\Temp文件夹下面

    仙士可
  • 实训任务—二次幂的进阶表示

    = 2(2(2)+2(1))+2(2(2))+2(2(1))+2(1)+2(0)

    程序员周同学
  • 求取一份极致的简单:全链路跟踪中间件探索之路

    公司内部的业务系统有近千个,基本上很少有比较孤立的;尤其外部系统,即便用户在页面上一个很普通的操作,后台也需要少则几个多则几十个服务协同完成。以前我们定位调用链...

    李海彬
  • ExtJS4预览:渲染过程重构和标准化

    在过去的四年,ExtJs代码库已经进化了,新组件被加进来,编码标准也改进了。在这个过程中,为了重构旧组件有必要经常追溯回去以保证他们也被改进。 在ExtJS4...

    用户1183026
  • react实践笔记:父子组件数值双向传递

        在编写 react 组件时,经常会遇到一个场景:子组件有个状态,可以通过内部的一个按钮进行切换;而父组件也可以通过一个按钮,同步去切换子组件的状态。比如...

    zww_v5
  • Django实战-生鲜电商-小结-下

    由于本项目配置了缓存机制,需要在 settings.py 文件中设置。配置redis作为cache和session的存储。

    小团子
  • React之父子组件传递和其它一些要点

    react是R系技术栈中最基础同时也是最核心的一环,2年不到获取了62.5k star(截止到目前),足可见其给力程度。下面对一些react日常开发中的注意事项...

    牧云云
  • Flutter最佳入门方式:写一个计算器

    工作以来,我在学习新知识的时候,常常与在应试教育阶段被传授的方法作斗争——把书本的内容100%复制到脑中才算学会吗?不会被使用或者不常用的知识,花费大量功夫去记...

    用户1269200

扫码关注云+社区

领取腾讯云代金券