微信公众号扫码登陆实现逻辑

143次阅读
没有评论

微信相关接口封装,示例代码所用框架 ThinkPHP6 配置公众号

使用微信公众号实现微信扫码登陆的逻辑 1. 微信端实现扫码事件操作通过微信发送给开发者服务器 2. 开发者服务器接收并处理二维码中的参数,并存储到服务器中 3. 开发者浏览器端轮询确认用户是否登陆成功

Wx.php

<?php
namespace app\index\logic;

use app\index\model\TabUser;
use think\Exception;
use think\facade\Log;
use Endroid\QrCode\QrCode;
use Endroid\QrCode\Writer\PngWriter;
use Endroid\QrCode\Encoding\Encoding;
use Endroid\QrCode\ErrorCorrectionLevel\ErrorCorrectionLevelLow;

class Wx
{
    // 存储当前对象
    private static $instance  = null;

    // 禁止被实例化
    private function __construct()
    { }

    // 禁止 clone
    private function __clone()
    { }

    // 实例化自己并保存到 $instance 中,已实例化则直接调用
    public static function getInstance()
    {if(empty(self::$instance)){self::$instance = new self();
        }
        return self::$instance;
    }

    public $appid='wxcdde******b20';
    public $appsecret='2da42c6f*****1e2ad061d57f7712';
    public $token = 'n4xmyq3z0*****rrhjwe11ow0u15uu1';
    public $EncodingAESKey = 'cbyrq3Cz4N1mdWqQ7bOvYLP58zKSNUytX8yc4TjWiOU';

    private function auth(){
        $token=$this->token;
        $signature = $_GET["signature"];
        $timestamp = $_GET["timestamp"];
        $nonce = $_GET["nonce"];
        $tmpArr = array($token, $timestamp, $nonce);
        sort($tmpArr, SORT_STRING);
        $tmpStr = implode($tmpArr);
        $tmpStr = sha1($tmpStr);
        if(trim($tmpStr) == trim($signature)){if(isset($_GET['echostr'])){echo $_GET['echostr'];
                exit;
            }else{return false;}
        }else{return false;}
    }

    //token
    public function token(){$this->auth();
        $postData = file_get_contents('php://input');
        libxml_disable_entity_loader(true);
        $data = $this->xmlToArray($postData);
        Log::info($data);
        if($data['MsgType']=='event'){ // 事件处理
            if($data['Event']=='unsubscribe'){// 取消关注的事件
                $this->unsubscribe($data);
            }else if($data['Event']=='subscribe'){// 关注的事件
                $this->subscribe($data);
            }else if($data['Event']=='SCAN'){// 扫描带参二维码事件
                $this->scan($data);
            }
        }
    }

    //xml 转数组
    private function xmlToArray($xml)
    {if (file_exists($xml)) {libxml_disable_entity_loader(false);
            $xml_string = simplexml_load_file($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
        } else {libxml_disable_entity_loader(true);
            $xml_string = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
        }
        $result = json_decode(json_encode($xml_string), true);
        return $result;
    }

    /**
     * 获取 access_token,用于获取用户信息
     * @param $code     用户扫码登录成功后,回调带的 code
     * @return mixed
     */
    private function get_access_token(){
        $cache_key = 'wx_access_token_'.$this->appid;

        if(!cache($cache_key)){
            $url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=".$this->appid."&secret=".$this->appsecret;
            $data = json_decode(curl_request($url),true);
            if(isset($data['access_token'])){cache($cache_key, $data['access_token'],$data['expires_in']-600);
            }else{Log::error($url. ' 请求失败 ');
                throw new Exception(' 微信接口请求失败 ');
            }
        }

        return cache($cache_key);
    }

    /**
     * 获取用户信息
     * @param $access_token  string access_token
     * @param $openid string  微信用户标识
     * @return mixed
     */
    private  function get_user_info($access_token, $openid){
        $url = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=".$access_token."&openid=".$openid."&lang=zh_CN";
        return json_decode(curl_request($url),true);
    }

    /**
     * 写入用户信息到数据表
     * @param $openid
     * @param $EventKey
     */
    private function register($openid, $EventKey)
    {$model = new TabUser();
        $data['account'] = Login::create_account();
        $data['nickname'] = $data['account'];
        $data['password'] = $data['account'];
        $data['openid'] = $openid;
        $result = $model->insert($data);

        cache('login_'.$EventKey,json_encode($result),'50');
    }

    /**
     * 扫描带参二维码事件
     */
    private  function scan($data)
    {$access_token= $this->get_access_token();

        $user_['access_token']=$access_token;
        $user_['openid']= $data['FromUserName'];

        $EventKey = $data['EventKey'];
        if(isset($user_['openid'])){
            // 说明获取用户信息获取成功了
            $info = cache('login_'.$EventKey);
            if(empty($info)){$users = TabUser::where(['openid'=>$user_['openid']])->find();
                if($users){cache('login_'.$EventKey,json_encode($users),'50');
                }else{
                    // 注册
                    $this->register($data['FromUserName'], $EventKey);
                }
                $msg = ' 登陆成功!';
                $textTpl = "<xml><ToUserName><![CDATA[%s]]></ToUserName><FromUserName><![CDATA[%s]]></FromUserName><CreateTime>%s</CreateTime><MsgType><![CDATA[%s]]></MsgType><Content><![CDATA[%s]]></Content></xml>";
                $resultStrq = sprintf($textTpl,$data['FromUserName'],$data['ToUserName'], time(), 'text', $msg);
                echo $resultStrq;
                exit;
            }
        }

    }
    /**
     * 关注订阅
     */
    private  function subscribe($data)
    {$EventKey = explode("_", $data['EventKey'])[1];

        $access_token= $this->get_access_token();

        $user_['access_token']=$access_token;
        $user_['openid']=$data['FromUserName'];
        if(isset($user_['openid'])){
            // 说明获取用户信息获取成功了
            $info=cache('login_'.$EventKey);
            if(empty($info)){$users = TabUser::where(['openid'=>$user_['openid']])->find();
                if($users){//Db::table("tab_wx_log")->insert(array('session_str'=>444,'content'=>444));
                    cache('login_'.$EventKey,json_encode($users),'50');
                }else{
                    // 注册
                    $this->register($data['FromUserName'], $EventKey);
                    //Db::table("tab_wx_log")->where(['session_str'=>666])->update(array('content'=>$data['FromUserName']));
                }

                $msg = ' 登陆成功!';
                $textTpl = "<xml><ToUserName><![CDATA[%s]]></ToUserName><FromUserName><![CDATA[%s]]></FromUserName><CreateTime>%s</CreateTime><MsgType><![CDATA[%s]]></MsgType><Content><![CDATA[%s]]></Content></xml>";
                $resultStrq = sprintf($textTpl,$data['FromUserName'],$data['ToUserName'], time(), 'text', $msg);
                echo $resultStrq;
                exit;
            }
        }
    }

    /**
     * 取消订阅
     */
    private  function unsubscribe($data)
    {echo ' 取消关注 ';exit;}

    /**
     * 获取微信场景二维码
     * @param $sceneValue 场景值
     * @param int $type 1:临时二维码  2:永久二维码
     * @return string
     */
    public  function getWeChatUrl($session_str,$code){cache('login_'.$session_str,true,50); // 用户客户端标识
        cache('code_'.$session_str,$code,50); // 邀请码

        $type=1;
        $access_token = $this->get_access_token();

        $url = 'https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token='.$access_token;

        $actionName = 'QR_STR_SCENE';
        if($type==2){$actionName = 'QR_STR_SCEN';}

        $data = json_encode([
            'expire_seconds'=>604800,
            'action_name'=>$actionName,
            'action_info'=>[
                'scene'=>[
                    'scene_id'=>$session_str,
                    'scene_str'=>$session_str
                ]
            ]
        ]);
        $res = curl_request($url, true ,$data);
        $res = json_decode($res,true);

        if(isset($res['errcode']) && $res['errcode']){throw new Exception(' 二维码接口请求失败 ');
        }
        return $res['url'];
    }

    /**
     * 功能:生成二维码 base64 图片
     * @param string $qrData 手机扫描后要跳转的网址
     * @param string $qrLevel 默认纠错比例 分为 L、M、Q、H 四个等级,H 代表最高纠错能力
     * @param string $qrSize 二维码图大小,1-10 可选,数字越大图片尺寸越大
     * @param string $savePath 图片存储路径
     * @param string $savePrefix 图片名称前缀
     * @return mixed
     */
    public function createQRcode($qrData = '', $qrSize = 200)
    {$writer = new PngWriter();
        $qrCode = new QrCode($qrData);
        $qrCode->setEncoding(new Encoding('UTF-8'));
        $qrCode->setErrorCorrectionLevel(new ErrorCorrectionLevelLow());
        $qrCode->setSize($qrSize);
        $qrCode->setMargin(10);

        $result = $writer->write($qrCode);
        return $result->getDataUri();}

    /**
     * 生成唯一客户端 id 标识
     * @return string
     */
    public function create_session_str()
    {
        $str = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
        $len = strlen($str)-1;
        $randstr = '';
        for ($i=0;$i<6;$i++) {$num=mt_rand(0,$len);
            $randstr .= $str[$num];
        }
        $session_str = $randstr.uniqid();
        return $session_str;
    }
}

控制器



class login
{
    /**
     *  微信 token 验证
     *  微信服务端与开发者客户端交互接口
     */
    public function token()
    {Wx::getInstance()->token();}

    /** * 携带客户端表示,显示二维码 */
    public function qrcode($session_str, $code='') {$url = Wx::getInstance()->getWeChatUrl($session_str,$code);
        $base64_img = Wx::getInstance()->createQRcode($url);
        echo $base64_img;
    }
    /** * 轮询请求是否扫码登陆成功 */
    public function check_login($session_str, $code='') {if(cache('login_'.$session_str)){return ture;} else{return false;}
    }

    /** * 生成 session_str 客户端唯一标识 * 在生成微信登陆二维码时携带 session_str 参数 */
    public function index($session_str, $code='') {$session_str = Wx::getInstance()->create_session_str();
        echo $session_str;
    }

}
···
正文完
有偿技术支持加微信
post-qrcode
 
评论(没有评论)
验证码