乐趣区

关于php:通过小程序实现微信扫码登录个人网站接入微信扫码登录功能

需要

网站如果想要实现微信扫码登录其实有很多种计划,常见的计划就是微信开放平台和微信公众号服务号。前者是目前大部分网站并且是微信认可的一种形式,后者是开发者发现服务号具备扫码关注后即可获取用户根本信息的能力后而开发的一种形式。

而这两者其实都是须要具备资质,例如认证,对于集体开发者来说,是有肯定的门槛的,而我这次分享的是 0 门槛的,集体开发者一样能够实现。

原理

小程序也是具备获取用户根本信息的能力的,能够调用 wx.login 接口 获取用户的 openid 实现登录。简略来说就是 web 端创立一个带参数的二维码同时向数据库插入一条登录记录,此时 web 端曾经开始轮询数据库这条记录的扫码状态了,微信扫码后关上小程序并立刻获取到这个参数,而后点击受权登录按钮申请 wx.login 这个接口获取到 openid,而后将 openid 更新至数据库这个登录记录中并更新扫码状态,web 端能够轮询到登录胜利的状态码就展现登录胜利。

代码

creatqrcode.php

<!DOCTYPE html>
<html>
<head>
    <title> 小程序扫码登录示例 </title>
    <meta charset="utf-8">
    <script type="text/javascript" src="./jquery.min.js"></script>
    <link rel="stylesheet" type="text/css" href="./bootstrap.min.css">
    <style>
        *{
            padding:0;
            margin:0;
        }
        #xcxqrcode{
            width: 200px;
            height: 200px;
            margin:50px auto;
            display: block;
        }
        #lgtext{
            text-align: center;
            padding:20px 20px;
            background: #f1f1f1;
            border-radius: 100px;
        }
        #openid{
            text-align: center;
            padding:20px 20px;
        }
    </style>
</head>
<body>
<?php
// Header
header("Content-type:text/html;charset=utf-8");

// 获取 access_token
function getToken(){
    /**
     * 这里替换为你的小程序的 appid 和 appsecret
     */
    $appid='xxx';
    $appsecret='xxx';
    // 读取 access_token
    include 'access_token.php';
    // 判断是否过期
    if (time() > $access_token['expires']){
        // 如果曾经过期就得从新获取并缓存
        $access_token = array();
        $access_token['access_token'] = getNewToken($appid,$appsecret);
        $access_token['expires']=time()+7000;
        // 将数组写入 php 文件
        $arr = '<?php'.PHP_EOL.'$access_token ='.var_export($access_token,true).';'.PHP_EOL.'?>';
        $arrfile = fopen("./access_token.php","w");
        fwrite($arrfile,$arr);
        fclose($arrfile);
        // 返回以后的 access_token
        return $access_token['access_token'];

    }else{
        // 如果没有过期就间接读取缓存文件
        return $access_token['access_token'];
    }
}

// 获取新的 access_token
function getNewToken($appid,$appsecret){$url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={$appid}&secret={$appsecret}";
    $access_token_Arr =  https_request($url);
    return $access_token_Arr['access_token'];
}

// curl 申请函数
function https_request ($url){$ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    $out = curl_exec($ch);
    curl_close($ch);
    return  json_decode($out,true);
}

// 创立小程序码
function creatQrcode(){
    // 申请小程序接口创立小程序码
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, 'https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token='.getToken());
    curl_setopt($ch, CURLOPT_POST, true);
    $sc = uniqid(); // 生成 scene
    $data = array(
        "scene" => $sc,
        "env_version" => "develop" // 小程序审核通过后须要批改参数为 release
    );
    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    $result = curl_exec($ch);
    // 图片 buffer 转本地图片
    $img = file_put_contents($sc.'.png', $result);
    // 引入数据库配置
    include './Db.php';
    // 将二维码的 scene 写入数据库
    $add_scene = "INSERT INTO xcxqrcodelogin (scene) VALUES ('$sc')";
    if ($conn->query($add_scene) === TRUE) {
        $file = $sc.'.png';
        if($fp = fopen($file,"rb", 0)) 
        {$gambar = fread($fp,filesize($file)); 
            fclose($fp);
            $base64_qrcode = 'data:image/jpg/png/gif;base64,'.chunk_split(base64_encode($gambar)); 
            // 以 JSON 的形式返回小程序码及 scene
            return json_encode(array('xcxqrcode'=>$base64_qrcode,'scene'=>$sc));
        }
    }
    // 断开连接
    curl_close($ch);
    $conn->close();}

?>

<!-- 获取到小程序码的 base64 数据 -->
<?php 
    $qrcodebase64json = json_decode(creatQrcode());
    $xcxqrcode = $qrcodebase64json->xcxqrcode;
    $scene = $qrcodebase64json->scene;
    // 删除本地的图片
    unlink('./'.$scene.'.png');
?>
<!-- 展现二维码及扫码后果 -->
<div style="width:300px;margin:50px auto;">
    <img src="<?php echo $xcxqrcode; ?>" id="xcxqrcode">
    <input type="hidden" value="<?php echo $scene; ?>" id="sc"/>
    <h4 id="lgtext"> 请应用微信扫码 </h4>
    <p id="openid"></p>
</div>

<!-- 轮询扫码后果 -->
<script type="text/javascript">

// 从 0 秒开始轮询
let TimeOut = 0;
let checklogin = setInterval('CheckStatus()', 1000);

// 查问扫码状态
function CheckStatus() {
    // 获取 scene
    var sc = $('#sc').val();
    $.ajax({
        type: "POST",
        url: "./getstatus.php?scene="+sc,
        success:function(data){
            // code==200 即受权登录胜利
            if (data.code == 200) {console.log(data.msg)
                $('#lgtext').html('<span style="color:#07c160;">'+data.msg+'</span>')
                $('#openid').text(data.openid)
                $('#xcxqrcode').css('filter','blur(5px)')
                clearTimeout(checklogin);
            }else{console.log(data.msg)
                if(data.code == 201){$('#lgtext').html('<span style="color:#666;">'+data.msg+'</span>')
                }else if(data.code == 202){$('#lgtext').html('<span style="color:#07c160;">'+data.msg+'</span>')
                }
            }
            guoqi();},
        error:function(data) {console.log('服务器产生谬误')
          $('#lgtext').text('服务器产生谬误')
        }
    });
}

// 小程序码过期检测
function guoqi(){
    TimeOut += 1;
    // 60 秒后过期
    if(TimeOut >= 60){
        // 过期后进行轮询
        clearTimeout(checklogin);
        $('#lgtext').text('已过期,请刷新页面')
        $('#xcxqrcode').css('filter','blur(5px)')
    }
}

</script>
</body>
</html>

getstatus.php

<?php
header("Content-type:application/json");

// 小程序扫码后解析小程序码获取到的 scene
$scene = $_GET['scene'];

// 引入数据库配置
include './Db.php';

// 查问以后 scene 的扫码状态
$getstatusinfo = "SELECT * FROM xcxqrcodelogin WHERE scene='$scene'";
$result_statusinfo = $conn->query($getstatusinfo);

// 如果 scene 存在
if ($result_statusinfo->num_rows > 0) {while($row_statusinfo = $result_statusinfo->fetch_assoc()) {$status = $row_statusinfo['status'];
        $openid = $row_statusinfo['openid'];
    }
    // 当 scene= 1 的时候代表还没扫码
    if($status == '1'){
        $ret = array(
            'code' => 201,
            'msg' => '请应用微信扫码'
        );
    }else if($status == '2'){
        // 当 scene= 2 的时候代表已扫码未登录
        $ret = array(
            'code' => 202,
            'msg' => '已扫码,请受权登录'
        );
    }else if($status == '3'){
        // 当 scene= 3 的时候代表已登录
        $ret = array(
            'code' => 200,
            'msg' => '登录胜利',
            'openid' => $openid
        );
    }
}else{
    $ret = array(
        'code' => 203,
        'msg' => '请刷新重试'
    );
}

// 断开数据库连贯
$conn->close();

// 输入后果
echo json_encode($ret,JSON_UNESCAPED_UNICODE);

?>

scanCode.php

<?php
/**
 * 通知数据库我曾经扫码了
 */
header("Content-type:application/json");
$scene = $_GET['scene'];
// 引入数据库配置
include './Db.php';
mysqli_query($conn,"UPDATE xcxqrcodelogin SET status='2'WHERE scene='$scene'");
$conn->close();
?>

login.php

<?php
header("content-type:application/json");

// 通过 wx.login 获取到的 code
$code = $_GET["code"];
$scene = $_GET['scene'];

/**
 * 这里替换为你的小程序的 appid 和 appsecret
 */
$appid = "xxx";
$secret = "xxx";

// 申请接口进行登录获取到 openid
$api = "https://api.weixin.qq.com/sns/jscode2session?appid=$appid&secret=$secret&js_code=$code&grant_type=authorization_code";
$result = file_get_contents($api);
$arr_result = json_decode($result, true);
$openid = $arr_result["openid"];

// 引入数据库配置
include './Db.php';
// 更新登录状态
mysqli_query($conn,"UPDATE xcxqrcodelogin SET openid='$openid',status='3'WHERE scene='$scene'");
$ret = array(
    'code' => 200,
    'msg' => '登录胜利',
    'openid' => $openid
);
$conn->close();

// 返回后果
echo json_encode($ret,JSON_UNESCAPED_UNICODE);
?>

Db.php

<?php

/**
 * 数据库配置
 * BY TANKING 2022-08-06
 * https://segmentfault.com/u/tanking
 */
$db_url = "XXX"; // 数据库服务器地址
$db_user = "XXX"; // 数据库账号
$db_pwd = "XXX"; // 数据库账号
$db_name = "XXX"; // 数据库名称

// 连贯数据库
$conn = new mysqli($db_url, $db_user, $db_pwd, $db_name);
mysqli_query($conn, "SET NAMES UTF-8");

?>

代码阐明

1、creatqrcode.php是生成小程序码的界面,其中 41 行和 42 行的 $appid 和 $appsecret 要换成你的小程序的。以及 92 行的 env_version 在你的小程序上线后要改为 release,如果是开发调试中,就放弃现状。
2、login.php 是小程序端向后端申请接口获取 openid 的,其中 11 行和 12 行的 $appid 和 $appsecret 要换成你的小程序的。
3、scanCode.php是扫码后通知服务器你曾经实现扫码的后端。
4、getstatus.php是轮询扫码状态的后端。
5、Db.php是数据库配置文件,须要进去配置你的数据库地址、账号、明码、数据库名称。

数据库创立

将这条 SQL 粘贴至你的数据库治理端进行创立数据库表。

CREATE TABLE `xcxqrcodelogin` (`id` int(11) NOT NULL AUTO_INCREMENT,
  `scene` varchar(32) DEFAULT '',
  `openid` varchar(32) DEFAULT '',
  `status` varchar(2) DEFAULT '1' COMMENT '1 未扫码 2 已扫码 3 已登录',
  `creat_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=148 DEFAULT CHARSET=utf8mb4

Demo

小程序端代码

以上仅为前端和后端的代码,小程序端的代码请点击这里下载。
小程序端代码:https://likeyun.lanzout.com/i…

作者

TANKING
如需求教,可加 WeChat:sansure2016

退出移动版