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接口定义的是什么?
<?php
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
<?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;
protected $name;
protected $attributes = [];
protected $handler;
protected $started = false;
public function __construct($name, SessionHandlerInterface $handler, $id = null)
{
$this->setId($id);
$this->name = $name;
$this->handler = $handler;
}
public function start()
{
$this->loadSession();
if (! $this->has('_token')) {
$this->regenerateToken();
}
return $this->started = true;
}
protected function loadSession()
{
$this->attributes = array_merge($this->attributes, $this->readFromHandler());
}
protected function readFromHandler()
{
if ($data = $this->handler->read($this->getId())) {
$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', []));
$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;
});
}
public function has($key)
{
return ! collect(is_array($key) ? $key : func_get_args())->contains(function ($key) {
return is_null($this->get($key));
});
}
public function get($key, $default = null)
{
return Arr::get($this->attributes, $key, $default);
}
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);
}
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);
});
}
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);
}
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();
});
}
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;
}
public function getName()
{
return $this->name;
}
public function setName($name)
{
$this->name = $name;
}
public function getId()
{
return $this->id;
}
public function setId($id)
{
$this->id = $this->isValidId($id) ? $id : $this->generateSessionId();
}
public function isValidId($id)
{
return is_string($id) && ctype_alnum($id) && strlen($id) === 40;
}
protected function generateSessionId()
{
return Str::random(40);
}
public function setExists($value)
{
if ($this->handler instanceof ExistenceAwareInterface) {
$this->handler->setExists($value);
}
}
public function token()
{
return $this->get('_token');
}
public function regenerateToken()
{
$this->put('_token', Str::random(40));
}
public function previousUrl()
{
return $this->get('_previous.url');
}
public function setPreviousUrl($url)
{
$this->put('_previous.url', $url);
}
public function getHandler()
{
return $this->handler;
}
public function handlerNeedsRequest()
{
return $this->handler instanceof CookieSessionHandler;
}
public function setRequestOnHandler($request)
{
if ($this->handlerNeedsRequest()) {
$this->handler->setRequest($request);
}
}
}
发表回复