微信公众号

微信公众号一

一、微信公众平台概述

1、微信发展史

2011年1月21日,腾讯推出
2012年8月20日,腾讯推出微信公众平台功能,同年11月开放第三方接口
2013年11月注册用户量突破6亿,是亚洲地区最大用户群体的移动即时通讯软件

2、微信与微信公众平台的区别及作用

微信公众平台依赖于微信,多个用户可以关注同一个公众平台,微信基于点对点关系,给朋友发信息(一对一),公众号是依赖于微信平台中,必须先有微信和才有公众号

公众平台作用:
品牌推广,服务(发消息让维修工作人员上门服务等)

3、微信公众平台的类型

订阅号
服务号
企业微信

(1)、三个区别简单说明

参考地址

https://kf.qq.com/faq/120911VrYVrA130805byM32u.html

新闻资讯类的 一般用订阅号
做服务的 用服务号
企业内部用的 用企业号(不过一般企业都用钉钉,因为这个要钱)

订阅号 是在订阅号文件夹种,服务号和企业是和好友列表同级的

订阅号 每天可以发1条 服务号 每个月只能发4条(可以发无数条,但是用户只能接受到4条)

微信认证:认证一次需要300元人民币,每年都需要认证一次。

个人注册使用只能是 【订阅号】,如果企业的话,都是可以注册,但是根据业务不同,选择不同类型公众号。

(2)、注册公众平台

https://mp.weixin.qq.com/

在这里插入图片描述

学习阶段不注册它也行
根据公众平台的提示,进行一步步的填写资料,完成注册功能,如果是给企业使用,一定要认证一下,这样才能使用到一些支付功能。个人开发者测试阶段,可以不用认证它。因为公众平台,给我们开发者测试提供一个测试平台。

(3)、登录公众平台(订阅号)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4、微信公众平台的两种运行模式

两种模式是互斥的,只能同时存在一个

(1)、编辑模式

使用微信公众号提供的统一的微信公众管理平台,进行操作。所有功能都已经写好,直接使用即可。只需要编辑相关内容信息。适合不会编程的人使用。
如果我们使用了编辑模式,它就不能很好的与我们现有的公司的系统结合,所以如果企业中使用了此方式就和我们开发没有太多关系了。

(2)、开发者模式

微信公众平台提供了服务器接入的方式,具有开发能力的运营者,可以进行定制开发。
开发者模式:特别适合企业,所以我们说的微信公众号开发就是说开发者模式的学习与使用。
开发者模式:需要一台或多台外网能访问到的服务器
注意:微信公众平台管理中,编辑模式和开发者模式是互斥的,也就是说只能使用其中一种。

开发者模式有2种请求方式:

被动:

在这里插入图片描述

主动(curl发起的请求):

在这里插入图片描述

二、编辑模式

微信给我们提供好的一个后台管理平台,通过此管理平台,可以进行公众号的管理操作。(这个模式非常弱,弱爆了)

1、编辑模式与开发者模式切换

在这里插入图片描述

2、被关注时候自动回复

在这里插入图片描述
注意:视频需要审核,多半整文字
在这里插入图片描述

3、关键词回复

在这里插入图片描述
在这里插入图片描述

(1)弊端一

在这里插入图片描述
这种情况,输入1 就只想回复小姐姐,但是它是随机的,真尴尬

(2)弊端二

半匹配关键词,要想让它回复,必须在你发送的文本中要有全的关键词才可以

三、开发准备环境工作

1、开发公众号准备

(1)、外网服务器(上线)

这是上线必选,腾讯云 阿里云 百度云,花钱买吧,学习阶段不建议

(2)、内网穿透(开发)

其实我也有服务器,做开发怎么可能会不在腾讯云搞活动买上一台呢?哈哈
抱着学习的心态,我选择用这个natapp软件

其实就是一个软件,个人感觉这个比外网服务器好调试

https://natapp.cn/

natapp软件,它给我们提供一个外网的域名,通过此软件,把我们内网的IP和端口,映射到natapp的服务器上面,这样公众号服务器访问到natapp的服务器上,然后natapp在把请求转发到内网中,从而就实现了内网的穿透。

注:软件平台,需要注册,注册是免费不花钱的。可以免费使用,需要实名认证。成年。

(3)、注册natapp

在这里插入图片描述

(4)、实名认证

在这里插入图片描述

(5)、购买隧道

在这里插入图片描述
在这里插入图片描述
这个很重要,等下客户端需要用到
在这里插入图片描述

(6)、下载软件并进行配置

根据你系统选择对应版本下载

https://natapp.cn/#download

下载下来只有一个natapp.exe,在natapp.exe同级目录下
新建配置文件config.ini
输入以下内容

[default]
# 对应一条隧道的authtoken值,在后台列表中复制过来
authtoken=aabbcc
# 日志等级,默认即可
loglevel=DEBUG

(7)、运行natapp

(7.1)、配置apache多端口

先 查看需要配置的端口是否被占用
如果查找到记录则表示此端口有在用

linux
netstat –tunpl | grep 8080  
windows
netstat –ano | findstr 8080 
#监听的端口
Listen 8080 
<VirtualHost *:8080>
	# 设置网站目录
	DocumentRoot "E:\eamp\www\wx.com"
	# 设置网站域名(这里是基于端口的不用设置都行)
	ServerName localhost
	# 一定要设置日志,日志可以访问我们进行系统统计
	# 日志是目录不会自动创建需要手动创建,文件是会自动创建
	# 错误日志
	ErrorLog "E:\eamp\www\wx.com\logs\error.log"
	# 成功日志
	CustomLog "E:\eamp\www\wx.com\logs\access.log" combined
	# 设置目录访问权限
	<Directory "E:\eamp\www\wx.com">
	    # 指定目录启用特性
	    Options Indexes FollowSymLinks 
	    # 是否允许使用.htaccess文件
	    AllowOverride All
	    # 访问目录权限 apache2.4
	    Require all granted
	</Directory>
</VirtualHost>
(7.2)、运行natapp

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

四、开发者模式

1、开启开发模式

在这里插入图片描述

2、接入指南文档

地址

https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Access_Overview.html

在这里插入图片描述

在这里插入图片描述

3、接入原理图

在这里插入图片描述

4、代码接入具体步骤

(1)、新建一个wx.php

在这里插入图片描述
通过上面内网穿透的地址访问
在这里插入图片描述

(2)、把访问地址添加到后台去

在这里插入图片描述
提交发现验证失败
在这里插入图片描述

这个时候natapp的好处就来了,打开请求输入页面地址

http://127.0.0.1:4040/

在这里插入图片描述
在这里插入图片描述

直接贴代码

<?php

/**
 * 公众号被动接受处理类
 */

$wx = new Wx();

class Wx
{
    // 微信后台设置的token值 php7.1之后可以加权限 private
    const TOKEN = 'weixin';

    // 构造方法
    public function __construct()
    {
        
        // 判断是否是第1次接入 echostr
        if (!empty($_GET['echostr'])) {
            echo $this->checkSign();
        }
    }
    /**
     * 初次接入校验
     * @return [type] [description]
     */
    private function checkSign()
    {
        //需要返回的随机字符串
        $echostr = $_GET["echostr"];
        //进行对比的参数
        $signature = $_GET["signature"];

        //进行操作的两个参数
        $timestamp = $_GET["timestamp"];
        $nonce = $_GET["nonce"];
        //后台设置的tokne值
        $token = self::TOKEN;

        //1.将token、timestamp、nonce三个参数进行字典序排序 
        $tmpArr = array($token, $timestamp, $nonce);
        sort($tmpArr, SORT_STRING);

        // 2.将三个参数字符串拼接成一个字符串进行sha1加密
        $tmpStr = implode($tmpArr);
        $tmpStr = sha1($tmpStr);

        // 3.开发者获得加密后的字符串可与signature对比,标识该请求来源于微信
        if ($tmpStr === $signature) {
            //请求来源于微信,请原样返回echostr参数内容
            return $echostr;
        }
        return '';
    }
}

一定要保持一致,否则接入失败
在这里插入图片描述

再次提交,一步到位直接成功

5、测试开发微信公众平台的使用

因为个人注册未认证或公司已使用的平台不方便调试,还有一些个人注册的订阅号权限过小,有些功能无法开发测试,所以公众平台提供一个,测试平台,方便开发者开发。

地址

https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Requesting_an_API_Test_Account.html

在这里插入图片描述

在这里插入图片描述
进入了测试平台后,就需要再次接入一次。
在这里插入图片描述
在这里插入图片描述
继续往下拉就会发现有个测试二维码,扫码即可就行代码测试
在这里插入图片描述

五、常用接受消息

1.一些常用的知识点预备

客户端发了一个标准数据格式 我们后端服务器用 $_GET $_POST接收
假如用户发了一个非标准数据(比如json,或者xml数据),我们后端服务器该怎么接受呢?

<?php

#var_dump(json_decode(file_get_contents('php://input'),true));

# 获取原生的请求数据
$xml = file_get_contents('php://input');

# 把xml转换为object对象来处理
$obj = simplexml_load_string($xml,'SimpleXMLElement',LIBXML_NOCDATA); 
# SimpleXMLElement 对象名称这个固定的,因为我们要用第三个参数所以要写    
#LIBXML_NOCDATA,这个是处理富文本的时候加的参数,不要返回对象,返回成字符串
#意思是看到有CDATA标记的时候就这样来处理


var_dump($obj);
// 获取name
echo $obj->stus->name;

echo "\n";

$name = '张三';
$age = 20;

# 数据展开一定要是索引数组
$arr[] = $name;
$arr[] = $age;

#$str = "小伙子姓名:{$name} 芳龄:${age}";
$str = "小伙子姓名:%s 芳龄:%d";
# 格式化替换输出
$str = sprintf($str,$name,$age);

# 数据展开 php7以后才有的
$str = sprintf($str,...$arr);

echo $str;

#cdata:在节点中有富文本时才使用它

2.六大消息接收接口

地址

https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Receiving_standard_messages.html

文本(text)、图片(image)、语音(voice)、视频(video)、地理位置(location)、链接(link)

我们接收微信发送的数据并写入日志

在这里插入图片描述
给测试账号发送信息,看到立马打印出日志
在这里插入图片描述
在没学natapp之前这个是必须打印调试的,现在有了natapp直接访问4040就可以直接看到相关信息

六、常用被动回复消息

在这里插入图片描述

1.介绍

当用户发送消息给公众号时或某些特定的用户操作引发的事件推送时,会产生一个POST请求,开发者可以在返回特定XML结构,来对该消息进行响应。
现支持回复类型有:
文本、图片、图文、语音、视频、音乐
严格来说:发送被动响应消息其实并不是一种接口,而是对微信服务器发过来消息的一次回复(响应)。

2.回复文本消息

在这里插入图片描述

注意:
在这里插入图片描述

<?php

/**
 * 公众号被动接受处理类
 */

$wx = new Wx();

class Wx
{
    // 微信后台设置的token值 php7.1之后可以加权限 private
    const TOKEN = 'weixin';

    // 构造方法
    public function __construct()
    {

        // 判断是否是第1次接入 echostr
        if (!empty($_GET['echostr'])) {
            echo $this->checkSign();
        } else {
            //接收处理数据
            $this->acceptMsg();
        }
    }


    /**
     * 接收公众号发过来的数据
     * @return [type] [description]
     */
    private function acceptMsg()
    {
        // 获取原生请求数据
        $xml = file_get_contents('php://input');
        //把xml转换为obj对象处理
        $obj = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
        //写接收日志
        $this->writeLog($xml);
        //处理回复信息
        //1.判断消息类型
        //2.根据不同的类型,回复处理不同的信息
        //判断类型
        $MsgType = $obj->MsgType;
        $fun = $MsgType . 'Fun';
        //调用方法
        echo $this->$fun($obj);
    }

    //处理回复文本
    // 处理回复文本
    private function textFun($obj)
    {
        $content = $obj->Content;
        // 回复文本
        $content = '公众号:' . $content;
        return $this->createText($obj, $content);
    }

    // 生成文本消息XML
    private function createText($obj, string $content)
    {
        $xml = '<xml>
		<ToUserName><![CDATA[%s]]>
		</ToUserName>
		<FromUserName><![CDATA[%s]]>
		</FromUserName>
		<CreateTime>%s</CreateTime>
		<MsgType><![CDATA[text]]>
		</MsgType>
		<Content><![CDATA[%s]]>
		</Content>
		</xml>';
        // 格式化替换输出
        $str = sprintf($xml, $obj->FromUserName, $obj->ToUserName, time(), $content);
        return $str;
    }




    /**
     * 写日志
     * @param  string      $xml  写入的xml
     * @param  int|integer $flag 标识 1:请求 2:发送
     * @return [type]            [description]
     */
    private function writeLog(string $xml, int $flag = 1)
    {
        $flagstr = $flag == 1 ? '接受' : '发送';
        $prevstr = '[' . $flagstr . ']' . date('Y-m-d') . "-----------------------------\n";
        $log = $prevstr . $xml . "\n---------------------------------------------\n";
        // 写日志                       追加的形式去写入
        file_put_contents('wx.xml', $log, FILE_APPEND);
        return true;
    }



    /**
     * 初次接入校验
     * @return [type] [description]
     */
    private function checkSign()
    {
        //需要返回的随机字符串
        $echostr = $_GET["echostr"];
        //进行对比的参数
        $signature = $_GET["signature"];

        //进行操作的两个参数
        $timestamp = $_GET["timestamp"];
        $nonce = $_GET["nonce"];
        //后台设置的tokne值
        $token = self::TOKEN;

        //1.将token、timestamp、nonce三个参数进行字典序排序 
        $tmpArr = array($token, $timestamp, $nonce);
        sort($tmpArr, SORT_STRING);

        // 2.将三个参数字符串拼接成一个字符串进行sha1加密
        $tmpStr = implode($tmpArr);
        $tmpStr = sha1($tmpStr);

        // 3.开发者获得加密后的字符串可与signature对比,标识该请求来源于微信
        if ($tmpStr === $signature) {
            //请求来源于微信,请原样返回echostr参数内容
            return $echostr;
        }
        return '';
    }
}

2.回复图片消息

这只是主要代码
在这里插入图片描述
在这里插入图片描述

3.回复音乐消息

这只是主要代码
在这里插入图片描述
在这里插入图片描述

七、接口调用凭证access_token

1.php发送请求的方法

(1)、file_get_contents

file_get_contents

#发起请求 方案1  不推荐用 对https支持不好,会给我们的服务器添加压力
$data = file_get_contents($url);

#如果出现乱码,需要查看一下网站的编码,比如网站的编码是gbk,那就转换成utf8
echo mb_convert_encoding($data,'utf-8','gbk');
(2)、fsockopen(不推荐)

//               域名            端口 错误码  错误信息  超时时间

$data = '';
$fp = fsockopen("localhost", 8080, $errno, $errstr, 30);
if (!$fp) {
    echo "$errstr ($errno)<br />\n";
} else {
	// 注意如果想加out 这个内容就浏览器打开复制请求头的内容
	//比如你可以加一个模拟浏览器请求
    $out = "GET /abc.html HTTP/1.1\r\n";
    $out .= "Host: localhost\r\n";
    $out .= "User-Agent: MSIE\r\n";
    $out .= "Connection: Close\r\n\r\n";
    // 发送请求
    fwrite($fp, $out);
    while (!feof($fp)) {
    	// 接受
        $data .= fgets($fp, 128);
    }
    // 关闭资源
    fclose($fp);
}

(3)、curl

curl是扩展,需要我们在php.ini文件中开启的

四个步骤,初始化 设置相关参数(这里忘了可以百度),发起请求 ,关闭请求

这里要注意一下 错误信息的获取 还有 跳过证书检查

(3.1)、curl发起get请求
function http_get($url){
	// 初始化
	$ch = curl_init();
	// 相关设置
	# 设置请求的URL地址
	curl_setopt($ch,CURLOPT_URL,$url);
	# 请求头关闭
	curl_setopt($ch,CURLOPT_HEADER,0);
	# 请求的得到的结果不直接输出,而是以字符串结果返回  必写
	curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
	# 设置请求的超时时间 单位秒
	curl_setopt($ch,CURLOPT_TIMEOUT,30);
	# 设置浏览器型号
	curl_setopt($ch,CURLOPT_USERAGENT,'MSIE001');

	# 证书不检查
	curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,0);
	curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,0);

	// 发起请求
	$data = curl_exec($ch);

	// 有没有发生异常
	if(curl_errno($ch) > 0){
		// 把错误发送给客户端
		echo curl_error($ch);
		$data = '';
	}

	// 关闭请求
	curl_close($ch);

	return $data;
}
(3.2)、curl发起post请求

和get就一点点区别,好比ajax有点点不一样,最后send出去

function http_post($url,$ret){
	// 初始化
	$ch = curl_init();
	// 相关设置
	# 设置请求的URL地址
	curl_setopt($ch,CURLOPT_URL,$url);
	# 请求头关闭
	curl_setopt($ch,CURLOPT_HEADER,0);
	# 请求的得到的结果不直接输出,而是以字符串结果返回  必写
	curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
	# 设置请求的超时时间 单位秒
	curl_setopt($ch,CURLOPT_TIMEOUT,30);
	# 设置浏览器型号
	curl_setopt($ch,CURLOPT_USERAGENT,'MSIE001');

	# 证书不检查
	curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,0);
	curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,0);

	# 设置为post请求
	# 开启post请求
	curl_setopt($ch,CURLOPT_POST,1);
	# post请求的数据 
	curl_setopt($ch,CURLOPT_POSTFIELDS,$ret);

	// 发起请求
	$data = curl_exec($ch);

	// 有没有发生异常
	if(curl_errno($ch) > 0){
		// 把错误发送给客户端
		echo curl_error($ch);
		$data = '';
	}

	// 关闭请求
	curl_close($ch);

	return $data;
}
#调用
#echo http_post('http://localhost:8080/post.php',['id'=>1,'name'=>'你好世界']);
(3.2)、curl发起post文件上传
function http_post_file($url,$ret,$file=''){
	if (!empty($file)) {  // 有文件上传
		# php5.5之前 '@'.$file;就可以进地文件上传
		# $ret['pic'] = '@'.$file;
		# php5.6之后用此方法
		$ret['pic'] = new CURLFile($file);
	}
	// 初始化
	$ch = curl_init();
	// 相关设置
	# 设置请求的URL地址
	curl_setopt($ch,CURLOPT_URL,$url);
	# 请求头关闭
	curl_setopt($ch,CURLOPT_HEADER,0);
	# 请求的得到的结果不直接输出,而是以字符串结果返回  必写
	curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
	# 设置请求的超时时间 单位秒
	curl_setopt($ch,CURLOPT_TIMEOUT,30);
	# 设置浏览器型号
	curl_setopt($ch,CURLOPT_USERAGENT,'MSIE001');

	# 证书不检查
	curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,0);
	curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,0);

	# 设置为post请求
	# 开启post请求
	curl_setopt($ch,CURLOPT_POST,1);
	# post请求的数据 
	curl_setopt($ch,CURLOPT_POSTFIELDS,$ret);

	// 发起请求
	$data = curl_exec($ch);

	// 有没有发生异常
	if(curl_errno($ch) > 0){
		// 把错误发送给客户端
		echo curl_error($ch);
		$data = '';
	}
	// 关闭请求
	curl_close($ch);
	return $data;
}

调用

#__DIR__ 魔术常量,代表当前路径
# 绝对路径
/*$file = __DIR__.'/1.jpg';
echo http_post_file('http://localhost:8080/post.php',['id'=>1,'name'=>'你好世界'],$file);*/

后台接收简单代码

#pic 上面设置的
$files = $_FILES['pic'];
# 得到扩展名
$ext = pathinfo($files['name'],PATHINFO_EXTENSION);
# 上传后的文件名
$name = time().'.'.$ext;

# 上传到服务器的绝对路径  up目录下
$realpath = __DIR__.'/up/'.$name;
move_uploaded_file($files['tmp_name'],$realpath);
(3.3)、把curl封装一下
function http_request($url,$ret='',$file=''){
	if (!empty($file)) {  // 有文件上传
		# php5.5之前 '@'.$file;就可以进地文件上传
		# $ret['pic'] = '@'.$file;
		# php5.6之后用此方法
		$ret['pic'] = new CURLFile($file);
	}
	// 初始化
	$ch = curl_init();
	// 相关设置
	# 设置请求的URL地址
	curl_setopt($ch,CURLOPT_URL,$url);
	# 请求头关闭
	curl_setopt($ch,CURLOPT_HEADER,0);
	# 请求的得到的结果不直接输出,而是以字符串结果返回  必写
	curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
	# 设置请求的超时时间 单位秒
	curl_setopt($ch,CURLOPT_TIMEOUT,30);
	# 设置浏览器型号
	curl_setopt($ch,CURLOPT_USERAGENT,'MSIE001');

	# 证书不检查
	curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,0);
	curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,0);

	# 设置为post请求
	if($ret){ # 如果 $ret不为假则是post提交
		# 开启post请求
		curl_setopt($ch,CURLOPT_POST,1);
		# post请求的数据 
		curl_setopt($ch,CURLOPT_POSTFIELDS,$ret);
	}
	// 发起请求
	$data = curl_exec($ch);
	// 有没有发生异常
	if(curl_errno($ch) > 0){
		// 把错误发送给客户端
		echo curl_error($ch);
		$data = '';
	}
	// 关闭请求
	curl_close($ch);
	return $data;
}

2.获取access_token

(1)、基本介绍
https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Get_access_token.html

access_toke是公众号的全局唯一接口调用凭据,公众号调用各接口时都需使用它。

access_token的存储至少要保留512个字符空间。
access_token的有效期目前为2个小时。

access_token的每天请求的次数为2000次。

根据官方所提的要求,那么我们在实现工作,一定要缓存起来我们access_token。
缓存的方案
数据库、redis、mongodb、memcache(推荐方案)、文件缓存
在这里插入图片描述

在这里插入图片描述

(2)、代码操作
(2.1)、缓存到文件中

上面可知需要两个参数
appid
appsecret

在这里插入图片描述
在这里插入图片描述
代码示例,由于需要测试

<?php

/**
 * 主动模式
 */


$wx  = new Wechat();

echo $wx->getAccessToken();

class Wechat
{
    // appid
    const APPID = 'wx208d2fff5f40ea69';
    // appsecret
    const SECRET = 'e6f5e83af1c0e7cb00d76b1d68450417';

    /**
     * 得到access_token  access_token是全局唯一有效的
     * @return [type] [description]
     */
    public function getAccessToken()
    {
        # 缓存的文件
        $cacheFile = self::APPID . '_cache.log';

        // 判断文件是否存在,要是不存在则表示没有缓存
        // 存在判断修改的时间是否过了有效期,如果没有过,则不进行url网络请求
        if (is_file($cacheFile) && filemtime($cacheFile) + 7000 > time()) {
            echo '缓存了<hr>';
            return file_get_contents($cacheFile);
        }

        // 第1次或缓存过期
        $surl = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s';
        $url = sprintf($surl, self::APPID, self::SECRET);
        // 发起GET请求
        $json = $this->http_request($url);
        // 把json转为数组
        $arr = json_decode($json, true);
        $access_token = $arr['access_token'];
        // 写缓存
        file_put_contents($cacheFile, $access_token);
        // 返回数据
        echo '2222<hr>';
        return $access_token;
    }

    /**
     * 发起请求
     * @param  strin $url  url地址
     * @param  string|array $ret  请求体
     * @param  string $file 上传的文件绝对地址
     * @return [type]       [description]
     */
    private function http_request($url, $ret = '', $file = '')
    {
        if (!empty($file)) {  // 有文件上传
            # php5.5之前 '@'.$file;就可以进地文件上传
            # $ret['pic'] = '@'.$file;
            # php5.6之后用此方法
            $ret['media'] = new CURLFile($file);
        }
        // 初始化
        $ch = curl_init();
        // 相关设置
        # 设置请求的URL地址
        curl_setopt($ch, CURLOPT_URL, $url);
        # 请求头关闭
        curl_setopt($ch, CURLOPT_HEADER, 0);
        # 请求的得到的结果不直接输出,而是以字符串结果返回  必写
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        # 设置请求的超时时间 单位秒
        curl_setopt($ch, CURLOPT_TIMEOUT, 30);
        # 设置浏览器型号
        curl_setopt($ch, CURLOPT_USERAGENT, 'MSIE001');

        # 证书不检查
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);

        # 设置为post请求
        if ($ret) { # 如果 $ret不为假则是post提交
            # 开启post请求
            curl_setopt($ch, CURLOPT_POST, 1);
            # post请求的数据 
            curl_setopt($ch, CURLOPT_POSTFIELDS, $ret);
        }
        // 发起请求
        $data = curl_exec($ch);
        // 有没有发生异常
        if (curl_errno($ch) > 0) {
            // 把错误发送给客户端
            echo curl_error($ch);
            $data = '';
        }
        // 关闭请求
        curl_close($ch);
        return $data;
    }
}

(2.2)、缓存到memcache(推荐 )
#回忆一下memeche
查看memcache缓存的列表信息
stats items
#执行结果
STAT items:1:number 2
STAT items:1:age 3054538109
STAT items:1:evicted 0
STAT items:1:evicted_nonzero 0
STAT items:1:evicted_time 0
STAT items:1:outofmemory 0
STAT items:1:tailrepairs 0
STAT items:6:number 1
STAT items:6:age 3054538477
STAT items:6:evicted 0
STAT items:6:evicted_nonzero 0
STAT items:6:evicted_time 0
STAT items:6:outofmemory 0
STAT items:6:tailrepairs 0

#查看块中的缓存列表(找到带number的查看 6是items后面的 1 是number后面的)
stats cachedump 6 1

#执行结果
ITEM wx3e7552f91168c93f_key [157 b; 1544673130 s]
get wx3e7552f91168c93f_key


#删除
delete wx3e7552f91168c93f_key
	/**
	 * 缓存到memcache中
	 * @return [type] [description]
	 */
	private function getAccessTokenMem(){
		# 缓存的key值
		$cachekey = self::APPID.'_key';
		$mem = new Memcache();
		$mem->addServer('localhost',11211);
		// 添加 如果存在则返回false
		#$mem->add('b','bbb',0,3);
		#$mem->set('d','ddd',0,5);
		# 有缓存 读缓存
		if (false != ($access_token = $mem->get($cachekey))) {
			return $access_token;
		}
		// 第1次或缓存过期
		$surl = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s';
		$url = sprintf($surl,self::APPID,self::SECRET);
		// 发起GET请求
		$json = $this->http_request($url);
		// 把json转为数组
		$arr = json_decode($json,true);
		$access_token = $arr['access_token'];
		// 写缓存
		$mem->set($cachekey,$access_token,0,7000);
		// 返回数据
		return $access_token;
	}

八、自定义菜单

1.自定义菜单概述

(1).基本概述

https://developers.weixin.qq.com/doc/offiaccount/Custom_Menus/Creating_Custom-Defined_Menu.html

在这里插入图片描述

我直接总结注意点:
总共能创建几个菜单?15个 3个一级菜单 5个二级
一级菜单最多4个汉字,二级菜单最多7个汉字,多出来的部分将会以“…”代替

面试可能会被文?二级菜单我可以整8个字吗??可以,显示7个多余的…代替,最大只能是60个字节

(2).按钮事件

在这里插入图片描述
具体注意点:
1.click ,用的非常少,比如可以用在电影网站,需要vip,获取最新的口令,才能看到vip视频,根据时间获取fromusername、openid,然后查看你是不是vip

2.view,工作中用的最多的是这个,认证用户才可以,非认证的只能跳转此连接图文,不能跳转到别的i地方去

todo:明天回头来改,剩下一大堆,几乎不用jssdk

请注意,3到8的所有事件,仅支持微信iPhone5.4.1以上版本,和Android5.4以上版本的微信用户,旧版本微信用户点击后将没有回应,开发者也不能正常接收到事件推送。9和10,是专门给第三方平台旗下未微信认证(具体而言,是资质认证未通过)的订阅号准备的事件类型,它们是没有事件推送的,能力相对受限,其他类型的公众号不必使用。

2.自定义菜单创建

官网有一个示例
在这里插入图片描述

代码示例

    /**
     * 创建自定义菜单
     * @param  array|string $menu [description]
     * @return [type]       [description]
     */
    public function createMenu($menu)
    {
        if (is_array($menu)) {
            // 因为菜单有中文,所以一定要写json_encode第2个参数,让中文不乱码
            $data = json_encode($menu, JSON_UNESCAPED_UNICODE); # 256
        } else {
            $data = $menu;
        }
        // 创建自定义菜单URL
        $url = 'https://api.weixin.qq.com/cgi-bin/menu/create?access_token=' . $this->getAccessToken();
        // 发起请求
        $json = $this->http_request($url, $data);
        return $json;
    }

调用

$menuList = '{
    "button":[
    {    
         "type":"click",
         "name":"首页",
         "key":"index001"
     },
     {
          "name":"最新活动",
          "sub_button":[
          {    
              "type":"view",
              "name":"搜索",
              "url":"http://m.baidu.com/"
           },
           {
              "type":"click",
              "name":"客服",
              "key":"kefu001"
           },{
                   "type": "pic_sysphoto", 
                   "name": "系统拍照", 
                   "key": "photo001"
             },{
               "name": "发送位置", 
           "type": "location_select", 
           "key": "rselfmenu_2_0"
               }]
      },
      {    
         "type":"view",
         "name":"个人中心",
         "url":"http://m.itcast.cn/"
     }
      ]
}';


echo $wx->createMenu($menuList);

代表执行成功。这个时候你关注就会发现菜单
在这里插入图片描述

3.自定义菜单删除

用于想要修改新的菜单,就是把之前的全部干掉,然后重新创建菜单

所以删除接口很简单,因为一般结合创建菜单使用

https://developers.weixin.qq.com/doc/offiaccount/Custom_Menus/Deleting_Custom-Defined_Menu.html

在这里插入图片描述
代码示例

	/**
	 * 删除自定义菜单
	 * @return [type] [description]
	 */
	public function delMenu(){
		$url = 'https://api.weixin.qq.com/cgi-bin/menu/delete?access_token='.$this->getAccessTokenMem();
		// 发起请求
		$json = $this->http_request($url);
		return $json;
	}

4.自定义菜单的响应

牢记 click和view 只有认证的公众号使用view事件才能跳转到任意url中。


    // 事件的处理
    private function eventFun($obj)
    {
        // 事件的名称
        $Event = $obj->Event;
        switch ($Event) {
            case 'CLICK':
                // 关于点击事件
                return $this->clickFun($obj);
                break;
        }
    }


    // 按钮的点击事件
    private function clickFun($obj)
    {
        $EventKey = $obj->EventKey;
        if ('index001' == $EventKey) {
            return $this->createText($obj, '你点击首页按钮');
        } elseif ('kefu001' == $EventKey) {
            return $this->createText($obj, '你点击找客服小姐姐!');
        }
        return $this->createText($obj, '我解决不了!');
    }

此时你点击菜单就会分别响应不同的信息

九、素材新增

公众号经常有需要用到一些多媒体素材的场景,例如在使用接口特别是发送消息时,对多媒体文件、多媒体消息的获取和调用等操作,是通过media_id来进行的。素材管理接口对所有认证的订阅号和服务号开放。

1.新增临时素材

https://developers.weixin.qq.com/doc/offiaccount/Asset_Management/New_temporary_materials.html

在这里插入图片描述

要求
图片(image): 2M,支持PNG\JPEG\JPG\GIF格式
语音(voice): 2M,播放长度不超过60s,支持AMR\MP3格式
视频(video): 10MB,支持MP4格式
缩略图(thumb):64KB,支持JPG格式

注意点:
1、临时素材media_id是可复用的。
2、媒体文件在微信后台保存时间为3天,即3天后media_id失效。
3、上传临时素材的格式、大小限制与公众平台官网一致。

临时素材只放一个不重要的东西,会过期的

2.新增永久素材

对于常用的素材,开发者可通过本接口上传到微信服务器,永久使用。
如:企业logo,小图标,公众号有些场景,规定只能使用永久素材。

注:
永久素材的使用一定要谨慎,用于公众号规则我们必须用的地方和企业LOGO。
临时素材我们可以随便用。

3.上传永久和临时素材综合代码

说明:永久素材上传时,它的上传的文件域的名称必须为 media

在这里插入图片描述

(1)、后台管理系统中制作出文件上传的表单html

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>素材管理页面</title>
</head>
<body>
	<form action="post.php" method="post" enctype="multipart/form-data">
		<p>
			素材类型:
			<select name="is_forever">
				<option value="0">临时</option>
				<option value="1">永久</option>
			</select>
			<input type="file" name="media" id="">
			<input type="submit" value="提交素材">
		</p>
	</form>
</body>
</html>

(2)、上传实现

<?php


// 引入微信操作类
include './Wechat.php';

$files = $_FILES['media'];
# 得到扩展名
$ext = pathinfo($files['name'], PATHINFO_EXTENSION);
# 上传后的文件名
$name = time() . '.' . $ext;

# 上传到服务器的绝对路径
$realpath = __DIR__ . '/up/' . $name;
move_uploaded_file($files['tmp_name'], $realpath);


// 上传素材到公众号平台
$wx = new Wechat();
$media_id = $wx->uploadMaterial($realpath, 'image', $_POST['is_forever']);


//入库
$pdo = new PDO("mysql:host=localhost;dbname=php", 'root', 'root', [
    // 有错误抛异常
    PDO::ERRMODE_EXCEPTION,
    // 以关联数组的形式输出
    PDO::FETCH_ASSOC
]);


//定义sql语句

$sql = "insert into material (realpath,ctime,is_forever,media_id) values (?,?,?,?)";
// 预处理对象
$stmt = $pdo->prepare($sql);

// 执行入库

$ret = $stmt->execute([$realpath,time(),$_POST['is_forever'],$media_id]);
var_dump($ret);

 

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

	// 上传素材
	public function uploadMaterial(string $path,string $type='image',$is_forever=0){
		if ($is_forever == 0) {
			// 临时
			$surl = 'https://api.weixin.qq.com/cgi-bin/media/upload?access_token=%s&type=%s';
		}else{
			// 永久
			$surl = 'https://api.weixin.qq.com/cgi-bin/material/add_material?access_token=%s&type=%s';
		}

		$url = sprintf($surl,$this->getAccessTokenMem(),$type);
		// 上传素材到微信公众平台
		$json = $this->http_request($url,[],$path);
		// json转为数组
		$arr = json_decode($json,true);
		// 有前返回,没有则返回空 php7提供的null合并
		return $arr['media_id'] ?? '';
	}

在这里插入图片描述
数据库创建语句

CREATE TABLE `material` (
	`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键ID',
	`realpath` VARCHAR(255) NOT NULL DEFAULT '' COLLATE 'utf8mb4_general_ci',
	`ctime` INT(10) UNSIGNED NOT NULL DEFAULT '0',
	`is_forever` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0',
	`media_id` VARCHAR(255) NOT NULL DEFAULT '' COLLATE 'utf8mb4_general_ci',
	`type` ENUM('image','voice') NOT NULL DEFAULT 'image' COLLATE 'utf8mb4_general_ci',
	PRIMARY KEY (`id`) USING BTREE
)
COMMENT='aa'
COLLATE='utf8mb4_general_ci'
ENGINE=InnoDB
AUTO_INCREMENT=2
;

十、客服消息

地址:

https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Service_Center_messages.html

客服消息是一种主动发送的消息模式,这个就是说微信用户给公众号发信息,在发送消息后,公众号可以点对点的进行回复!!
但是也是有条件的限制,只有**激活用户(发一句语言,或者click点击,一般弄一个菜单,搞一个客服选项)**在48小时之内,可以无限制,发送消息。

1.发送消息

在这里插入图片描述

代码示例

<?php
include './Wechat.php';




if (isset($_POST['msg'])) {
    $openid = $_POST['openid'];
    $msg = $_POST['msg'];

    // 实现公众平台主动发送消息给指定的客户
    echo (new Wechat())->kefuMsg($openid, $msg);
}
?>

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>客服消息</title>
</head>

<body>

    <form action="" method="post">
        <input type="text" name="openid" value="oGdnK6rv8XuoycHPC0UcpbbkGTPw">
        <input type="text" name="msg" id="">
        <input type="submit" value="发送消息">
    </form>

</body>

</html>

十一、生成场景二维码

为了满足用户渠道推广分析和用户帐号绑定等场景的需要,公众平台提供了生成带参数二维码的接口。使用该接口可以获得多个带不同场景值的二维码,用户扫描后,公众号可以接收到事件推送。
场景二维码作用:
解决关注时来源问题
使用的场景:
加盟
活动场景
分销系统

目前有2种类型的二维码:

临时二维码,是有过期时间的,最长可以设置为在二维码生成后的30天(即2592000秒)后过期,但能够生成较多数量。临时二维码主要用于帐号绑定等不要求二维码永久保存的业务场景
永久二维码,是无过期时间的,但数量较少(目前为最多10万个)。永久二维码主要用于适用于帐号绑定、用户来源统计等场景。

1.生成永久和临时二维码

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

总结一下总共三个步骤
1.获取ticket(凭据)
2.通过ticket(凭据)换取二维码图片资源
3.保存二维码图片资源到本机

封装代码示例

	/**
	 * 生成场景二维码
	 * @param  int|integer $flag 0 临时 1永久
	 * @return [type]            [description]
	 */
	public function createQrcode(int $flag = 0,int $id=1){
		// 第1步 获取ticket
		$url = 'https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token='.$this->getAccessTokenMem();
		# 参数的准备
		if (0 === $flag) {
			$data = '{"expire_seconds": 2592000, "action_name": "QR_SCENE", "action_info": {"scene": {"scene_id": '.$id.'}}}';
		}else{
			$data = '{"action_name": "QR_LIMIT_SCENE", "action_info": {"scene": {"scene_id": '.$id.'}}}';
		}
		# 得到ticket
		$json = $this->http_request($url,$data);
		# json转数组
		$arr = json_decode($json,true);
		$ticket = $arr['ticket'];

		// 第2步 用ticket换取二维码资源
		# TICKET记得进行UrlEncode
		$url = 'https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket='.urlencode($ticket);
		# 发起get请求
		$img = $this->http_request($url); 

		// 第3步 写入到文件中
		file_put_contents('qrcode.jpg',$img);

		return 'qrcode.jpg';
	}

2.三级分销表设计

可能最先想到的就是递归
在这里插入图片描述
但是这种,到时候要查询id为1这个人下面有多少下级,就要一直递归,所以就会特别消耗mysql性能。要是数据有几十万,几百万,那不就干崩了么?

三级分销表设计
在这里插入图片描述
数据库代码

CREATE TABLE `user` (
	`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
	`openid` VARCHAR(255) NOT NULL DEFAULT '' COMMENT 'openid' COLLATE 'utf8mb4_general_ci',
	`f1` VARCHAR(255) NOT NULL DEFAULT '' COMMENT '一级' COLLATE 'utf8mb4_general_ci',
	`f2` VARCHAR(255) NOT NULL DEFAULT '' COMMENT '二级' COLLATE 'utf8mb4_general_ci',
	`f3` VARCHAR(255) NOT NULL DEFAULT '' COMMENT '三级' COLLATE 'utf8mb4_general_ci',
	PRIMARY KEY (`id`) USING BTREE
)
COMMENT='用户表'
COLLATE='utf8mb4_general_ci'
ENGINE=InnoDB
;

上面已经生成了二维码,让用户关注后生成二维码,再关注,关注二维码是一个事件
所以是被动的,我们需要去被动处理类里面处理,关注后会有一个事件subscribe,在事件处理类中,添加如下代码

			case 'subscribe':
				// 如果 EventKey 此没有值,表示顶级
				//注意默认 $obj->EventKey获取的是对象
			$EventKey = $obj->EventKey;
			$EventKey = (string)$EventKey;

				if(empty($EventKey)){ // 顶级添加数据库
					$sql = "insert into user (openid) values (?)";
					$stmt = $this->pdo->prepare($sql);
					$stmt->execute([$obj->FromUserName]);
				}else{
					# 得到上级ID号
					$id = str_replace('qrscene_','',$EventKey);
					$id = (int)$id;
					# 查询它的记录
					$sql = "select * from user where id=$id";
					$row = $this->pdo->query($sql)->fetch();

					# 添加本人的记录到数据
					$sql = "insert into user (openid,f1,f2,f3) values (?,?,?,?)";
					$stmt = $this->pdo->prepare($sql);
					$openid = $obj->FromUserName;
					$stmt->execute([$openid,$row['openid'],$row['f1'],$row['f2']]);
				}

				return $this->createText($obj,"欢迎关注我们的公众平台\n这里有你想要的一切!");
				break;

测试
在这里插入图片描述

db.php

<?php
// 数据库,注意更改成本地数据库名称
return new PDO("mysql:host=localhost;dbname=php",'root','root',[
    // 有错误抛异常
    PDO::ERRMODE_EXCEPTION,
    // 以关联数组的形式输出
    PDO::FETCH_ASSOC
]);

十二、微信语音识别

就在关注者在公众号里面说一句话语音,公众号接收到用户的语音并返回对应的文字。
据测试,微信语音识别功能,准确率还是挺好的,当然针对的是普通话

注:对新关注者,立刻生效,对已关注者,24小时之内生效,对已关注都取消关注再次关注,也需要等待。

想要测试需要先开启

在这里插入图片描述
在这里插入图片描述

因为是被动的,发送给对象服务器,响应给微信客户端,需要去被动处理类里面处理

php代码

    // 处理语音
    private function voiceFun($obj)
    {
        $content = (string)$obj->Recognition;
        $content = !empty($content) ? $content : '没有转过来';

        return $this->createText($obj, $content);
    }

十三、微信语音识别微信LBS

LBS 是指基于位置的服务 Location Based Service

它是通过网络定位或是外部定位方式(如GPS)获取终端用户的位置信息(经纬度),根据位置(经纬度)为用户提供相应服务的一种增值业务。

1.开启LBS

在这里插入图片描述

在这里插入图片描述

2.接收用户位置

然后重新关注一下共总好,然后就会发现,每隔5秒就会上传一下位置
日志中可以看到
在这里插入图片描述
natapp4040端口也可以查看
在这里插入图片描述

在这里插入图片描述

3.位置入库

第一步:

给用户表,增加两个字段 latitudelongitude,创建表语句如下

CREATE TABLE `user` (
	`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
	`openid` VARCHAR(255) NOT NULL DEFAULT '' COMMENT 'openid' COLLATE 'utf8mb4_general_ci',
	`f1` VARCHAR(255) NOT NULL DEFAULT '' COMMENT '一级' COLLATE 'utf8mb4_general_ci',
	`f2` VARCHAR(255) NOT NULL DEFAULT '' COMMENT '二级' COLLATE 'utf8mb4_general_ci',
	`f3` VARCHAR(255) NOT NULL DEFAULT '' COMMENT '三级' COLLATE 'utf8mb4_general_ci',
	`latitude` DECIMAL(10,6) NOT NULL DEFAULT '0.000000' COMMENT '纬度',
	`longitude` DECIMAL(10,6) NOT NULL DEFAULT '0.000000' COMMENT '精度',
	PRIMARY KEY (`id`) USING BTREE
)
COMMENT='用户表'
COLLATE='utf8mb4_general_ci'
ENGINE=InnoDB
AUTO_INCREMENT=2
;

第二步:
在这里插入图片描述
在这里插入图片描述

            case 'LOCATION': # 位置
                # 记录位置
                $openid = $obj->FromUserName;
                $Longitude = $obj->Longitude;
                $Latitude = $obj->Latitude;
                // 修改表记录(偷懒写法)
                //$sql = "update user set longitude=$Longitude,latitude=$Latitude where openid='$openid'";
                // 执行sql语句
                //$ret = $this->pdo->exec($sql);

                // 修改表记录(预处理写法)
                //创建预处理sql语句
                $sql = "update user set longitude=:longitude,latitude=:latitude where openid=:openid";
                //执行sql预处理语句,创建一个PDOStatement
                $pdoStmt = $this->$pdo->prepare($sql);
                //更新数据
                $data = ['longitude' => $Longitude, 'latitude' => $Latitude, 'openid' => $openid];
                //参数绑定
                $stmt->bindParam(':longitude', $Longitude);
                $stmt->bindParam(':latitude', $Latitude);
                $stmt->bindParam(':openid', $openid);
                //执行语句
                $ret = $stmt->execute($data);

因为5分钟自动执行一次,所以代码一写好,就已经入库了
在这里插入图片描述

4.整合高德地图位置服务

提示:当你开发越来越多的时候,需要的账号就越多,就好比上面的natapp,高德平台等、最好搞地方集中把账号记录起来,更换手机号的时候要小心。

(1)、注册高德平台

官方地址:

https://lbs.amap.com/

在这里插入图片描述

(2)、添加apikey

在这里插入图片描述
在这里插入图片描述

(3)、代码实现,获取周边位置

在这里插入图片描述
直接上php代码

    // 处理回复文本
    private function textFun($obj)
    {
        $content = $obj->Content;
        // 判断是否是音乐
        if ('音乐' == $content) {
            return $this->musicFun($obj);
        } elseif (strstr($content, '位置-')) {
            // 餐饮
            # 得到关键词
            $kw = str_replace('位置-', '', $content);
            $kw = trim($kw);
            //$openid = $obj->FromUserName;
            //$sql = "select * from user where openid='$openid'";
            //这里地址就给写死了,到时候可以通过数据库查询数据通过openid取出位置
            $url = 'https://restapi.amap.com/v3/place/around?key=e6f5f0cf14172ada0fb2e645affa90d9&location=118.078400,24.618500&keywords=' . $kw . '&types=050000&radius=10000&offset=1&page=1&extensions=all';
            $json = $this->http_request($url);
            # json转为arr
            $arr = json_decode($json, true);
            # 判断是否有搜索的结果
            if (count($arr['pois']) == 0) {
                $content = '没有找到相关服务';
            } else {
                # emoji表情 如果用到了此表情,数据表最好用utf8mb4编码
                $content  = "🚩距您最近:". "\n";
                $content .= "名称:" . $arr['pois'][0]['name'] . "\n";
                $content .= "地址:" . $arr['pois'][0]['address'] . "\n";
                $content .= "距离:" . $arr['pois'][0]['distance'] . "米\n";
            }
            return $this->createText($obj, $content);
        }else{
            $content = '公众号:' . $content;
            return $this->createText($obj, $content);
        }
        
    }

测试结果图
在这里插入图片描述

(4)、总结

在后台开启获取位置服务,选5s获取一次
在事件获取位置的接受处理中,把位置入库
注册位置提供的开放平台(高德),得到api接口地址和apikey
在公众号中进行关键词回复功能中添加相关的业务代码
可以让回复的文本更加的优美,用于emoji表情

十四、网页授权

1、概述

公众号后台可以通过设置授权域名,然后通过此域名生成相应的链接,分享到朋友圈,好友等,后用户通过微信客户端来点击访问此链接,公众平台就可以获取用户基本信息,进而实现业务逻辑。

场景
问卷调查
抽奖
购物车
如果openid和用户和密码,直接登陆

2、网页授权原理

在这里插入图片描述

3、设置微信授权域名

在这里插入图片描述
注意:这里是域名
在这里插入图片描述

4、网页授权开发工具

为了帮助开发者简单和高效地开发和调试微信公众号,推出了全新的 微信开发者工具,集成了公众号网页调试小程序调试两种开发模式。

https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5、微信授权代码实现

地址

https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html

在这里插入图片描述
两种网页授权的区别(工作中多半用userinfo的可以获得用户基本信息)?
在这里插入图片描述

6、微信授权代码实现

在这里插入图片描述

(1)、获取code值

在这里插入图片描述
在这里插入图片描述

在服务器中编写生成跳转地址url的方法
在这里插入图片描述

代码

<?php

//跳转程序

// appid 公众号
$appid = 'wx208d2fff5f40ea69';
// secret 公众号
$secret = 'e6f5e83af1c0e7cb00d76b1d68450417';
// 授权成功后回调地址  请使用 urlEncode 对链接进行处理
//http://ftzsh9.natappfree.cc 是内网穿透工具netapp分配的域名
//当前地址     http://ftzsh9.natappfree.cc/auth/goto.php
$redirect_uri = urlencode('http://ftzsh9.natappfree.cc/auth/shop.php');

$url = 'https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=snsapi_userinfo&state=100#wechat_redirect';

$url = sprintf($url,$appid,$redirect_uri);

// 跳转
header('location:'.$url);

回调地址php

<?php
// appid 公众号
$appid = 'wx208d2fff5f40ea69';
// secret 公众号
$secret = 'e6f5e83af1c0e7cb00d76b1d68450417';
// 得到code
$code = $_GET['code'];

exit($code);

直接在pc浏览器上打开
在这里插入图片描述
去开发工具中打开

在这里插入图片描述
在地址哪里输入地址跳转
在这里插入图片描述
成功取到coe

在这里插入图片描述

注意:每次授权code的值将会不一样,code只能用一次,5分钟没使用就会过期
在这里插入图片描述

(2)、得到openid完成授权

在这里插入图片描述

代码

<?php
// appid 公众号
$appid = 'wx208d2fff5f40ea69';
// secret 公众号
$secret = 'e6f5e83af1c0e7cb00d76b1d68450417';
// 得到code
$code = $_GET['code'];

$url = 'https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code';
$url = sprintf($url, $appid, $secret, $code);
// 发起get请求
$json = http_request($url);
# json 转为  array
$arr = json_decode($json, true);
$access_token = $arr['access_token'];
$openid = $arr['openid'];

exit($openid);

(3)、拉取用户信息

在这里插入图片描述

这个步骤,其实你就可以丰富你那个用户表字段了。
在这里插入图片描述

完整代码

<?php
// appid 公众号
$appid = 'wx208d2fff5f40ea69';
// secret 公众号
$secret = 'e6f5e83af1c0e7cb00d76b1d68450417';
// 得到code
$code = $_GET['code'];

$url = 'https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code';
$url = sprintf($url, $appid, $secret, $code);
// 发起get请求
$json = http_request($url);
# json 转为  array
$arr = json_decode($json, true);
$access_token = $arr['access_token'];
$openid = $arr['openid'];

// 拉取用户信息
$url = 'https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s&lang=zh_CN';
$url = sprintf($url, $access_token, $openid);
// 发起get请求
$json = http_request($url);
# json 转为  array
$userinfo = json_decode($json, true);





function http_request($url, $ret = '', $file = '')
{
    if (!empty($file)) {  // 有文件上传
        # php5.5之前 '@'.$file;就可以进地文件上传
        # $ret['pic'] = '@'.$file;
        # php5.6之后用此方法
        $ret['media'] = new CURLFile($file);
    }
    // 初始化
    $ch = curl_init();
    // 相关设置
    # 设置请求的URL地址
    curl_setopt($ch, CURLOPT_URL, $url);
    # 请求头关闭
    curl_setopt($ch, CURLOPT_HEADER, 0);
    # 请求的得到的结果不直接输出,而是以字符串结果返回  必写
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    # 设置请求的超时时间 单位秒
    curl_setopt($ch, CURLOPT_TIMEOUT, 30);
    # 设置浏览器型号
    curl_setopt($ch, CURLOPT_USERAGENT, 'MSIE001');

    # 证书不检查
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);

    # 设置为post请求
    if ($ret) { # 如果 $ret不为假则是post提交
        # 开启post请求
        curl_setopt($ch, CURLOPT_POST, 1);
        # post请求的数据 
        curl_setopt($ch, CURLOPT_POSTFIELDS, $ret);
    }
    // 发起请求
    $data = curl_exec($ch);
    // 有没有发生异常
    if (curl_errno($ch) > 0) {
        // 把错误发送给客户端
        echo curl_error($ch);
        $data = '';
    }
    // 关闭请求
    curl_close($ch);
    return $data;
}
?>

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <!-- 视口 -->
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>首页</title>
</head>

<body>
    <div class="user">
        <p>openid:<?php echo $openid; ?></p>
        <p>昵称:<?php echo $userinfo['nickname']; ?></p>
        <p>昵称:<?php echo $userinfo['sex'] == 1 ? '先生' : '女士'; ?></p>
        <p>
            <img src="<?php echo $userinfo['headimgurl'] ?>" style="width: 300px;">
        </p>
    </div>
</body>

</html>

(4)、微信授权小结

1.生成跳转的url地址,得到了code
2.用code换取access_token和openid,完成授权
3.非必须的,如果是userinfo授权,则可以获取用户的基本信息

十五、微信JS-SDK

有前端操作,有后端操作

1、什么是JSSDK

就是微信帮助我们完成的JS一个工具的封装,直接调用这些接口就可以完成相应的功能。

作用:
自定义分享的链接(此链接也是有规定,如公众后台设置有效域名一致)
调用一些手机底层 应用,摄像头,获取网络制式

开发步骤(5步):

1.平台绑定授权域名
2.引入公众平台jssdk的js文件
3.根据官方签名算法编写出对就的签名字符串
4.设置前台script中的config接口配置注入权限验证
5.通过前台script中的接口提供的ready方法处理成功验证

2、jssdk绑定域名

为什么要绑定?为了安全
在这里插入图片描述

3、jssdk的使用步骤

地址:

https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html

在这里插入图片描述

(1)、引入JS文件

在这里插入图片描述
在这里插入图片描述

(2)、生成签名算法

(2.1)、得到jsapi_ticket

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
代码

    // 得到jsapi_ticket
    public function getTicket()
    {
        $url = 'https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi&access_token=' . $this->getAccessToken();
        $json = $this->http_request($url);
        $arr = json_decode($json, true);
        return $arr['ticket'];
    }
(2.1)、生成签名

为什么要生成这个玩意?因为下面需要通过config接口注入权限验证配置
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
得到签名

在这里插入图片描述

(3)、通过config接口注入权限验证配置

在这里插入图片描述

在这里插入图片描述
一切正常
在这里插入图片描述
在这里插入图片描述

前端使用

<?php
include '../Wechat.php';
$wx = new Wechat();
$config = $wx->signature();


// var_dump(($config));die();

?>

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>砍一刀</title>
    <script src="./js/jweixin-1.6.0.js"></script>
    <script>
        // 权限配置验证
        wx.config({
        debug: true, // 开启调试模式
        appId: '<?php echo $config['appid']; ?>', // 必填,公众号的唯一标识
        timestamp: <?php echo $config['time']; ?>, // 必填,生成签名的时间戳
        nonceStr: '<?php echo $config['noncestr']; ?>', // 必填,生成签名的随机串
        signature: '<?php echo $config['signature']; ?>', // 必填,签名
        jsApiList: [] // 必填,需要使用的JS接口列表
        });
    </script>
</head>

<body>

</body>

</html>

在这里插入图片描述
注意:这里的安全域名一定要配置,不正确的化,会一直报错
在这里插入图片描述

在这里插入图片描述

(4)、通过ready接口处理成功验证

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

代码:

<?php
include '../Wechat.php';
$wx = new Wechat();
$config = $wx->signature();


// var_dump(($config));die();

?>

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>砍一刀</title>
    <script src="./js/jweixin-1.6.0.js"></script>
    <script>
        // 权限配置验证
        wx.config({
            debug: true, // 开启调试模式
            appId: '<?php echo $config['appid']; ?>', // 必填,公众号的唯一标识
            timestamp: <?php echo $config['time']; ?>, // 必填,生成签名的时间戳
            nonceStr: '<?php echo $config['noncestr']; ?>', // 必填,生成签名的随机串
            signature: '<?php echo $config['signature']; ?>', // 必填,签名
            jsApiList: [
                'onMenuShareAppMessage',
                'onMenuShareTimeline',
                'chooseImage'
            ] // 必填,需要使用的JS接口列表
        });


        // 验证成功后我们要处理的动作
        wx.ready(function() {

            // 分享给好友
            wx.onMenuShareAppMessage({
                title: '我就是我不一样的烟火', // 分享标题
                desc: '享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致', // 分享描述
                link: '<?php echo $config['url']; ?>', // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
                imgUrl: 'http://8n2ah7.natappfree.cc/qrcode.jpg', // 分享图标
                type: 'link', // 分享类型,music、video或link,不填默认为link
                dataUrl: '', // 如果type是music或video,则要提供数据链接,默认为空
                success: function() {
                    // 用户点击了分享后执行的回调函数
                    alert('成功');
                }
            });

            // 自定义分享到朋友圈
            wx.onMenuShareTimeline({
                title: '这是标题', // 分享标题
                link: '<?php echo $config['url']; ?>',
                imgUrl: 'http://8n2ah7.natappfree.cc/qrcode.jpg', // 分享图标
                success: function() {
                    // 设置成功
                    alert('分享成功');
                }
            });

            //选择图片
            wx.chooseImage({
                count: 1, // 默认9
                sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有
                sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
                success: function(res) {
                    var localIds = res.localIds; // 返回选定照片的本地ID列表,localId可以作为img标签的src属性显示图片
                }
            });

        });
    </script>
</head>

<body>

</body>

</html>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值