thinkphp6使用easywechat笔记!

公众号端基本配置

image.png

公众号端设置

image.png

域名要备案,文件下载上传至tp6的public目录下

image.png

composer require overtrue/wechat -vvv

微信相关路由配置

 

    //微信
    Route::group('wechat', function () use($version){
        Route::get('',"{$version}.Wechat/index");//微信首页
        Route::any('me',"{$version}.Wechat/me");//微信首页
        Route::any('oauth_callback',"{$version}.Wechat/oauth_callback");//微信首页
        Route::get('test',"{$version}.Wechat/test");//微信首页
        Route::get('menu',"{$version}.Wechat/menuList");//微信菜单列表
        Route::post('menu',"{$version}.Wechat/menuAdd");//微信菜单添加
        Route::get('resource',"{$version}.Wechat/resource");//资源

    });

config/wechat.php配置文件

 

<?php

return [
    /**
     * 账号基本信息,请从微信公众平台/开放平台获取
     */
    'app_id' => env('WECHAT_OFFICIAL_ACCOUNT_APPID', ''),         // AppID
    'secret' => env('WECHAT_OFFICIAL_ACCOUNT_SECRET', ''),    // AppSecret
    'token' => env('WECHAT_OFFICIAL_ACCOUNT_TOKEN', ''),           // Token
    'aes_key' => env('WECHAT_OFFICIAL_ACCOUNT_AES_KEY', '
'),                 // EncodingAESKey

    /**
     * 指定 API 调用返回结果的类型:array(default)/collection/object/raw/自定义类名
     * 使用自定义类名时,构造函数将会接收一个 `EasyWeChat\Kernel\Http\Response` 实例
     */
    'response_type' => 'array',

    /**
     * 日志配置
     *
     * level: 日志级别, 可选为:
     *         debug/info/notice/warning/error/critical/alert/emergency
     * path:日志文件位置(绝对路径!!!),要求可写权限
     */
    'log' => [
        'default' => 'dev', // 默认使用的 channel,生产环境可以改为下面的 prod
        'channels' => [
            // 测试环境
            'dev' => [
                'driver' => 'single',
                'path' => ROOT_PATH.'logs/'.date('Y-m-d').'/easywechat.log',
                'level' => 'debug',
            ],
            // 生产环境
            'prod' => [
                'driver' => 'daily',
                'path' =>  ROOT_PATH.'logs/'.date('Y-m-d').'/easywechat.log',
                'level' => 'info',
            ],
        ],
    ],

    /**
     * 接口请求相关配置,超时时间等,具体可用参数请参考:
     * http://docs.guzzlephp.org/en/stable/request-config.html
     *
     * - retries: 重试次数,默认 1,指定当 http 请求失败时重试的次数。
     * - retry_delay: 重试延迟间隔(单位:ms),默认 500
     * - log_template: 指定 HTTP 日志模板,请参考:https://github.com/guzzle/guzzle/blob/master/src/MessageFormatter.php
     */
    'http' => [
        'max_retries' => 1,
        'retry_delay' => 500,
        'timeout' => 5.0,
        // 'base_uri' => 'https://api.weixin.qq.com/', // 如果你在国外想要覆盖默认的 url 的时候才使用,根据不同的模块配置不同的 uri
    ],

    /**
     * OAuth 配置
     *
     * scopes:公众平台(snsapi_userinfo / snsapi_base),开放平台:snsapi_login
     * callback:OAuth授权完成后的回调页地址
     */
    'oauth' => [
        'scopes'   => ['snsapi_userinfo'],
        'callback' => '/api/wechat/oauth_callback',
    ],
];

 

<?php
// +----------------------------------------------------------------------
// | 微信逻辑【业务层】
// +----------------------------------------------------------------------
// | Author: DragonersLi<865196792@qq.com>
// +----------------------------------------------------------------------
// | Date:  2020/07/23
// +----------------------------------------------------------------------

namespace app\common\logic;
use EasyWeChat\OpenPlatform\Server\Guard;
use EasyWeChat\Factory;
use EasyWeChat\Kernel\Messages\Text;
use EasyWeChat\Kernel\Messages\Image;
use EasyWeChat\Kernel\Messages\Video;
use EasyWeChat\Kernel\Messages\Voice;
use EasyWeChat\Kernel\Messages\News;
use EasyWeChat\Kernel\Messages\NewsItem;
use EasyWeChat\Kernel\Messages\Article;
use app\common\service\RedisService;
use app\common\model\UserWeixin;
use app\common\model\Keyword;
use app\common\model\Notice;
use think\facade\Log;
class WechatLogic extends BaseLogic
{

    public function initialize()
    {
        parent::initialize();
    }

    public function __construct()
    {
        $this->app = Factory::officialAccount(config('wechat'));
    }

    /**
     * 微信首页
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public  function index(){

        try{
            $this->app->server->push(function ($message){
                $user_openid = $message['FromUserName'];

                switch ($message['MsgType']) {
                    case 'event':
                        $message['user'] = $this->app->user->get($user_openid);
                        return  $result = $this->event($message);//处理点击事件
                        break;
                    case 'text':
                        return $this->text($message['Content']);//处理被动回复文本
                        break;
                    case 'image':
                        return $image = new Image($mediaId = '0b69zmxmX9VQ1WOyimslclMr3f2YbnNgrMkjS2KxWZM');
                        break;
                    case 'voice':
                        return $voice = new Voice($mediaId = 'Rwqz1xLYDNwFvTJ254fBstYU1rY3aKiN-z7aqEpiWic');
                        break;
                    case 'video':
                        return $video = new Video($mediaId = 'Rwqz1xLYDNwFvTJ254fBsmzRm-HXa-ilLRc028v-Ar0', [
                            'title' => $title = '标题',
                            'description' => '简介...',
                        ]);
                        break;
                    case 'location'://收到坐标消息,微信目前不支持回复坐标消息
                        return  $text = new Text("您好!openid:{$message['FromUserName']},{$message['MsgType']},收到坐标消息,微信目前不支持回复坐标消息");
                        break;
                    case 'link'://收到链接消息,微信目前不支持回复链接消息
                        return  $text = new Text("您好!openid:{$message['FromUserName']},{$message['MsgType']},收到链接消息,微信目前不支持回复链接消息");
                        break;
                    case 'file':
                        return  $text = new Text("您好!openid:{$message['FromUserName']},{$message['MsgType']},收到文件消息");
                    // ... 其它消息
                    default:
                        return '收到其它消息';
                        break;
                }
            });
        }catch(\Exception $e){
            dlog('wechat',$e->getMessage());
        }

        $response = $this->app->server->serve()->send();

    }

    /*
     * 菜单列表
     */
    public  function menuList()
    {
        $list = $this->app->menu->list();//读取(查询)已设置菜单
        $current = $this->app->menu->current();//获取当前菜单
        return [
            'list'=>$list,
            'current'=>$current
        ];
    }

    /*
     * 菜单创建
     */
    public  function menuAdd(){
        $buttons = [
            [
                "type" => "view",
                "name" => "下载APP",
                "url"  => config('system.api.url')."/download.html"
            ],
            [
                "type" => "view",
                "name" => "个人中心",
                "url"  => config('system.api.url')."/h5"
            ]
        ];
        return $this->app->menu->create($buttons);
    }


    /*
     * $type 素材的类型,图片(image)、视频(video)、语音 (voice)、图文(news)
     * $offset 从全部素材的该偏移位置开始返回,可选,默认 0,0 表示从第一个素材 返回
     * $count 返回素材的数量,可选,默认 20, 取值在 1 到 20 之间
     */
    public  function resource($type = 'image'){
        $user = $this->app->user->list($nextOpenId = null);  // $nextOpenId 可选

        $stats = $this->app->material->stats();//获取各类素材总数
        //$item = $this->app->material->get($mediaId='');//获取单个素材
        $resource = $this->app->material->list($type, $offset= 0, $count= 20);
        // $this->app->material->delete($mediaId='');//删除素材
        return [
            'count'=>$stats,
            'list'=>$resource,
            'user'=>$user
        ];
    }

    /**
     * 授权页面
     * @return mixed
     */
    public function me(){
        if (!cookie('wechat_user')) {// 未登录
            cookie('target_url',config('system.api.url').'/api/wechat/me');
            return $this->app->oauth->redirect()->send();
        }

        $url = config('system.api.url').'/h5';
        header('location:'. $url);
    }

    /**
     * 回调页面
     */
    public function oauth_callback(){
        $user =  $this->app->oauth->user();  // 获取 OAuth 授权结果用户信息
        cookie('wechat_user',json_encode($user));
        dlog('wechat_user',$user);
        RedisService::redis()->set('weixin_user:'.$user->id,json_encode([
            'openid'=>$user->id,
            'nickname'=>$user->nickname,
            'avatar'=>$user->avatar
        ]));
        $url = cookie('target_url') ? cookie('target_url') : config('system.api.url').'/h5';
        header('location:'. $url);
    }

    /**
     * 回复事件
     * @param array $message
     * @return Image|string
     */
    private function event($message = []){
        $user_openid =  $message['user']['openid'];
        switch ($message['Event']) {
            case "subscribe"://关注微信用户表新增记录
                return  '欢迎关注派金花公众号,有疑问请联系在线客服!' ;
                break;
            case "unsubscribe"://取消关注时执行的操作,要把记录该用户从记录微信用户信息的表中删掉
                $msg = "{$user_openid}:取消关注!清除微信信息:";
                $msg.= UserWeixin::destroy(function($query) use($user_openid){
                    $query->where(['wxOpenid'=>$user_openid]);
                }) ? 'success' : 'failed';
                dlog('wechat',$msg);//取消关注时执行的操作,要把记录该用户从记录微信用户信息的表中删掉
                break;

            case "CLICK":
                switch ($message['EventKey']) {
                    case "V1000":

                        break;

                    case "V1001":
                    default:
                        return $image = new Image($mediaId = 'Rwqz1xLYDNwFvTJ254fBspGO-4KAaoUILJIKRzwUBrE');
                        break;
                }
                break;

            case "SCAN":
            case "LOCATION":
            case "VIEW":
            default:
                break;
        }
    }

    /**
     * 回复文本
     * @param string $content
     * @return Image|News|Text|Video|Voice
     */
    private  function text($content = ''){
        $result = config('wechatreply.keywords');
        if(empty($result[$content])){ //关键词匹配失败
            $other = config('wechatreply.other');
            if(empty($other[$content])){//其它关键词也匹配失败,则返回关键词列表

                $content = "输入序号快捷获取回复!\n";
                foreach($result as $k=>$v){
                    $content .= "【{$k}】{$v['title']}\n";
                }
                return  $text = new Text($content);
            }else{ //匹配其它关键词
                $result = $other;
            }
        }


        switch ($result[$content]['type']){

            case 'image'://图片
                return $image = new Image($result[$content]['content']);
                break;
            case 'video'://视频
                return $video = new Video($mediaId = $result[$content]['content'], [
                    'title' => $result[$content]['title'],
                    'description' => '视频描述...',
                    // 'thumb_media_id'=>'Rwqz1xLYDNwFvTJ254fBsiuqJw5ZV9dZF2jNu34_bPU' // 封面资源 ID
                ]);
                break;
            case 'voice'://声音
                return $voice = new Voice($mediaId = $result[$content]['content']);
                break;

            case 'news'://资讯
                $data = Notice::where(['id'=>$result[$content]['content']])->field('id,title,content')->find();
                return $news = new News([
                    new NewsItem([
                        'title'       => $result[$content]['title'],
                        'description' =>$result[$content]['content'],
                        'url'         =>$result[$content]['id'],
                        //'image'       => 'https://www.easywechat.com/img/logo-black.svg',
                        // ...
                    ]),
                ]);
                break;

            case 'text'://文本
            default:
                $result[$content]['content'] = htmlspecialchars_decode($result[$content]['content']);
                $result[$content]['content'] = str_replace('<p>','',$result[$content]['content']);
                $result[$content]['content'] = str_replace('</p>',"\r",$result[$content]['content']);
                $result[$content]['content'] = str_replace('<br/>',"\r",$result[$content]['content']);
                return  $text = new Text($result[$content]['content']);
                break;
        }
    }

    /**
     * 发送模板消息[静态方法方便调用]
     * @param array $data
     * @return mixed
     */
    public static function tpl($data = []){
//        $data['openid'] = 'o9soys5-em4VBQD78uy4_dyZx_Pg';
//        $data['type'] = 'test';
//        $data['url'] = config('system.api.url').'/h5';
//        $data['data'] =[
//            'first'=>'hello,world',
//            'keyword1' => '220.30元',
//            'keyword2' => '荣事达旗舰店',
//            'keyword3' => '2014年7月21日 18:36',
//        ];
//        $this->tpl($data);
        $result = Factory::officialAccount(config('wechat'))->template_message->send([
                'touser'=>$data['openid'],
                'template_id'=>config("system.wechat_tpl.{$data['type']}"),
                'url' => $data['url'],
                'data' => $data['data'],
            ]);
        if(!$result['errcode']){//发送成功
            return ['code'=>1,'msg'=>$result['errmsg'],'data'=>['msgid'=>$result['msgid']]];
        }else{//发送失败记录日志
            dlog('wechat_tpl',['data'=>$data,'result'=>$result]);
            return ['code'=>0,'msg'=>$result['errmsg'],'data'=>['result'=>$result]];
        }
    }

}

开通模版消息,配置模版ID

 

    //微信模板ID
    'wechat_tpl'=>[
        'test'=>'tGy9UXpXz97cv7SygOnVR6S-kqOZtnEDblTnN5QwkJs',//测试
        'register'=>'pxIIRpFWFZu-02103RmVIxCmqS-LdyDJIpPcNbwVupo',//注册模板ID
    ],

官网文档:https://www.easywechat.com/docs/master/overview

完全按官网demo接入,菜单资源等接口都能正常运作,自动回复却提示:该公众号暂时无法提供服务,请稍后再试
tail -f tp6.xxx.com.log查看日志,看到是post请求,返回错误404 Not Found

排查结果:路由请求方式由get改成any解决!

 

223.166.222.120 - - [22/Aug/2020:14:12:37 +0800] "POST /api/wechat?signature=acd16cbad48ae6bad1df96b27e302d979eb454cd&timestamp=1598076757&nonce=1560311832&openid=o9soys5-em4VBQD78uy4_dyZx_Pg&encrypt_type=aes&msg_signature=26a0a9c431a2a56fca7e5e0db794e4a98e7b4617 HTTP/1.1" 404 21487 "-" "Mozilla/4.0"

laraval下请求方式错误返回405 Method Not Allowed
"The POST method is not supported for this route. Supported methods: GET, HEAD."



作者:DragonersLi
链接:https://www.jianshu.com/p/8d14f20f4aed
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值