[PHP+WeChat Development] WeChat scan code login

Table of contents

1. Data table

2. Obtain token

3. Generate QR code

4. Scan the code and receive the callback

5. Check whether the QR code is scanned successfully


General instructions for WeChat scan code login: first obtain the token and ticket, generate the QR code through the WeChat QR code generation interface, add the QR code information to the data table, and detect the QR code scanning status when the user scans the code. After the scan is successful, Update the QR code status and jump to the page.

Related reference: WeChat message template push + php for WeChat development

PHP WeChat development generates QR code and scans the code to follow the WeChat public account

 WeChat open document

1. Data table

qrcord table, the user stores QR code information. Each time a QR code is generated, a record is generated. The openid field is used to determine whether the scan is successful. If the openid is not empty, the scan is successful. Otherwise, the scan fails or it is a new QR code, id. The field is scene_id used below. This field always exists as a key field for operating QR codes.

id addtime openid createtime updatetime
ID QR code generation time WeChat ID creation time Update time

2. Obtain token

Logic description: Request the WeChat interface to obtain the token, store the obtained token on the server, and store the current time together to determine whether the token has expired (because the token has an expiration time). When calling this method, Compare the current time with the time stored in the token database (that is, the time when the token was obtained). If the current time > database storage time + 7000, the unit is seconds, it means that the original token has expired, and you need to obtain the token again and store the new one. into the database.

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

3. Generate QR code

Logic description: ① Before generating the QR code, first generate a piece of data and insert it into the qrcode table to record the QR code status. The data includes the QR code generation time. After the insertion, the self-increasing primary key ID is returned, and the returned ID is assigned to the variable. $scene_id, ② Start generating QR code: piece together parameters: QR code validity time, QR code type, QR code details, splice URL, request (two) WeChat interfaces to generate QR code.

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

Front-end code: Use labels to directly display QR codes. The hidden field is scene_id, which is used to query QR code information (including QR code scanning status).

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

4. Scan the code and receive the callback

Note: After generating the QR code, the user can scan the QR code. If it is scanned, the WeChat server will receive it and return the information, which is to return to the callback address previously filled in the WeChat official account. Note that this address is publicly accessible. Yes, there cannot be verification, otherwise the WeChat server cannot return the message to the callback address.

Callback method processing logic: receive the message returned by the WeChat server. The returned message format is xml by default. It needs to be converted into object format. The returned information includes EventKey, FormUserName, ToUserName, and Event. Modify the QRcode table information based on scene_id, mainly adding openid, indicating that the QR code has been successfully scanned by the user.

public function wxBack()
	{
		$postStr = file_get_contents('php://input'); // 获取请求体
     
	    //写入文件
	   // file_put_contents('./uploads/weixin.log', $postStr."\r\n", 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()]);
	}

5. Check whether the QR code is scanned successfully

Logic description: Use the function to query the QR code scanning status every 2 seconds, and query the openid in the qrcode table through scene_id on the backend. If the corresponding openid column is empty, it means that this is a new QR code. There is no user scanning. If the corresponding openid column is not empty, it means it has been scanned. If the scan is successful, the message will be pushed and the page will be redirected.

front-end code 

// 每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)
                    
                }
            }     
       })
}

backend code

    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','非法请求');
         }
     }

Guess you like

Origin blog.csdn.net/qq_25285531/article/details/130823460