正式开始
领导打算使用公众号登录,让网站的流量导入公众号中,方便进行转化。于是我就在帝国cms的基础上开始进行设置
首先
先得有一个微信开放平台的账号,微信公众平台的根本不行,账号也不能通用,需要另外一个邮箱账号。(完善开发者信息是真的麻烦)
然后就是创建一个网站应用,需要logo,一张表(带公章的)
最后就是等待审核通过了。
(你以为完事了?还有认证呢)
开始设置开发者认证
首先,开发者认证需要300块。
然后需要申请公函(就是让你填一个表,带公章的那种,前面的名字别写网站应用的名字,需要写上公司全称),企业资质信息(就是营业执照),对公账户信息(就是公司对外账户),认证联系人信息(可以理解为你的信息)
后面还有
税务信息(就是营业执照)
纳税识别号
我猜这俩应该是那300块的发票
然后就准备付钱吧
这些都完成了你还是等待审核。
2020年9月16日改
前置完成
终于完成了一个小目标,自己生成二维码扫描公众号,但还没写完登录原因是我不会
目前帝国cms微信插件公开的是这种.
根本没有二维码 设置完后就是一个认证一样 也不会进公众号,更谈不到获取信息
还有一种是使用
http://res.wx.qq.com/connect/zh_CN/htmledition/js/wxLogin.js
var obj = new WxLogin({
self_redirect:true,
id:"login_container",
appid: "",
scope: "",
redirect_uri: "",
state: "",
style: "",
href: ""
});
这种更坑爹,没法使用公众号APPID,只能使用网站应用的APPID,出现的二维码是网站应用的信息,和公众号不沾边,因为公众号只能snsapi_base或者snsapi_userinfo,而网站应用是snsapi_login
正题
在网上寻找了半天,最后决定使用phpthink5+csdn里面下载的一位老哥的文件包
controller类
Base.php
<?php
namespace app\index\controller;
use think\Controller;
use think\Db;
use think\exception\HttpResponseException;
/**
* 前台接口公用基础控制器
* Class ApiBase
* @package app\common\controller
*/
class Base extends Controller
{
/**
* 默认响应输出类型,支持json/xml
* @var string
*/
protected $responseType = 'json';
/**
* 接口返回的数据
* @author Mr.tang
* @since 2020-01-13
* @param string $msg 提示信息
* @param mixed $data 要返回的数据
* @param int $code 返回码,默认为1
* @param string $type 输出类型
* @param array $header 发送的 Header 信息
*/
public function returnApi($msg = '', $code = 1, $data = null,$type = null, array $header = []){
$result = [
'code' => $code,
'msg' => $msg,
'time' => request()->server('REQUEST_TIME')
];
if(!empty($data)){
$result['data']=$data;
}
// 如果未设置类型则自动判断
$type = $type ? $type : ($this->request->param(config('var_jsonp_handler')) ? 'jsonp' : $this->responseType);
if (isset($header['statuscode'])) {
$code = $header['statuscode'];
unset($header['statuscode']);
} else {
//未设置状态码,根据code值判断
$code = $code >= 1000 || $code < 200 ? 200 : $code;
}
$response = response()->create($result,$type, $code)->header($header);
throw new HttpResponseException($response);
}
}
老哥原先的控制器名字是Wx,但我不会改tp5的控制,所以改名为index
Index.php
<?php
namespace app\index\controller;
use think\Db;
use think\facade\Env;
use app\index\controller\WechatCallBackApi;
use app\index\controller\Base;
class Index extends Base{
//微信开发
public function index(){
//获取token
$access_token=$this->get_access_token();
if(!$access_token){
die('获取token失败');
}
//数据库中添加二维码信息
$scene_id=Db::name('qrcode')->insertGetId(['create_time'=>time()]);
// 创建二维码ticket
// 每次创建二维码ticket需要提供一个开发者自行设定的参数(scene_id),分别介绍临时二维码和永久二维码的创建二维码ticket过程。
// 临时二维码请求说明
$url="https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=".$access_token;
$data=array(
'expire_seconds'=>60*5,
'action_name'=>"QR_SCENE",
'action_info'=>array('scene'=>array('scene_id'=>$scene_id)),
);
$result=$this->doPost($url,json_encode($data));
$result=json_decode($result,true);
$ticket=isset($result['ticket'])?$result['ticket']:"";
$expire_seconds=isset($result['expire_seconds'])?$result['expire_seconds']:"";
$url=isset($result['url'])?$result['url']:"";
if($ticket&&$expire_seconds&&$url){
Db::name('qrcode')->where('id',$scene_id)->update(['ticket'=>$ticket,'expire_seconds'=>$expire_seconds,'url'=>$url]);
$qrcode_url="https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=".$ticket;
$this->assign('qrcode_url',$qrcode_url);
}else{
die('获取临时二维码失败');
}
$this->assign('scene_id',$scene_id);
return $this->fetch();
}
//检查是否登录
public function ajax_check_login(){
$scene_id=input('post.scene_id');
$res=Db::name('qrcode')->where('id',$scene_id)->field('openid,nickname,logintime')->find();
if(!empty($res)){
if($res['logintime']>0){
$this->returnApi('登录成功',200,$res);
}else{
$this->returnApi('未登录',0);
}
}else{
$this->returnApi('未登录',0);
}
}
//微信通知
public function wx_notice(){
$wechatObj = new WechatCallBackApi();
$wechatObj->valid();//填写的URL需要正确响应微信发送的Token验证
}
//获取用户基本信息(UnionID机制)
public function getUserInfo($openid=''){
if(!$openid){
return false;
}
$access_token=$this->get_access_token();
if(!$access_token){
return false;
}
$url="https://api.weixin.qq.com/cgi-bin/user/info?access_token=".$access_token."&openid=".$openid."&lang=zh_CN";
$data=$this->doGet($url);
$data=json_decode($data,true);
$errcode=isset($data['errcode'])?$data['errcode']:"";
if($errcode){
return false;
}
$result=array(
'openid'=>isset($data['openid'])?$data['openid']:"",
'nickname'=>isset($data['nickname'])?$data['nickname']:"",
'sex'=>isset($data['sex'])?$data['sex']:"",
'country'=>isset($data['country'])?$data['country']:"",
'province'=>isset($data['province'])?$data['province']:"",
'city'=>isset($data['city'])?$data['city']:"",
'headimgurl'=>isset($data['headimgurl'])?$data['headimgurl']:""
);
return $result;
}
// 获取access_token
public function get_access_token(){
$res=Db::name('token')->where('appid',config('system.appid'))->field('id,access_token,expires_in,create_time')->find();
if(!empty($res)){
$time=$res['create_time']+$res['expires_in']-300;//提前5分钟更新token
if($time<=time()){
$url="https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=".config('system.appid')."&secret=".config('system.appsecret');
$data=$this->doGet($url);
$data=json_decode($data,true);
$access_token=isset($data['access_token'])?$data['access_token']:"";
$expires_in=isset($data['expires_in'])?$data['expires_in']:"";
if($access_token&&$expires_in){
Db::name('token')->where('id',$res['id'])->update(['access_token'=>$access_token,'expires_in'=>$expires_in,'create_time'=>time()]);
return $access_token;
}else{
return false;
}
}else{
return $res['access_token'];
}
}else{
$url="https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=".config('system.appid')."&secret=".config('system.appsecret');
$data=$this->doGet($url);
$data=json_decode($data,true);
$access_token=isset($data['access_token'])?$data['access_token']:"";
$expires_in=isset($data['expires_in'])?$data['expires_in']:"";
if($access_token&&$expires_in){
Db::name('token')->insert(['appid'=>config('system.appid'),'access_token'=>$access_token,'expires_in'=>$expires_in,'create_time'=>time()]);
return $access_token;
}else{
return false;
}
}
}
/**
* @param string $url
* @return mixed
*/
public function doGet($url){
//初始化
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,$url);
// 执行后不直接打印出来
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, false);
// 跳过证书检查
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
// 不从证书中检查SSL加密算法是否存在
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
//执行并获取HTML文档内容
$output = curl_exec($ch);
//释放curl句柄
curl_close($ch);
return $output;
}
public function doPost($url,$data){
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
// post数据
curl_setopt($ch, CURLOPT_POST, 1);
// post的变量
curl_setopt($ch, CURLOPT_POSTFIELDS,$data);
curl_setopt($ch, CURLOPT_HEADER, 0);
//执行请求
$output = curl_exec($ch);
//打印获得的数据
return $output;
curl_close($ch);
}
//新的日志写入 使用方式:$this->put_log_create(json_encode($array,JSON_UNESCAPED_UNICODE),'37/123','log.log');
public function put_log_create($data,$path,$fileName){
date_default_timezone_set('Asia/Shanghai'); //设置中国时区
//判断文件是否存在
if($path){
$filename=Env::get('ROOT_PATH').'log/'.$path.'/';
}else{
$filename=Env::get('ROOT_PATH').'log/';
}
if(!is_dir($filename)) {
mkdir($filename, 0777,true);
}
//判断文件是否存在
$dir=$filename.'/'.$fileName;
return file_put_contents($dir, PHP_EOL."时间:".date('Y-m-d H:i:s').PHP_EOL.$data.PHP_EOL, FILE_APPEND);
}
}
WechatCallBackApi.php
<?php
namespace app\index\controller;
use think\Controller;
use think\Db;
use app\index\controller\Index;
class WechatCallBackApi extends Controller{
//填写的URL需要正确响应微信发送的Token验证
public function valid(){
ob_clean();
$echoStr =isset($_GET["echostr"])?$_GET["echostr"]:'';
if($this->checkSignature($echoStr)){
echo $echoStr;
exit;
}
}
//消息处理
public function responseMsg() {
//get post data, May be due to the different environments
$postStr = !empty($GLOBALS ["HTTP_RAW_POST_DATA"])?$GLOBALS ["HTTP_RAW_POST_DATA"]:file_get_contents("php://input");
$wx = new Index();
//$wx->put_log_create($postStr,'','wx_notice.log');
//extract post data
if (! empty ( $postStr )) {
$postObj = simplexml_load_string ( $postStr);
//微信openid
$openid=$postObj->FromUserName;
//转换角色
$toUserName=$postObj->ToUserName;
//scene_id qrscene_
$scene_id=str_replace("qrscene_",'',$postObj->EventKey);
//Event
$event=strtolower($postObj->Event);
if($event=='subscribe'){//首次关注
$is_first=0;
$content='欢迎注册,已登录!';
}elseif($event=='scan'){
$is_first=1;//已关注
$content='登录成功!';
}
$userInfo=$wx->getUserInfo($openid);
$openid=isset($userInfo['openid'])?$userInfo['openid']:"";
$nickname=isset($userInfo['nickname'])?$userInfo['nickname']:"";
$sex=isset($userInfo['sex'])?$userInfo['sex']:"";
$country=isset($userInfo['country'])?$userInfo['country']:"";
$province=isset($userInfo['province'])?$userInfo['province']:"";
$city=isset($userInfo['city'])?$userInfo['city']:"";
$headimgurl=isset($userInfo['headimgurl'])?$userInfo['headimgurl']:"";
Db::name('qrcode')->where('id',$scene_id)->update(['openid'=>$openid,'logintime'=>time(),'is_first'=>$is_first,'nickname'=>$nickname,'headimgurl'=>$headimgurl,'sex'=>$sex,'province'=>$province,'city'=>$city,'country'=>$country]);
//回复消息
$this->handleText($postObj,$content);
} else {
echo "";
exit ();
}
}
/**
* 处理text类型的消息
* Enter description here ...
*/
public function handleText($postObj,$content)
{
$xmlTpl = "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[%s]]></MsgType>
<Content><![CDATA[%s]]></Content>
</xml>";
$fromUsername = $postObj->FromUserName;
$toUsername = $postObj->ToUserName;
$time = time();
$msgType = 'text';
$resultStr = sprintf($xmlTpl, $fromUsername, $toUsername, $time, $msgType, $content);
echo $resultStr;
}
private function checkSignature($echoStr)
{
// you must define TOKEN by yourself
if (!config('system.token')) {
throw new Exception('TOKEN is not defined!');
}
$signature = $_GET["signature"];
$timestamp = $_GET["timestamp"];
$nonce = $_GET["nonce"];
$token = config('system.token');
$tmpArr = array($token, $timestamp, $nonce);
// use SORT_STRING rule
sort($tmpArr, SORT_STRING);
$tmpStr = implode( $tmpArr );
$tmpStr = sha1( $tmpStr );
if( $tmpStr == $signature && $echoStr){
return true;
}else{
$this->responseMsg();
}
}
}
view
application/index/view/index/index.html
<html>
<head>
<meta charset="utf-8">
<!-- <meta name="keywords" content=""> -->
<meta name="description" content="">
<meta name="HandheldFriendly" content="True">
<meta name="MobileOptimized" content="320">
<meta name="format-detection" content="telephone=no">
<meta http-equiv="cleartype" content="on">
<meta name="referrer" content="always">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>PHP微信扫码关注公众号并授权登录</title>
</head>
<body>
<div style="text-align: center;padding-top: 50px;">
<div style="color: red;padding-bottom: 30px;">请使用微信扫一扫</div>
<img src="{$qrcode_url}" style="width: 300px;height: 300px;border-style:dashed;">
</div>
</body>
<script src="__CDN__/assets/js/jquery.min.js"></script>
<script type="text/javascript" src="__CDN__/assets/layer/layer.js"></script>
<script type="text/javascript">
$(document).ready(function(){
clock = setInterval(function(){
check_login("{$scene_id}");
}, 1000);
$('#down').click(function(){
clearInterval(clock);
})
});
function check_login(scene_id){
$.ajax({
url:"__CDN__/index/index/ajax_check_login",
type:'post',
data:{"scene_id":scene_id},
cache:false,
success:function(data){
console.log(data);
if(data.code=='200'){
clearInterval(clock);
var msg=`微信openid:`+data.data.openid+`<div style='padding-top:20px;'>微信昵称:`+data.data.nickname+`</div>`;
layer.open({
title: data.msg
,area: ['400px', '200px']
,content: msg
});
}
}
})
}
</script>
</html>
config
记得设置数据库账号密码和数据库名字
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
return [
// 数据库类型
'type' => 'mysql',
// 服务器地址
'hostname' => 'localhost',
// 数据库名
'database' => '',
// 用户名
'username' => '',
// 密码
'password' => '',
// 端口
'hostport' => '',
// 连接dsn
'dsn' => '',
// 数据库连接参数
'params' => [],
// 数据库编码默认采用utf8
'charset' => 'utf8',
// 数据库表前缀
'prefix' => 'wx_',
// 数据库调试模式
'debug' => true,
// 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器)
'deploy' => 0,
// 数据库读写是否分离 主从式有效
'rw_separate' => false,
// 读写分离后 主服务器数量
'master_num' => 1,
// 指定从服务器序号
'slave_no' => '',
// 自动读取主库数据
'read_master' => false,
// 是否严格检查字段是否存在
'fields_strict' => true,
// 数据集返回类型
'resultset_type' => 'array',
// 自动写入时间戳字段
'auto_timestamp' => false,
// 时间字段取出后的默认时间格式
'datetime_format' => 'Y-m-d H:i:s',
// 是否需要进行SQL性能分析
'sql_explain' => false,
// Builder类
'builder' => '',
// Query类
'query' => '\\think\\db\\Query',
// 是否需要断线重连
'break_reconnect' => false,
// 断线标识字符串
'break_match_str' => [],
];
system.php
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
// +----------------------------------------------------------------------
// | 系统设置
// +----------------------------------------------------------------------
return [
//公众号AppID
'appid'=>"公众号AppID",
//公众号AppSecret
'appsecret'=>"公众号AppSecret",
//token
'token'=>"",
];
Mysql
-- phpMyAdmin SQL Dump
-- version 4.4.15.10
-- https://www.phpmyadmin.net
--
-- Host: localhost
-- Generation Time: 2020-04-18 14:06:19
-- 服务器版本: 5.6.47-log
-- PHP Version: 5.6.40
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET time_zone = "+00:00";
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8mb4 */;
--
-- Database: `wx`
--
-- --------------------------------------------------------
--
-- 表的结构 `wx_qrcode`
--
CREATE TABLE IF NOT EXISTS `wx_qrcode` (
`id` int(10) NOT NULL COMMENT '序号',
`ticket` varchar(500) DEFAULT NULL COMMENT '获取的二维码ticket',
`expire_seconds` int(10) DEFAULT NULL COMMENT '该二维码有效时间,以秒为单位',
`url` varchar(300) DEFAULT NULL COMMENT '二维码图片解析后的地址',
`openid` varchar(50) DEFAULT NULL COMMENT '微信openid',
`logintime` int(10) unsigned DEFAULT '0' COMMENT '登录时间',
`is_first` tinyint(2) DEFAULT '0' COMMENT '0首次关注,1已关注',
`nickname` varchar(100) DEFAULT NULL COMMENT '微信昵称',
`headimgurl` varchar(300) DEFAULT NULL COMMENT '头像',
`sex` tinyint(2) DEFAULT '0' COMMENT '性别:0未知,1男,2女',
`country` varchar(100) DEFAULT NULL COMMENT '用户所在国家',
`province` varchar(100) DEFAULT NULL COMMENT '用户所在省份',
`city` varchar(100) DEFAULT NULL COMMENT '用户所在城市',
`create_time` int(10) NOT NULL COMMENT '添加时间'
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COMMENT='二维码表';
-- --------------------------------------------------------
--
-- 表的结构 `wx_token`
--
CREATE TABLE IF NOT EXISTS `wx_token` (
`id` int(10) NOT NULL COMMENT '序号',
`appid` varchar(100) NOT NULL COMMENT '公众号appid',
`access_token` varchar(500) NOT NULL COMMENT 'token值',
`expires_in` int(10) NOT NULL COMMENT '凭证有效时间',
`create_time` int(10) NOT NULL COMMENT '创建时间'
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='微信access_token表';
--
-- Indexes for dumped tables
--
--
-- Indexes for table `wx_qrcode`
--
ALTER TABLE `wx_qrcode`
ADD PRIMARY KEY (`id`);
--
-- Indexes for table `wx_token`
--
ALTER TABLE `wx_token`
ADD PRIMARY KEY (`id`);
--
-- AUTO_INCREMENT for dumped tables
--
--
-- AUTO_INCREMENT for table `wx_qrcode`
--
ALTER TABLE `wx_qrcode`
MODIFY `id` int(10) NOT NULL AUTO_INCREMENT COMMENT '序号',AUTO_INCREMENT=4;
--
-- AUTO_INCREMENT for table `wx_token`
--
ALTER TABLE `wx_token`
MODIFY `id` int(10) NOT NULL AUTO_INCREMENT COMMENT '序号',AUTO_INCREMENT=2;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
这些东西直接放入最原始的tp5后启动服务就能显示公众号的二维码
我现在就完成这个时候了
最后,这些代码都不是我的,是我从https://download.csdn.net/download/IT_yongsheng/12337100下载的
欠缺
- 需要完成二维码关注后登陆信息
- 并入帝国cms微信插件,毕竟模板生成的页面没法动态
- 模板页面显示微信登录信息
2020年9月22日改
继续干
上面的代码就有问题,运行之后不会反馈微信发送的信息,这样就会显示服务器故障,不过后来经过一位老哥php小渣渣的完善,现在已经已经没问题了。(老哥博客里面也有微信登录教程)
对了,需要注意的是,本身代码里面没有设置解密方式,加密方式只能是明文或者兼容,这样才能成功。
另外,开启服务器设置本身对授权那些毫无影响,那些本身就做了各种防护,出现服务器故障肯定是代码的问题,除非你授权的不是商品软件。
暂时就想到这么多,完成了1和3,最后整2。
2020年9月25日改