美文网首页
thinkphp6使用easywechat笔记!

thinkphp6使用easywechat笔记!

作者: DragonersLi | 来源:发表于2020-08-22 14:19 被阅读0次
    公众号端基本配置
    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."

    相关文章

      网友评论

          本文标题:thinkphp6使用easywechat笔记!

          本文链接:https://www.haomeiwen.com/subject/tdqarxtx.html