PHP 微信公众号对接学习记录

1585364631
2023-02-09 / 0 评论 / 140 阅读 / 正在检测是否收录...

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

评论 (0)

取消