PHP开发微信公众平台
0.微信公众平台官方文档
https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Access_Overview.html
https://res.wx.qq.com/op_res/-serEQ6xSDVIjfoOHcX78T1JAYX-pM_fghzfiNYoD8uHVd3fOeC0PC_pvlg4-kmP
1.配置与微信服务器的通信
1.打开微信公众平台,获取并写入基本信息
index.php文件
<?php
// 微信公众平台基本信息
$token = 'xxxx';
$AppID = 'wx64xxxxxxxxxf014';
$AppSecret = 'd9bxxxxxxxxxxxxxxxxxxxc2';
?>
2.验证消息是否来自微信服务器
index.php文件
<?php
// 微信公众平台基本信息
$token = 'xxxx';
$AppID = 'wx64xxxxxxxxxf014';
$AppSecret = 'd9bxxxxxxxxxxxxxxxxxxxc2';
// 验证消息是否来自微信服务器
// 计算signature微信加密签名,并且与微信请求字段的signature进行值对比,从而证明消息来自微信服务器
if(!empty($_GET['echostr'])){
// 微信通信请求字段
$signature = $_GET["signature"];
$timestamp = $_GET["timestamp"];
$nonce = $_GET["nonce"];
$echostr = $_GET['echostr'];
// 将token,timestamp,nonce三个字段合为一个数组,并且按照字典排序
$arr = array($token, $timestamp, $nonce);
sort($arr,SORT_STRING);
// 将数组内容拼接为一个字符串
$str = implode($arr);
// 将拼接后的字符串内容进行sha1加密
$sign = sha1($str);
// 与微信服务器请求的signature字段内容进行对比,则证明是来自微信服务器的消息
if($sign == $signature){
//将echoStr字段的值返回给微信
echo $echostr;
}else{
// 内容不一样则退出
return false;
}
}
?>
3.配置微信公众平台
1.登入微信公众平台
2.点击基本配置
3.在“IP白名单” 点击查看,添加服务器IP地址
4.在“服务器配置” 点击修改配置
- URL:网页地址
- Token:与php文件中的token一样
- EncodingAESKey:随机生成一个
- 消息加解密方式:兼容模式
5.点击提交-确定
6.启用
2.获取access_token
- access_token有效期为两小时,所以1.5小时就重新刷新获取一次access_token
- access_token每天请求上线为2000次,每次请求都获取一次access_token,可以将当前access_token缓存在本地文件
1.获取access_token架构:
- 本地没有保存access_token的文件,获取access_token,并且保存在文件
本地有保存access_token点文件:
判断access_token是否过期:
- 过期了,重新获取access_token,保存替换文件
- 没有过期,直接使用
2.创建get_access_token.php文件
get_access_token.php文件
<?php
// 文件名
$file = "access_token.dao";
// access_token获取地址,修改appid和secret
$get_url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=wx6xxxxxxxxx014&secret=d9bxxxxxxxxxxxxxxxxxx76c2";
// access_token
$access_token = "";
function get_access_token(){
// 引用全局变量
global $file,$get_url,$access_token;
// 取网页源码
$html = file_get_contents($get_url);
// 取access_token的值
$access_token = json_decode($html)->access_token;
// 取当前时间戳
$timer = time();
// 打开access_token保存文件
$fp = fopen($file, "w+");
// 写入时间戳 access_token,以空格分割
fwrite($fp,($timer . " " . $access_token));
// 关闭文件
fclose($fp);
return false;
}
// 如果文件不存在,则执行获取access_token函数
if(!file_exists($file)){
get_access_token();
}
// 如果文件存在,则获取当前时间戳减去文本中的时间戳,判断access_token是否超时
$access_token_file = fopen($file,'r');
// 取出文本内容并且按照空格将字符串切割为数组
$text = explode(" ",fread($access_token_file,filesize($file)));
fclose($access_token_file);
// 取当前时间戳,减去文本中转为整数型的时间戳,如果大于5400(1.5小时),则重新获取一次access_token_file
if((time() - ((int)$text[0])) >= 5400){
get_access_token();
}
$access_token = $text[1];
return false;
?>
3.获取用户发送的消息
官方文档:
消息事件:
https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Receiving_standard_messages.html
推送事件:
https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Receiving_event_pushes.html
微信服务器会发送两种消息给开发者服务器
- get - 验证服务器的有效性
- post - 微信服务器会将用户发送的数据以post请求都方式发送到服务器,但是不能用post来接收消息
调试代码:
index.php文件
<?php
// 执行php文件得到可用access_token
include "get_access_token.php";
// 微信公众平台基本信息
$token = 'xxxx';
$AppID = 'wx64xxxxxxxxxf014';
$AppSecret = 'd9bxxxxxxxxxxxxxxxxxxxc2';
// 验证消息是否来自微信服务器
// 计算signature微信加密签名,并且与微信请求字段的signature进行值对比,从而证明消息来自微信服务器
if(!empty($_GET['echostr'])){
// 微信通信请求字段
$signature = $_GET["signature"];
$timestamp = $_GET["timestamp"];
$nonce = $_GET["nonce"];
$echostr = $_GET['echostr'];
// 将token,timestamp,nonce三个字段合为一个数组,并且按照字典排序
$arr = array($token, $timestamp, $nonce);
sort($arr,SORT_STRING);
// 将数组内容拼接为一个字符串
$str = implode($arr);
// 将拼接后的字符串内容进行sha1加密
$sign = sha1($str);
// 与微信服务器请求的signature字段内容进行对比,则证明是来自微信服务器的消息
if($sign == $signature){
//将echoStr字段的值返回给微信
echo $echostr;
}else{
// 内容不一样则退出
return false;
}
}
// 接收用户对公众号发送的信息
function get_info(){
// 接收xml数据 $GLOBALS['HTTP_RAW_POST_DATA'],如果用不了就使用file_get_contents('php://input')
// 或者找到php.ini配置文件,修改配置为always_populate_raw_post_data = On
// $xml = $GLOBALS['HTTP_RAW_POST_DATA'];
$xml = file_get_contents('php://input');
// 如果$xml有数据才执行
if(!empty($xml)){
// 临时存放字符串数据
$text = $xml;
// 防止xml注入,禁止xml实体解析
libxml_disable_entity_loader(true);
// 使用simpleXML解析该xml字符串
$xml = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
// 通过元素MsgType来判断该微信服务器转发的消息类型
switch ($xml->MsgType){
// 接收到事件消息
case 'event':
// 公众号订阅事件
if ($xml->Event=='subscribe'){
}
// 公众号取消订阅事件
if ($xml->Event=='unsubscribe'){
}
break;
// 接收到文本消息
case 'text':
// 调试是否正常接收文本
$fp = fopen("1.txt","w+");
fwrite($fp,$text);
fclose($fp);
break;
// 接收到图片消息
case 'image':
break;
//接收到语音消息
case 'voice':
break;
//接收到视频消息
case 'video':
break;
//接收到短视频消息
case 'shortvideo':
break;
//接收到位置消息
case 'location':
break;
//接收到链接消息
case 'link':
break;
}
}
}
get_info();
?>
给微信公众号发送一条消息,大概内容如下
1.txt
<xml>
<ToUserName><![CDATA[gh_5xxxxxxxxxxxxxxe7]]></ToUserName>
<FromUserName><![CDATA[oKMn3wXdxxxxxxxxxxxxxxxbrdx2-tqk]]></FromUserName>
<CreateTime>1649653429</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[111]]></Content>
<MsgId>2361xxxxxxxx36426</MsgId>
<Encrypt><![CDATA[Mlg9c4rQVY86dvfWgMMMgzVYfc9Sxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx3v6akekFxR3wuSr+tdUTx7vmGdNZipLwlfDkJASTHS3dp2Dmk=]]></Encrypt>
</xml>
精简代码:
index.php文件
<?php
// 执行php文件得到可用access_token
include "get_access_token.php";
// 微信公众平台基本信息
$token = 'xxxx';
$AppID = 'wx64xxxxxxxxxf014';
$AppSecret = 'd9bxxxxxxxxxxxxxxxxxxxc2';
// 验证消息是否来自微信服务器
// 计算signature微信加密签名,并且与微信请求字段的signature进行值对比,从而证明消息来自微信服务器
if(!empty($_GET['echostr'])){
// 微信通信请求字段
$signature = $_GET["signature"];
$timestamp = $_GET["timestamp"];
$nonce = $_GET["nonce"];
$echostr = $_GET['echostr'];
// 将token,timestamp,nonce三个字段合为一个数组,并且按照字典排序
$arr = array($token, $timestamp, $nonce);
sort($arr,SORT_STRING);
// 将数组内容拼接为一个字符串
$str = implode($arr);
// 将拼接后的字符串内容进行sha1加密
$sign = sha1($str);
// 与微信服务器请求的signature字段内容进行对比,则证明是来自微信服务器的消息
if($sign == $signature){
//将echoStr字段的值返回给微信
echo $echostr;
}else{
// 内容不一样则退出
return false;
}
}
// 接收用户对公众号发送的信息
function get_info(){
// 接收xml数据 $GLOBALS['HTTP_RAW_POST_DATA'],如果用不了就使用file_get_contents('php://input')
// 或者找到php.ini配置文件,修改配置为always_populate_raw_post_data = On
// $xml = $GLOBALS['HTTP_RAW_POST_DATA'];
$xml = file_get_contents('php://input');
// 如果$xml有数据才执行
if(!empty($xml)){
// 防止xml注入,禁止xml实体解析
libxml_disable_entity_loader(true);
// 使用simpleXML解析该xml字符串
$xml = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
// 通过元素MsgType来判断该微信服务器转发的消息类型
switch ($xml->MsgType){
// 接收到事件消息
case 'event':
// 公众号订阅事件
if ($xml->Event=='subscribe'){
}
// 公众号取消订阅事件
if ($xml->Event=='unsubscribe'){
}
break;
// 接收到文本消息
case 'text':
break;
// 接收到图片消息
case 'image':
break;
//接收到语音消息
case 'voice':
break;
//接收到视频消息
case 'video':
break;
//接收到短视频消息
case 'shortvideo':
break;
//接收到位置消息
case 'location':
break;
//接收到链接消息
case 'link':
break;
}
}
}
get_info();
?>
4.根据用户发送的消息进行回复
官方文档:
https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Passive_user_reply_message.html
定义一个全局发消息模板
index.php
// 全局变量定义消息发送模板
$send_info_array = array(
// %s 代表变量,之后可以使用spritf传值
// 文本消息的发送模板
"text" => "<xml><ToUserName><![CDATA[%s]]></ToUserName><FromUserName><![CDATA[%s]]></FromUserName><CreateTime>%s</CreateTime><MsgType><![CDATA[text]]></MsgType><Content><![CDATA[%s]]></Content></xml>"
);
定义一个发送文本消息的函数,形参$xml接受$xml内容
index.php
// 定义用户关注公众号函数
function user_subscribe($xml){
// 引用全局变量模板
global $send_info_array;
$cont = "此乃缘,妙,不可言";
$res = sprintf($send_info_array['text'],$xml->FromUserName,$xml->ToUserName,time(),$cont);
die($res);
}
// 定义用户取消关注公众号函数
function user_unsubscribe($xml){
// 引用全局变量模板
global $send_info_array;
$cont = "天下分久必合,合久必分,无不散之筵席,有缘再相见";
$res = sprintf($send_info_array['text'],$xml->FromUserName,$xml->ToUserName,time(),$cont);
die($res);
}
// 定义一个发送文本消息的函数,形参$xml接受$xml内容
function send_text_info($xml){
// 引用全局变量模板
global $send_info_array;
$cont = $xml->Content;
$res = sprintf($send_info_array['text'],$xml->FromUserName,$xml->ToUserName,time(),$cont);
die($res);
}
在事件处添加函数
index.php
// 接收到事件消息
case 'event':
// 公众号订阅事件
if ($xml->Event=='subscribe'){
user_subscribe($xml);
}
// 公众号取消订阅事件
if ($xml->Event=='unsubscribe'){
user_unsubscribe($xml);
}
break;
// 接收到文本消息
case 'text':
// 判断为文本消息后,跳转函数
send_text_info($xml);
break;
完整代码
index.php
<?php
// 执行php文件得到可用access_token
include "get_access_token.php";
// 微信公众平台基本信息
$token = 'xxxx';
$AppID = 'wx64xxxxxxxxxf014';
$AppSecret = 'd9bxxxxxxxxxxxxxxxxxxxc2';
// 验证消息是否来自微信服务器
// 计算signature微信加密签名,并且与微信请求字段的signature进行值对比,从而证明消息来自微信服务器
if(!empty($_GET['echostr'])){
// 微信通信请求字段
$signature = $_GET["signature"];
$timestamp = $_GET["timestamp"];
$nonce = $_GET["nonce"];
$echostr = $_GET['echostr'];
// 将token,timestamp,nonce三个字段合为一个数组,并且按照字典排序
$arr = array($token, $timestamp, $nonce);
sort($arr,SORT_STRING);
// 将数组内容拼接为一个字符串
$str = implode($arr);
// 将拼接后的字符串内容进行sha1加密
$sign = sha1($str);
// 与微信服务器请求的signature字段内容进行对比,则证明是来自微信服务器的消息
if($sign == $signature){
//将echoStr字段的值返回给微信
echo $echostr;
}else{
// 内容不一样则退出
return false;
}
}
// 全局变量定义消息发送模板
$send_info_array = array(
// %s 代表变量,之后可以使用spritf传值
// 文本消息的发送模板
"text" => "<xml><ToUserName><![CDATA[%s]]></ToUserName><FromUserName><![CDATA[%s]]></FromUserName><CreateTime>%s</CreateTime><MsgType><![CDATA[text]]></MsgType><Content><![CDATA[%s]]></Content></xml>"
);
// 定义用户关注公众号函数
function user_subscribe($xml){
// 引用全局变量模板
global $send_info_array;
$cont = "此乃缘,妙,不可言";
$res = sprintf($send_info_array['text'],$xml->FromUserName,$xml->ToUserName,time(),$cont);
die($res);
}
// 定义用户取消关注公众号函数
function user_unsubscribe($xml){
// 引用全局变量模板
global $send_info_array;
$cont = "天下分久必合,合久必分,无不散之筵席,有缘再相见";
$res = sprintf($send_info_array['text'],$xml->FromUserName,$xml->ToUserName,time(),$cont);
die($res);
}
// 定义一个发送文本消息的函数,形参$xml接受$xml内容
function send_text_info($xml){
// 引用全局变量模板
global $send_info_array;
$cont = $xml->Content;
$res = sprintf($send_info_array['text'],$xml->FromUserName,$xml->ToUserName,time(),$cont);
die($res);
}
// 接收用户对公众号发送的信息
function get_info(){
// 接收xml数据 $GLOBALS['HTTP_RAW_POST_DATA'],如果用不了就使用file_get_contents('php://input')
// 或者找到php.ini配置文件,修改配置为always_populate_raw_post_data = On
// $xml = $GLOBALS['HTTP_RAW_POST_DATA'];
$xml = file_get_contents('php://input');
// 如果$xml有数据才执行
if(!empty($xml)){
// 防止xml注入,禁止xml实体解析
libxml_disable_entity_loader(true);
// 使用simpleXML解析该xml字符串
$xml = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
// 通过元素MsgType来判断该微信服务器转发的消息类型
switch ($xml->MsgType){
// 接收到事件消息
case 'event':
// 公众号订阅事件
if ($xml->Event=='subscribe'){
user_subscribe($xml);
}
// 公众号取消订阅事件
if ($xml->Event=='unsubscribe'){
user_unsubscribe($xml);
}
break;
// 接收到文本消息
case 'text':
// 判断为文本消息后,跳转函数
send_text_info($xml);
break;
// 接收到图片消息
case 'image':
break;
//接收到语音消息
case 'voice':
break;
//接收到视频消息
case 'video':
break;
//接收到短视频消息
case 'shortvideo':
break;
//接收到位置消息
case 'location':
break;
//接收到链接消息
case 'link':
break;
}
}
}
get_info();
?>
在公众号回复内容进行验证,如需其他功能自行看官方文档扩展
5.回复带有超链接的文本
使用HTML5代码格式
"超链接文本"
$url = "https://www.baidu.com";
$res = sprintf($send_info_array['text'],$xml->FromUserName,$xml->ToUserName,time(),"<a href=\"$url\">超链接文本</a>");
die($res);
评论 (0)