推送事件和消息回复

实例化

use zxf\WeChat\OfficialAccount\Receive;


$receive-> = new Receive();
OR
$receive = new Receive('选择不同的微信配置 例如:"mini_program"');

api

try {
    // 获取当前推送接口类型 ( text,image,loction,event... )
    $msgType = $receive->getMsgType();
    
    // 获取当前推送来源用户的openid
    $openid = $receive->getOpenid();
    
    // 获取当前推送的所有数据
    $data = $receive->getReceive();
    var_export($data);
    
    // 回复文本消息
    $receive->text($content)->reply();
    
    // 回复图文消息(高级图文或普通图文,数组)
    $receive->news($news)->reply();
    
    // 回复图片消息(需先上传到微信服务器生成 media_id)
    $receive->image($media_id)->reply();
    
    // 回复语音消息(需先上传到微信服务器生成 media_id)
    $receive->voice($media_id)->reply();
    
    // 回复视频消息(需先上传到微信服务器生成 media_id)
    $receive->video($media_id,$title,$desc)->reply();
    
    // 回复音乐消息
    $receive->music($title,$desc,$musicUrl,$hgMusicUrl,$thumbe)->reply();
    
    // 将消息转发给多客服务
    $receive->transferCustomerService($account)->reply();
    
} catch (\Exception $e) {
    // 处理异常
    echo $e->getMessage();
}

实操

<?php

use zxf\WeChat\OfficialAccount\Qrcode;
use zxf\WeChat\OfficialAccount\Receive;
use zxf\WeChat\OfficialAccount\Template;
use zxf\WeChat\OfficialAccount\User;

/**
 * 微信服务端接口回调
 */
class Notify extends CallbackController
{
    private ?array   $user    = []; // 微信公众号配置
    private ?Receive $receive; // 处理消息的对象Obj
    private array    $pushAll = []; // 微信推送过来的所有数据
    private string   $openid  = ''; // 用户openid

    private string $configKey = 'wechat_sandbox'; // 微信配置的key

    public function __construct()
    {
        if (php_sapi_name() !== 'cli') {
            // 非命令行中运行
            $this->receive = new Receive($this->configKey);
        }
    }

    /**
     * 微信服务端回调入口
     *
     * @return string|void|null
     */
    public function index(Request $request)
    {
        // Test::write('微信服务回调数据header', $request->header());
        // Test::write('微信服务回调数据body', $request->all());

        // 获取当前推送的所有数据 ,并把所有键名改为小写
        // $this->pushAll = array_change_key_case($this->receive->getReceive(), CASE_LOWER);
        $this->pushAll = $this->receive->getReceive();

        // 获取当前推送接口类型 ( text,image,loction,event... )
        $msgType = $this->receive->getMsgType();

        // 获取当前推送来源用户的openid
        $this->openid = $this->receive->getOpenid();

        $this->getUserInfo();

        switch ($msgType) {
            case 'text':
                return $this->textHandle();
            case 'image':
                return $this->imageHandle();
            case 'voice':
                return $this->voiceHandle();
            case 'video':
                return $this->videoHandle();
            case 'shortvideo':
                return $this->shortVideoHandle();
            case 'link':
                return $this->linkHandle();
            case 'location':
                return $this->locationHandle();
            case 'event':
                return $this->eventHandle();
            default:
                echo "未定义";
        }

    }

    // 获取用户信息
    public function getUserInfo()
    {
        if (empty($this->openid)) {
            return false;
        }
        $this->user = User::instance($this->configKey)->getUserInfo($this->openid);
    }

    // 事件处理
    public function eventHandle()
    {
        switch ($this->pushAll['Event']) {
            case 'subscribe':
                return $this->subscribeHandle();
            case 'unsubscribe':
                return $this->unsubscribeHandle();
            case 'SCAN':
                return $this->scanHandle();
            case 'LOCATION':
                return $this->locationHandle();
            case 'CLICK':
                return $this->clickHandle();
            case 'VIEW':
                return $this->viewHandle();
            case 'MASSSENDJOBFINISH': // 群发消息结束通知
                return $this->massMsgHandle();
            default:
                echo "未定义";
        }
    }

    public function unsubscribeHandle()
    {
        // 取消订阅
        return true;
    }

    // 订阅事件
    public function subscribeHandle()
    {
        // 扫描带参数二维码 关注订阅 事件
        if (!empty($this->pushAll['EventKey']) && (substr($this->pushAll['EventKey'], 0, 8) == 'qrscene_')) {
            // 扫描带参数二维码事件 用户未关注时,进行关注后的事件推送
            $scene_id = substr($this->pushAll['EventKey'], 8);//  二维码scene_id
            // $this->pushAll['Ticket'] 二维码的ticket,可用来换取二维码图片

            // 回复文本消息
            return $this->receive->text('扫码关注:' . $scene_id)->reply();
        } else {
            // 普通关注
            // 回复图文消息(高级图文或普通图文,数组)
            return $this->receive->news([
                [
                    'Title'       => '感谢关注',
                    'Description' => 'Description',
                    'PicUrl'      => 'https://weisifang.com/static/inspinia/img/logo.png',
                    'Url'         => 'https://weisifang.com',
                ],
            ])->reply();

        }
    }

    // 扫码事件
    public function scanHandle()
    {
        // 已经关注 扫描带参数二维码事件
        if (!empty($this->pushAll['EventKey'])) {
            // 扫描带参数二维码事件 用户已关注时的事件推送
            // $this->pushAll['EventKey'] 二维码scene_id
            // $this->pushAll['Ticket'] 二维码的ticket,可用来换取二维码图片

            // 回复文本消息
            return $this->receive->text('已经关注用户扫码:' . $this->pushAll['EventKey'])->reply();
        }
        return false;
    }

    public function locationHandle()
    {
        if (!empty($this->pushAll['Latitude'])) {
            // 上报地理位置事件 用户同意上报地理位置后,每次进入公众号会话时,都会在进入时上报地理位置,或在进入会话后每5秒上报一次地理位置
            // $this->pushAll['Latitude']; // 地理位置纬度
            // $this->pushAll['Longitude']; // 地理位置经度
            // $this->pushAll['Precision']; // 地理位置精度

            // 回复文本消息
            return $this->receive->text('上报位置: -经度:' . $this->pushAll['Longitude'] . ' -维度:' . $this->pushAll['Latitude'] . ' -精度:' . $this->pushAll['Precision'])->reply();
        } else {
            // 普通地理位置消息
            // $this->pushAll['Location_X']; // 地理位置纬度
            // $this->pushAll['Location_Y']; // 地理位置经度
            // $this->pushAll['Scale']; // 地图缩放大小
            // $this->pushAll['Label']; // 地理位置信息
            // $this->pushAll['MsgId']; // 消息id,64位整型
            // $this->pushAll['MsgDataId']; // 消息的数据ID(消息如果来自文章时才有)
            // $this->pushAll['Idx']; // 多图文时第几篇文章,从1开始(消息如果来自文章时才有)

            // 回复文本消息
            return $this->receive->text('发送位置: -经度:' . $this->pushAll['Location_Y'] . ' -维度:' . $this->pushAll['Location_X'] . ' -缩放大小:' . $this->pushAll['Scale'] . ' -位置信息:' . $this->pushAll['Label'])->reply();
        }
    }

    // 自定义菜单事件
    public function clickHandle()
    {
        // 自定义菜单事件 点击菜单拉取消息时的事件推送
        // $this->pushAll['EventKey']; // 事件 KEY 值,与自定义菜单接口中 KEY 值对应

        return $this->receive->text('点击菜单:' . $this->pushAll['EventKey'])->reply();

    }

    //自定义菜单事件 点击菜单跳转链接时的事件推送
    public function viewHandle()
    {
        // $this->pushAll['EventKey']; // 跳转地址 www.a.com
        return $this->receive->text('点击菜单跳转:' . $this->pushAll['EventKey'])->reply();
    }

    public function imageHandle()
    {
        // $this->pushAll['PicUrl']; // 图片链接(由系统生成)
        // $this->pushAll['MediaId']; // 图片消息媒体id,可以调用获取临时素材接口拉取数据。
        // $this->pushAll['MsgId']; // 消息id,64位整型
        // $this->pushAll['MsgDataId']; // 消息的数据ID(消息如果来自文章时才有)
        // $this->pushAll['Idx']; // 多图文时第几篇文章,从1开始(消息如果来自文章时才有)

        // 回复图片消息(需先上传到微信服务器生成 media_id)
        $this->receive->image($this->pushAll['MediaId'])->reply();
        return $this->receive->text('图片地址:' . $this->pushAll['PicUrl'])->reply();
    }

    // 语音消息
    public function voiceHandle()
    {
        // $this->pushAll['MediaId']; // 语音消息媒体id,可以调用获取临时素材接口拉取数据。
        // $this->pushAll['Format']; // 语音格式,如amr,speex等
        // $this->pushAll['MsgId']; // 消息id,64位整型
        // $this->pushAll['MsgDataId']; // 消息的数据ID(消息如果来自文章时才有)
        // $this->pushAll['Idx']; // 多图文时第几篇文章,从1开始(消息如果来自文章时才有)
        // $this->pushAll['Recognition']; // 语音识别结果,UTF8编码 请注意,「开通语音识别后」,用户每次发送语音给公众号时,微信会在推送的语音消息 XML 数据包中,增加一个 Recognition 字段(注:由于客户端缓存,开发者开启或者关闭语音识别功能,对新关注者立刻生效,对已关注用户需要24小时生效。开发者可以重新关注此帐号进行测试)

        // 回复语音消息(需先上传到微信服务器生成 media_id)
        return $this->receive->voice($this->pushAll['MediaId'])->reply();
    }

    // 视频消息
    public function videoHandle()
    {
        // $this->pushAll['ThumbMediaId']; // 视频消息缩略图的媒体id,可以调用多媒体文件下载接口拉取数据。
        // $this->pushAll['MediaId']; // 视频消息媒体id,可以调用获取临时素材接口拉取数据。
        // $this->pushAll['MsgId']; // 消息id,64位整型
        // $this->pushAll['MsgDataId']; // 消息的数据ID(消息如果来自文章时才有)
        // $this->pushAll['Idx']; // 多图文时第几篇文章,从1开始(消息如果来自文章时才有)

        // 回复视频消息(需先上传到微信服务器生成 media_id)
        return $this->receive->video($this->pushAll['MediaId'], '视频标题', '视频描述')->reply();
    }

    // 小视频
    public function shortVideoHandle()
    {
        //  $this->pushAll['ThumbMediaId']; // 视频消息缩略图的媒体id,可以调用多媒体文件下载接口拉取数据。
        //  $this->pushAll['MediaId']; // 视频消息媒体id,可以调用获取临时素材接口拉取数据。
        //  $this->pushAll['MsgId']; // 消息id,64位整型
        //  $this->pushAll['MsgDataId']; // 消息的数据ID(消息如果来自文章时才有)
        //  $this->pushAll['Idx']; // 多图文时第几篇文章,从1开始(消息如果来自文章时才有)

        // 回复视频消息(需先上传到微信服务器生成 media_id)
        return $this->receive->video($this->pushAll['MediaId'], '小视频标题', '小视频描述')->reply();
    }

    public function linkHandle()
    {
        //  $this->pushAll['Title']; // 标题
        //  $this->pushAll['Description']; // 描述
        //  $this->pushAll['Url']; // url
        //  $this->pushAll['MsgId']; // 消息id,64位整型
        //  $this->pushAll['MsgDataId']; // 消息的数据ID(消息如果来自文章时才有)
        //  $this->pushAll['Idx']; // 多图文时第几篇文章,从1开始(消息如果来自文章时才有)

        return true;
    }

    // 群发消息结束后微信通知
    public function massMsgHandle()
    {
        // 群发的结果,为“send success”或“send fail”或“err(num)”。但send success时,也有可能因用户拒收公众号的消息、系统错误等原因造成少量用户接收失败。err(num)是审核失败的具体原因,可能的情况如下:err(10001):涉嫌广告, err(20001):涉嫌政治, err(20004):涉嫌社会, err(20002):涉嫌色情, err(20006):涉嫌违法犯罪, err(20008):涉嫌欺诈, err(20013):涉嫌版权, err(22000):涉嫌互推(互相宣传), err(21000):涉嫌其他, err(30001):原创校验出现系统错误且用户选择了被判为转载就不群发, err(30002): 原创校验被判定为不能群发, err(30003): 原创校验被判定为转载文且用户选择了被判为转载就不群发, err(40001):管理员拒绝, err(40002):管理员30分钟内无响应,超时
        //$this->pushAll['Status']; // 群发的结果
        //$this->pushAll['TotalCount']; // tag_id下粉丝数;或者openid_list中的粉丝数
        //$this->pushAll['FilterCount']; // 过滤(过滤是指特定地区、性别的过滤、用户设置拒收的过滤,用户接收已超4条的过滤)后,准备发送的粉丝数,原则上,FilterCount 约等于 SentCount + ErrorCount
        //$this->pushAll['SentCount']; // 发送成功的粉丝数
        //$this->pushAll['ErrorCount']; // 发送失败的粉丝数
        //$this->pushAll['ArticleUrl']; // 群发文章的url
        // ... 还有其他参数

        return true;
    }

    // 文本消息处理
    public function textHandle()
    {
        // $this->pushAll['Content']; // 消息内容
        // $this->pushAll['MsgId']; // 消息id,64位整型
        // $this->pushAll['MsgDataId']; // 消息的数据ID(消息如果来自文章时才有)
        // $this->pushAll['Idx']; // 多图文时第几篇文章,从1开始(消息如果来自文章时才有)

        $qrcode = Qrcode::instance($this->configKey);
        if (in_array($this->pushAll['Content'], ['qr', 'qrcode', '二维码', '登录码', '登录二维码', '登录'])) {
            // 有效期一周
            // $res = $qrcode->create('login', 604800);
            // 有效期永久
            $res = $qrcode->create('long_login');

            if (!empty($res['ticket'])) {
                return $this->receive->text('永久登录码:' . $qrcode->url($res['ticket']))->reply();
            } else {
                return $this->receive->text('一周登录码:' . $res['ticket'] . ' -url:' . $res['url'])->reply();
            }
        }

        if (in_array($this->pushAll['Content'], ['模板', '模板消息', 'template', '威四方', 'wsf'])) {
            // 发送模板消息
            try {
                // 实例接口
                $wechat = new Template($this->configKey);
                // 执行操作
                $wechat->send([
                    "touser"      => $this->openid,
                    "template_id" => "abCo26-Q19y4-x02_ENJpJeF5tunXPps4EcXGzVHAzI",
                    "url"         => "https://weisifang.com",
                    "data"        => [
                        "content" => [
                            "value" => "威四方",
                        ],
                    ],
                ]);
            } catch (\Exception $e) {
                // 异常处理
                write_error($e);
                return $this->receive->text('换个词试试~')->reply();
            }
            die;
        }
        return $this->receive->text('小威正在学习中,还未收录「' . $this->pushAll['Content'] . '」')->reply();
    }
}