php mysql 实现 session_php如何实现session,自己实现session,laravel如何实现session

1、php如何实现session

执行php脚本,session_start()会从php.ini中读取配置项,将生成的唯一值sessionID保存文件放到配置项中的保存路径和地点。并通过HTTP协议返回响应消息头setCookie

Cookie名=Cookie值发送给客户端。

客户端接受到Set-Cookie,将cookie值写入cookie文件

在接下来的访问中,客户端会携带cookie访问浏览器,浏览器接受到cookie值,生成http请求头将包含的COOKIE发送给Php,php识别cookie值,从保存路径中找对应的文件。

找到文件之后,检验是否在有效期内,在有效期内就读取文件,不再有效期内就清空文件

2、自己实现session需要考虑的几个问题

1)、生成唯一值的算法

2)、将session存到文件里还是存到redis还是memcache,应该存什么数据

3)、接受cookie值,从保存位置找到对应的文件或数据

4)、session垃圾回收机制,删除session文件和数据

5)、分布式的话,session同步问题

3、分析一下laravel如何实现session.

vendor/laravel/framework/src/Illuminate/Contracts定义都是接口类(契约)。向开发者提供了统一的接口类访问Session数据

看一下session接口定义的是什么?

namespace Illuminate\Contracts\Session;

interface Session

{

public function getName();//获得session名字

public function getId();//获得当前sessionID

public function setId($id);//修改sessionID

public function start();//启动session,从配置文件中读取数据

public function save();//将session数据保存

public function all();//获得所有的session

public function exists($key);//检查session名称是否存在

public function has($key);//检查session名称是否存在和不为空

public function get($key, $default = null);//通过session名称获取session值

public function put($key, $value = null);//将session名称和session值存入session文件或数据库

public function token(); //获得csrf token的值

public function remove($key);//根据session名称删除session信息

public function forget($keys);//根据session名称删除session信息

public function flush();//清空所有的session内容

public function migrate($destroy = false); //为session会话创建一个新的session会话

public function isStarted();//确定会话是否启动

public function previousUrl();//从会话中获取session的url

public function setPreviousUrl($url);//设置previous的url存入session

public function getHandler();//获得session处理实例

public function handlerNeedsRequest();//确定会话程序是否需要请求

public function setRequestOnHandler($request);//在处理请求实例上设置请求

}

实现接口类的具体实现类只有一个,也被称为驱动器

vendor/laravel/framework/src/Illuminate/Session/Store.php

namespace Illuminate\Session;

use Closure;

use stdClass;

use Illuminate\Support\Arr;

use Illuminate\Support\Str;

use SessionHandlerInterface;

use Illuminate\Contracts\Session\Session;

class Store implements Session

{

protected $id;//session id

protected $name;//session name

protected $attributes = [];//session

protected $handler;//会话处理程序实现,使用了sessionHandlerInterface接口

protected $started = false;//会话存储处理状态

public function __construct($name, SessionHandlerInterface $handler, $id = null)//创建一个新的session实例

{

$this->setId($id);

$this->name = $name;

$this->handler = $handler;

//setId

//$this->id = $this->isValidId($id) ? $id : $this->generateSessionId();

//1、 $this->isValidId($id)?

//return is_string($id) && ctype_alnum($id) && strlen($id) === 40;

//is_string($id)检查sessionid是不是字符串,ctype_alnum检查sessionid所有的字符全是字母和数字,是为true,否为false;strlen检查字符串长度是否等于40

//2、$this->generateSessionId();?

//return Str::random(40); 这个使用Str门面类生成长度为40的唯一值

//handler使用的是php预留接口类SessionnHandlerInterface,这个接口是为了将session存储到数据库中,(难怪在laravel查半天都没查到)。该类的回调方法是在php内部调用。

}

来源于vendorlaravelframeworksrcIlluminateSupportStr.php

laravel实现生成session唯一值算法函数,重点是使用了random_bytes函数和base64_encode函数

public static function random($length = 16)

{

$string = '';

while (($len = strlen($string)) < $length) {//当它的长度小于$length时

$size = $length - $len;//长度差

$bytes = random_bytes($size);//根据size生成加密安全的伪随机字节字符串

$string .= substr(str_replace(['/', '+', '='], '', base64_encode($bytes)), 0, $size);//base64_encode对其进行编码,目的时为了使二进制数据可以通过非纯8比特的传输层传输,通过str_replace函数去掉字符串的/+=3种符号,在用substr截取$size大小的字符串。

}

return $string;

}

来源于php手册中的关于SessionHandlerInterface接口的定义

SessionHandlerInterface {

/* 方法 */

abstract public close ( void ) : bool

abstract public destroy ( string $session_id ) : bool

abstract public gc ( int $maxlifetime ) : int

abstract public open ( string $save_path , string $session_name ) : bool

abstract public read ( string $session_id ) : string

abstract public write ( string $session_id , string $session_data ) :bool

}

看看都有那些类实现了SessionHandler,在编程软件中全局搜索implements SessionHandlerInterface

//CacheBasedSessionHandler 使用的实例化对象是

Illuminate/Contracts/Cache/Repository

'cache.store' => [IlluminateCacheRepository::class,

IlluminateContractsCacheRepository::class],

//CookieSessionHandler

//DatabaseSessionHandler

//FileSessionHandler

//NullSessionHandler

//根据session id读取数据

public function start()

{

$this->loadSession();

//验证csrf_token

if (! $this->has('_token')) {

$this->regenerateToken();

}

return $this->started = true;

}

protected function loadSession()

{

//array_merge合并两个数组

//readFromHandler() 从驱动器中根据session id得到session信息

$this->attributes = array_merge($this->attributes, $this->readFromHandler());

}

protected function readFromHandler()

{

if ($data = $this->handler->read($this->getId())) {

//@阻止警告输出

//unserialize反序列化读出来的session的id信息

$data = @unserialize($this->prepareForUnserialize($data));

//如果数组不是错误,不为空,是数组就返回数据

if ($data !== false && ! is_null($data) && is_array($data)) {

return $data;

}

}

return [];

}

//返回数据

protected function prepareForUnserialize($data)

{

return $data;

}

public function save()

{

$this->ageFlashData();

$this->handler->write($this->getId(), $this->prepareForStorage(

serialize($this->attributes)

));

$this->started = false;

}

protected function prepareForStorage($data)

{

return $data;

}

//使会话闪存存数据老化

public function ageFlashData()

{

$this->forget($this->get('_flash.old', []));

//其他文件定义的forget方法

> public static function forget(&$array, $keys)

> {

> $original = &$array;

>

> $keys = (array) $keys;

>

> if (count($keys) === 0) {

> return;

> }

>

> foreach ($keys as $key) {

> // if the exact key exists in the top-level, remove it

> if (static::exists($array, $key)) {

> unset($array[$key]);

>

> continue;

> }

>

> $parts = explode('.', $key);

>

> // clean up before each pass

> $array = &$original;

>

> while (count($parts) > 1) {

> $part = array_shift($parts);

>

> if (isset($array[$part]) && is_array($array[$part])) {

> $array = &$array[$part];

> } else {

> continue 2;

> }

> }

>

> unset($array[array_shift($parts)]);

> }

> }

$this->put('_flash.old', $this->get('_flash.new', []));

$this->put('_flash.new', []);

}

public function all()

{

return $this->attributes;

}

public function exists($key)

{

$placeholder = new stdClass;

return ! collect(is_array($key) ? $key : func_get_args())->contains(function ($key) use ($placeholder) {

return $this->get($key, $placeholder) === $placeholder;

});

}

//检查是否存在Key值

public function has($key)

{

return ! collect(is_array($key) ? $key : func_get_args())->contains(function ($key) {

return is_null($this->get($key));

});

}

//获取session信息

public function get($key, $default = null)

{

return Arr::get($this->attributes, $key, $default);

}

//删除,类似pop

public function pull($key, $default = null)

{

return Arr::pull($this->attributes, $key, $default);

}

public function hasOldInput($key = null)

{

$old = $this->getOldInput($key);

return is_null($key) ? count($old) > 0 : ! is_null($old);

}

public function getOldInput($key = null, $default = null)

{

return Arr::get($this->get('_old_input', []), $key, $default);

}

public function replace(array $attributes)

{

$this->put($attributes);

}

//session永久保存,在不过期范围内

public function put($key, $value = null)

{

if (! is_array($key)) {

$key = [$key => $value];

}

foreach ($key as $arrayKey => $arrayValue) {

Arr::set($this->attributes, $arrayKey, $arrayValue);

}

}

public function remember($key, Closure $callback)

{

if (! is_null($value = $this->get($key))) {

return $value;

}

return tap($callback(), function ($value) use ($key) {

$this->put($key, $value);

});

}

//类似于push

public function push($key, $value)

{

$array = $this->get($key, []);

$array[] = $value;

$this->put($key, $array);

}

public function increment($key, $amount = 1)

{

$this->put($key, $value = $this->get($key, 0) + $amount);

return $value;

}

public function decrement($key, $amount = 1)

{

return $this->increment($key, $amount * -1);

}

//快闪保存,只保存两次请求

public function flash(string $key, $value = true)

{

$this->put($key, $value);

$this->push('_flash.new', $key);

$this->removeFromOldFlashData([$key]);

}

public function now($key, $value)

{

$this->put($key, $value);

$this->push('_flash.old', $key);

}

public function reflash()

{

$this->mergeNewFlashes($this->get('_flash.old', []));

$this->put('_flash.old', []);

}

//刷新快闪数据时间,保持到下次请求

public function keep($keys = null)

{

$this->mergeNewFlashes($keys = is_array($keys) ? $keys : func_get_args());

$this->removeFromOldFlashData($keys);

}

protected function mergeNewFlashes(array $keys)

{

$values = array_unique(array_merge($this->get('_flash.new', []), $keys));

$this->put('_flash.new', $values);

}

protected function removeFromOldFlashData(array $keys)

{

$this->put('_flash.old', array_diff($this->get('_flash.old', []), $keys));

}

public function flashInput(array $value)

{

$this->flash('_old_input', $value);

}

public function remove($key)

{

return Arr::pull($this->attributes, $key);

}

public function forget($keys)

{

Arr::forget($this->attributes, $keys);

}

//每次flush将数组置空

public function flush()

{

$this->attributes = [];

}

public function invalidate()

{

$this->flush();

return $this->migrate(true);

}

public function regenerate($destroy = false)

{

return tap($this->migrate($destroy), function () {

$this->regenerateToken();

});

}

//给session生成一个新的sessionID

public function migrate($destroy = false)

{

//如果

if ($destroy) {

$this->handler->destroy($this->getId());

}

$this->setExists(false);

$this->setId($this->generateSessionId());

return true;

}

//是否启动

public function isStarted()

{

return $this->started;

}

//获取session名

public function getName()

{

return $this->name;

}

//设置session 名

public function setName($name)

{

$this->name = $name;

}

//获取session id

public function getId()

{

return $this->id;

}

//如果sessionid有效,就返回有效id,如果失效就生成session id

public function setId($id)

{

$this->id = $this->isValidId($id) ? $id : $this->generateSessionId();

}

//检查session id

public function isValidId($id)

{

return is_string($id) && ctype_alnum($id) && strlen($id) === 40;

}

//获取sessionID 唯一的40长度值

protected function generateSessionId()

{

return Str::random(40);

}

//如果适用,在处理程序上设置会话的存在性

public function setExists($value)

{

if ($this->handler instanceof ExistenceAwareInterface) {

$this->handler->setExists($value);

}

}

//获取token值

public function token()

{

return $this->get('_token');

}

//生成唯一值40,存入_token

public function regenerateToken()

{

$this->put('_token', Str::random(40));

}

//获取当前url

public function previousUrl()

{

return $this->get('_previous.url');

}

//存储当前url

public function setPreviousUrl($url)

{

$this->put('_previous.url', $url);

}

//获取当前使用的驱动器

public function getHandler()

{

return $this->handler;

}

//返回驱动器实例是否使CokieSessionHandler

public function handlerNeedsRequest()

{

return $this->handler instanceof CookieSessionHandler;

}

//如果驱动器是CookieSessionHandler,那么执行setRequest方法

public function setRequestOnHandler($request)

{

if ($this->handlerNeedsRequest()) {

$this->handler->setRequest($request);

}

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值