最近在做一个自己家用的物联网项目,其中服务器端采用thinkphp5和workman搭建的后台,开发过程中发现workman获取不到thinkphp的Session数据。经过研究最终找到了一个思路,现在波波将相关思路分享如下。
其实仔细阅读Workman文档会发现Workman运行在CLI模式下,其Session用法与thinkPHP的会话方式有很大的区别,所以这里波波引用了一个Session共享的方法。如下图所示:
这个方法就是我们把MVC的Session数据保存在Redis中,Workman需要读取MVC框架Session的时候可以直接读取Redis数据,这个过程中需要PHP开启Redis扩展,不仅运行与CGI模式下的需要开启,运行于CLI模式下的PHP同样需要开启(主要防止多版本共存情况出现错误)。
原理就是Session共享的思路,很简单。下面波波分享一下波波为Workman写的Redis数据驱动。与workman一起运行于CLI模式下。
- <?php
- /**
- * Created by bobo.
- * DateTime: 2019/11/16 13:40
- * Function:Workman MVC session验证器
- */
- namespace app\pigeon\model;
- class EventsModel{
- //Redis配置
- protected $options = [
- 'host' => '127.0.0.1',
- 'port' => 6379,
- 'password' => '',
- 'select' => 0,
- 'timeout' => 0,
- 'expire' => 0,
- 'persistent' => false,
- 'prefix' => '',
- ];
- //构造函数
- public function __construct($options = []){
- if (!extension_loaded('redis')) {
- throw new \Exception('not support: redis');
- }
- if (!emptyempty($options)) {
- $this->options = array_merge($this->options, $options);
- }
- $func = $this->options['persistent'] ? 'pconnect' : 'connect';
- $this->handler = new \Redis;
- $this->handler->$func($this->options['host'], $this->options['port'], $this->options['timeout']);
- if ('' != $this->options['password']) {
- $this->handler->auth($this->options['password']);
- }
- if (0 != $this->options['select']) {
- $this->handler->select($this->options['select']);
- }
- }
- protected function getCacheKey($name){
- return $this->options['prefix'] . $name;
- }
- public function has($name)
- {
- return $this->handler->get($this->getCacheKey($name)) ? true : false;
- }
- //设置标签
- protected function setTagItem($name)
- {
- if ($this->tag) {
- $key = 'tag_' . md5($this->tag);
- $this->tag = null;
- if ($this->has($key)) {
- $value = explode(',', $this->get($key));
- $value[] = $name;
- $value = implode(',', array_unique($value));
- } else {
- $value = $name;
- }
- $this->set($key, $value, 0);
- }
- }
- //查询Redis数据
- public function get($name, $default = false){
- $value = $this->handler->get($this->getCacheKey($name));
- if (is_null($value)) {
- return $default;
- }
- $jsonData = json_decode($value, true);
- // 检测是否为JSON数据 true 返回JSON解析数组, false返回源数据
- return (null === $jsonData) ? $value : $jsonData;
- }
- //写入Redis数据
- public function set($name, $value, $expire = null)
- {
- if (is_null($expire)) {
- $expire = $this->options['expire'];
- }
- if ($expire instanceof \DateTime) {
- $expire = $expire->getTimestamp() - time();
- }
- if ($this->tag && !$this->has($name)) {
- $first = true;
- }
- $key = $this->getCacheKey($name);
- //对数组/对象数据进行缓存处理,保证数据完整性
- $value = (is_object($value) || is_array($value)) ? json_encode($value) : $value;
- if (is_int($expire) && $expire) {
- $result = $this->handler->setex($key, $expire, $value);
- } else {
- $result = $this->handler->set($key, $value);
- }
- isset($first) && $this->setTagItem($key);
- return $result;
- }
- }
因为我在写这部分代码的时候结合MVC写到了model层,大家可以自己重新定义命名空间。到此彻底解决了workman无法获取Session数据的问题了。
总结:
其实关于用户信息的验证有很多种方法,为什么我一直纠结必须用Session呢?因为对于MVC框架来说,用户的Session意味着用户在线的活跃状态,随着用户关闭页面而终止(其实有过期时间),这在最大程度上可以保障用户信息的安全性和有效性。那么做为一个后端开发的人来讲,我们必须要力求逻辑的严谨性,虽然失误总是不可避免,BUG总会出现,但是只有力求完美才能给客户、给自己开发出稳定、安全的系统。