目次
WeChat スキャン コード ログインの一般的な手順: 最初にトークンとチケットを取得し、WeChat QR コード生成インターフェイスを通じて QR コードを生成し、QR コード情報をデータ テーブルに追加し、ユーザーがコードをスキャンしたときに QR コード スキャン ステータスを検出します。スキャンが成功したら、QR コードのステータスを更新し、ページにジャンプします。
関連資料: WeChat 開発用の WeChat メッセージ テンプレート プッシュ + php
PHP WeChat 開発では QR コードを生成し、そのコードをスキャンして WeChat 公開アカウントをフォローします
1. データテーブル
qrcord テーブルには、ユーザーが QR コード情報を保存します。QR コードが生成されるたびに、レコードが生成されます。openid フィールドは、スキャンが成功したかどうかを判断するために使用されます。openid が空でない場合、スキャンは成功します。それ以外の場合、スキャンが失敗したか、新しい QR コード ID です。フィールドは以下で使用する scene_id です。このフィールドは、QR コードを操作するためのキー フィールドとして常に存在します。
ID | 追加時間 | オープンID | 作成時間 | 更新時間 |
---|---|---|---|---|
ID | QRコード生成時間 | WeChat ID | 作成時間 | 更新時間 |
2. トークンの取得
ロジックの説明: WeChat インターフェイスにトークンの取得を要求し、取得したトークンをサーバーに保存し、現在時刻を合わせて保存して、トークンの有効期限が切れているかどうかを判断します (トークンには有効期限があるため)。このメソッドを呼び出すときは、現在時刻とトークン データベースに保存されている時刻 (つまり、トークンが取得された時刻) を比較します。現在時刻 > データベース保存時間 + 7000 (秒単位) の場合、元のトークンの有効期限が切れていることを意味します。トークンを再度取得し、新しいトークンをデータベースに保存します。
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. QRコードを生成する
ロジック説明: ① QR コードを生成する前に、まずデータを生成し、それを qrcode テーブルに挿入して、QR コードのステータスを記録します. データには、QR コードの生成時間が含まれます. 挿入後、自己増加する主キー ID $scene_id, ② QR コードの生成開始: 結合パラメータ: QR コードの有効期間、QR コードの種類、QR コードの詳細、結合 URL、生成する WeChat インターフェイスのリクエスト (2 つ) QRコード。
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';
}
}
フロントエンド コード: ラベルを使用して QR コードを直接表示します。隠しフィールドは scene_id で、QR コード情報 (QR コードのスキャン ステータスを含む) をクエリするために使用されます。
<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. コードをスキャンしてコールバックを受信します。
注: QR コードを生成した後、ユーザーは QR コードをスキャンできます。スキャンされると、WeChat サーバーはそれを受信し、情報を返します。これは、WeChat 公式アカウントに事前に入力されたコールバック アドレスに返されます。このアドレスはパブリックにアクセスできます。はい、検証できません。そうでないと、WeChat サーバーはコールバック アドレスにメッセージを返すことができません。
コールバック メソッド処理ロジック: WeChat サーバーから返されたメッセージを受信します。返されるメッセージの形式は、デフォルトでは xml です。オブジェクト形式に変換する必要があります。返される情報には、EventKey、FormUserName、ToUserName、および Event が含まれます。scene_id に基づいて QR コード テーブル情報を変更します。主に、QR コードがユーザーによって正常にスキャンされたことを示す openid を追加します。
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. QRコードが正常に読み取られたか確認します
ロジックの説明: 関数を使用して 2 秒ごとに QR コードのスキャン ステータスをクエリし、バックエンドの scene_id を介して qrcode テーブルの openid をクエリします。対応する openid 列が空の場合、これは新しい QR コードであることを意味します。ユーザー スキャンがありません。対応する 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','非法请求');
}
}