您现在的位置是:首页 >技术交流 >【PHP+微信开发】之微信扫码登录网站首页技术交流

【PHP+微信开发】之微信扫码登录

下页、再停留 2024-06-19 13:56:27
简介【PHP+微信开发】之微信扫码登录

目录

一、数据表

二、获取token

三、生成二维码

四、扫码,并接收回调

五、检测二维码是否扫描成功


微信扫码登录总体说明:先获取token和ticket,通过微信生成二维码接口生成二维码,把二维码信息添加到数据表中,用户扫码时检测二维码扫描状态,扫描成功后更新二维码状态,跳转页面。

相关参考:微信开发之微信消息模板推送 + php

PHP 微信开发之生成二维码,并扫码关注微信公众号

 微信开放文档

一、数据表

qrcord表,用户存储二维码信息,每生成一个二维码生成一条记录,通过openid字段判断是否扫描成功,如果openid不为空说明扫描成功,否则扫描失败或者是一条新的二维码,id字段就是下面使用的scene_id,此字段一直存在,作为操作二维码的关键字段。

idaddtimeopenidcreatetimeupdatetime
ID二维码生成时间微信id创建时间更新时间

二、获取token

逻辑说明:请求微信接口获取token,把获取到token存储到服务器上,并把当前时间一并存储,用于判定token是否失效(因为token是有失效时间的),在调用此方法的时候,把当前时间和token数据库存储的时间(就是获取token的时间)对比,如果当前时间 > 数据库存储时间+7000,单位是秒,说明原来的token已经失效了,需要再重新获取token,并把新的存储到数据库中。

public function access_token()
{
  $time = time();
  $access_token = db::table('access_token')->find();
  $up_time = $access_token['update_time']+7000;
  if($time < $up_time){
    return $access_token;
  }else{
    $url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=".AppID."&secret=".AppSecret;
    // $access_token =  http_curl($url,'get');
    $access_token =  http_get_json($url);
    $save['update_time'] = time();
    $save['access_token'] = $access_token['access_token'];
    db::table('access_token')->where('id',1)->update($save);
    return $access_token;
  }
  
}

三、生成二维码

逻辑说明:① 在生成二维码前,首先生成一条数据插入qrcode表,用于记录二维码状态,数据包括二维码生成时间,插入后返回自增主键ID,把返回的ID赋给变量$scene_id,② 开始生成二维码:拼凑参数:二维码有效时间、二维码类型、二维码详细信息,拼接URL,请求(两个)微信接口生成二维码。

public function qrcode()
{
    //先删除openid为空的垃圾数据 
	Db::table('qrcode')->where(['openid'=>''])->delete();
    //插入数据 - 二维码记录
    $data_insert = [
        'addtime'=>  time(),
    ];
        
    // 插入新记录,并返回记录id
    $scene_id = Db::table('qrcode')->insertGetId($data_insert); 
        
    if(!$scene_id){
      	return false;
    }
    $token = $this->access_token();
    $access_token = $token['access_token'];
    $url = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=$access_token";
    // 参数
    $param = array();
    $param['expire_seconds'] = 3600 * 24; //有效时间 
    $param['action_name'] = 'QR_SCENE'; //二维码类型 
    $param['action_info']['scene']['scene_id'] = $scene_id;  //二维码详细信息
    $param = json_encode($param,true);

    // 返回二维码的ticket和二维码图片解析地址
    $ticket_arr = $this->http_curl($url, 'post', 'json', $param);
    //拿ticket换取二维码
    if (empty($ticket_arr['errcode'])) { 
        $ticket = $ticket_arr['ticket'];
       // 通过ticket换取二维码
       $qrcode = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=".$ticket_arr['ticket'];

        $api = array();
        $api['qrcode'] = $qrcode;
        $api['scene_id'] = $scene_id;
        return $api;
            
    }else { 
      
       //echo '发生错误:错误代码 ' . $ticket_arr['errcode'] . ',微信返回错误信息:' . $ticket_arr['errmsg']; 
       //   return   apiResponse(110,$ticket_arr['errcode'],$ticket_arr['errmsg']);
       return '110';
    }
}

前端代码:用标签直接显示二维码,隐藏域为scene_id,用于查询二维码信息(包括二维码扫描状态)。

<img src="{$qrcode.qrcode}"  style="width: 250px;box-shadow:0 0 10px #F1F3F4">
<input type="hidden" name="scene_id" id="" value="{$qrcode.scene_id}" />

四、扫码,并接收回调

说明:生成二维码后,用户可以扫描二维码,如果扫描之后,微信服务器会收到,并返回信息,就是返回到事先填写在微信公众号上的回调地址,注意这个地址是可以公开访问的,不能有验证,否则微信服务器无法返回消息给回调地址。

回调方法处理逻辑:接收微信服务器返回的消息,返回的消息格式默认是xml,需要把它转换成对象格式,返回的信息包括EventKey,FormUserName,ToUserName,Event。根据scene_id修改qrcode表信息,主要是添加openid,表示该二维码已被用户扫码成功。

public function wxBack()
	{
		$postStr = file_get_contents('php://input'); // 获取请求体
     
	    //写入文件
	   // file_put_contents('./uploads/weixin.log', $postStr."
", FILE_APPEND); // 将信息追加到文件末尾
	    $postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
	    
	    $scene_id = $postObj->EventKey;

        $openid = $postObj->FromUserName;   //openid
          
        $ToUserName = $postObj->ToUserName;  //公众号
        
        $Event = strtolower($postObj->Event);   //事件类型
        
        //添加扫码记录
        $res = Db::table('qrcode')->where('id',$scene_id)->update(['openid'=>$openid,'createtime'=>time()]);
	}

五、检测二维码是否扫描成功

逻辑说明:使用函数每隔2秒执行一次查询一次二维码扫描状态,在后端通过scene_id查询qrcode表里的openid,如果对应的openid列为空,说明这是一个新的二维码,还没有用户扫描,如果对应的openid列不为空说明已经被扫描,扫码成功,那就推送消息并跳转页面。

前端代码 

// 每2秒查询一次数据表用户是否已经扫码
$(document).ready(function(){
   	c = setInterval(check_login,2000);   //每2秒执行一次
});

//检测用户是否已扫描
function check_login() { 
	    
        var scene_id=$("input[name='scene_id']").val();

        $.ajax({
            url:'check_login2',   //请求地址
            data:{scene_id:scene_id},   //发送的数据
            type:'POST',     //请求的方式
            dataType:'JSON',
            success:function(res){
                // console.log(res)
                if(res.code == '200'){  //已完成推送
                    layer.msg(res.message, {
                      icon: 1,
                      time: 2000 //2秒关闭(如果不配置,默认是3秒)
                    }, function(){
                      window.location.href='/teacher/index/index';
                    });
                    window.clearInterval(c); //终止
                }else if(res.code == '110'){
                    layer.msg(res.message, {
                      icon: 2,
                      time: 2000 //2秒关闭(如果不配置,默认是3秒)
                    })
                    
                    window.clearInterval(c); //终止
                    
                    setTimeout(function(){
                        window.location.reload();//刷新当前页面. 100s
                    },3000)
                    
                }
            }     
       })
}

后端代码

    public function check_login2(){
         if (request()->isPost()) {
             
             $scene_id = input('post.scene_id');
             // 获取二维码信息
	        $res = model('Login')->getQrcodeInfo($scene_id);
	        if (!empty($res['openid'])) {
	                
    				    //推送登录成功消息
    	               	$token = access_token();
    		            $access_token = $token['access_token'];
    		          //  微信推送
    	                $url="https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=".$access_token;
    	                
    	                $post_data = array(
    
                            "touser"=>$user['openid'], //推送给谁,openid
                
                            "template_id"=>"xxxxxx", //微信后台的模板信息id      
                
                            "data"=> array(
                                "first" => array(
                                    "value"=>"账号登录成功 - 首医中医药研学平台",
                                    "color"=>"#888"
                                ),
                                "keyword1"=>array(
                                    "value"=>$user['name'], //传的变量
                                    "color"=>"#888"
                                ),
                                 "keyword2"=>array(
                                    "value"=> date("Y.m.d H:i:s",time()),
                                    "color"=>"#888"
                                ), 
                                "keyword3"=>array(
                                    "value"=>'教师', //传的变量
                                    "color"=>"#888"
                                ),
                                "remark"=>array(
                                    "value"=> '您已成功登录!',
                                    "color"=>"#888"
                                ),  
                            )
                
                        );
                        //将上面的数组数据转为json格式
                        $post_data = json_encode($post_data);
                        
                        //发送数据,post方式
                        //配置curl请求
                        $ch = curl_init();
                        curl_setopt($ch,CURLOPT_URL,$url);
                        curl_setopt($ch, CURLOPT_RETURNTRANSFER,1); //设置有返回值,0,直接显示
                        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER,0); //禁用证书验证
                        curl_setopt($ch,CURLOPT_POST,1);
                        curl_setopt($ch,CURLOPT_POSTFIELDS,$post_data);
                    
                        //接收执行返回的数据
                        $res = curl_exec($ch);
                    
                        //关闭句柄
                        curl_close($ch);
                       
                        // return apiResponse('200','登录成功');
    					return apiResponse('200','登陆成功,正在跳转...');
    				}
	           
	            
	        }else{
	            return apiResponse('100','操作失败,请刷新页面重试!');
	        }
	        
         }else{
             return apiResponse('110','非法请求');
         }
     }

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。