thinkPHP3.2 、thinkPHP5 结合workerman + Redis 实现账号单点登录

  • thinkPHP3.2  与workerman 结合
  1. 首先下载wokerman,放到TP项目下面的ThinkPHP/Library目录,并命名为Workerman
  2. 除Constants.php以外的所有php文件改为.class.php后缀
  3. 代码块

        Js代码


        var uid = sessionStorage.getItem('userid'); // 登录平台用户id, 登录时存入
            
        var ws = new WebSocket("ws://127.0.0.1:2346");  // 连接socket

        // 初始化连接
        ws.onopen = function() {
            console.log("连接成功"); 
            if(uid != null){
                ws.send(userid);  // 发送数据到后端
            }
           
        };

        // 返回信息
        ws.onmessage = function(evt){
            var res = evt.data;
           
            if(JSON.parse(res).code == 1001){
                layer.msg(JSON.parse(res).msg,{icon:6,time:2000},function(){
                    sessionStorage.removeItem('userid');  // 清楚浏览器userid
                    window.location.href = 'url'; // 退出接口
                });
            }
        }

登录成功后

ws.send(“用户id”);

 PHP代码块: 新建一个WorkerController.class.php 控制器

 0, 'msg' => '您的账号已在别处登录'];
    /**
     * 构造函数
     * @access public
     */
    public function __construct()
    {
        // 实例化 Websocket 服务
        $this->worker = new \Workerman\Worker('websocket://0.0.0.0:2346');

        $this->worker->count = 4;// 设置进程数
        $this->init();//初始化
        // 设置回调
        foreach (['onWorkerStart', 'onConnect', 'onMessage', 'onClose', 'onError', 'onBufferFull', 'onBufferDrain', 'onWorkerStop', 'onWorkerReload'] as $event) {
            if (method_exists($this, $event)) {
                $this->worker->$event = [$this, $event];
            }
        }
        // Run worker
        Worker::runAll();
    }
 
    /**
     * 收到信息
     * @param $connection
     * @param $data
     */
    public function onMessage($connection, $data)
    {
        $this->data = $data;
        //登录连接时分配一个全局唯一的uid
        $connection->uid = uniqid('xxx_');
        //追入redis中
        $this->redis->hSet('key',$connection->uid, $data);
        $expireTime = mktime(23, 59, 59, date("m"), date("d"), date("Y"));
        //设置键的过期时间
        $this ->redis->expireAt('hxt', $expireTime);
    }
 
    /**
     * 当连接建立时触发的回调函数
     * @param $connection
     */
    public function onConnect($connection)
    {
        // redis 不存在则实例化Redis对象, 并连接
        if($this->redis == ''){
            $this->redis = new Redis();
            $this->redis->connect('127.0.0.1',6379);
        }
    }
 
    /**
     * 当连接断开时触发的回调函数

     * @param $connection
     */
    public function onClose($connection)
    {
        if(isset($connection ->uid)){
            //找出userid 对应key
            $cid = $connection ->uid;
            //清除redis中对应id
             $this ->redis ->hDel('key',$cid);
             
        }
    }
 
    /**
     * 当客户端的连接上发生错误时触发
     * @param $connection
     * @param $code
     * @param $msg
     */
    public function onError($connection, $code, $msg)
    {
        echo "error $code $msg\n";
    }
 
    /**
     * 每个进程启动
     * @param $worker
     */
    public function onWorkerStart($worker)
    {
        //var_dump($worker->connections);
        Timer::add(1, function()use($worker){
            $time_now = time();
           
            if($this->redis == ''){
                $this->redis = new Redis();
                $this->redis->connect('127.0.0.1',6379);
            }

            //取出redis中所有连接客户端key
            $arr = $this->redis->hGetAll('key');
            //查询当前登录id是否在redis中
            $true = array_search($this->data,$arr);

            $sum=$this->get_array_repeats($tarr,$this->data);

            foreach($worker->connections as $connection) {
                if(isset($connection ->uid) && $connection->uid == $true && $sum>=2){
                    $connection->send(json_encode($this->msg)); // 发送给客户端
                    $connection->close();
                }
                

                $jicheng = $connection;
                // 有可能该connection还没收到过消息,则lastMessageTime设置为当前时间
             
                if (empty($jicheng->lastMessageTime)) {
                    $jicheng->lastMessageTime = $time_now;
                    continue;
                }
                // 上次通讯时间间隔大于心跳间隔,则认为客户端已经下线,关闭连接
                if ($time_now - $jicheng->lastMessageTime > HEARTBEAT_TIME) {
                // $connection->close();
                    echo "下线";
                }
            }
        });
    }

    //计算$string在$array(需为数组)中重复出现的次数
    public function get_array_repeats(array $array,$string)
    {
    
        $count = array_count_values($array);
        //统计中重复元素的次数,再重组数组, 
       
        if (key_exists($string,$count)) {
            return $count[$string];
        }else{
            return 0;
        }
    }
 
    public function init(){
 
    }
}

 

  1. 开启Redis服务  

        thinkPHP3.2 、thinkPHP5 结合workerman + Redis 实现账号单点登录_第1张图片

  1. 开启worker 服务

        thinkPHP3.2 、thinkPHP5 结合workerman + Redis 实现账号单点登录_第2张图片

      到这里就实现了 thinkPHP3.2 + Redis + workerman 就完成了账号单点登录

 

2. thinkPHP5 与 Redis + workerman 实现  

workerman 的安装:thinkPHP5可以直接用composer 安装workerman  扩展,具体方法请自行参考thinkPHP5官方文档

js与上面的相同,自行参考

 

PHP代码部分:

 

 

一、在项目跟目录新建一个server.php 文件 ,代码如下:

二、建立push模块并建立worker.php 文件, 代码如下:

最后同上:开启Redis , 在跟目录开启server服务

php server.php

 

你可能感兴趣的:(thinkPHP3.2,workerman,redis,单点登录,PHP技术博文,技术小例子)