php如何实现session自己实现sessionlaravel如何实现session

31次阅读

共计 6843 个字符,预计需要花费 18 分钟才能阅读完成。

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);
        }
    }
}

正文完
 0