您现在的位置是:首页 >技术交流 >【PHP+微信开发】之微信扫码登录网站首页技术交流
【PHP+微信开发】之微信扫码登录
目录
微信扫码登录总体说明:先获取token和ticket,通过微信生成二维码接口生成二维码,把二维码信息添加到数据表中,用户扫码时检测二维码扫描状态,扫描成功后更新二维码状态,跳转页面。
相关参考:微信开发之微信消息模板推送 + php
一、数据表
qrcord表,用户存储二维码信息,每生成一个二维码生成一条记录,通过openid字段判断是否扫描成功,如果openid不为空说明扫描成功,否则扫描失败或者是一条新的二维码,id字段就是下面使用的scene_id,此字段一直存在,作为操作二维码的关键字段。
id | addtime | openid | createtime | updatetime |
---|---|---|---|---|
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','非法请求');
}
}