🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
# 订阅号的注册 由于我们这个只是演示,我也不好拿公司的公众号来讲,所以只能自己注册一个订阅号 freelog。 微信公众平台 首页点注册: ![2015-07-06/55995dd87871e](http://box.kancloud.cn/2015-07-06_55995dd87871e.png) ![第二步](http://box.kancloud.cn/2015-07-06_55995dead31a4.png) ![验证邮件](http://box.kancloud.cn/2015-07-06_55995e85dadf3.png) 选择订阅号 后填一些信息。 ![登录注册者信息(实名的)](http://box.kancloud.cn/2015-07-06_55995e9b12cfb.png) 前面都是公司运营应该做的。 # 获取`appid`和`secret_token`及aeskey 注册完毕后,点微信公众平台的左侧菜单里的开发者中心,可以看到我们想要的appid和secret_token ![2015-07-06/55996057e9a50](http://box.kancloud.cn/2015-07-06_55996057e9a50.png) 需要扫码后完整显示。 至于AESKEY ,下面初次配置开发的应用url时会随机生成一个: ![2015-07-06/5599618aa4c3c](http://box.kancloud.cn/2015-07-06_5599618aa4c3c.png) 获取到以后,我们就要在项目公共配置里配置上: ~~~ //微信相关 'WEIXIN'=>array( 'TOKEN' => 'freelog', 'APPID' => 'wx72e0b206f3fb96af', 'AESKEY' => 'PbYuJRJ1UKYzpZoH7PUA6MQySGaqiLTit0XveNPtWQ', 'SECRET' => 'e733caf9234ed2ea1342e85366172513', ), ~~~ 在配置应用微信接入地址时,我们传了slog_force_client_id,这样我们可以用socketlog 进行调试微信响应。 并且,如果在我们每次修改微信开发配置时,保存不成功说明,我们程序端没通过验证。 用了麦当苗儿写的wechat 类,我们可以不用写任何验证代码。 # 订阅号开发者模式能做到的接口 ![2015-07-06/559961c2c72e8](http://box.kancloud.cn/2015-07-06_559961c2c72e8.png) 基本上就是获得access_token、服务器ip地址,然后处理一些消息的响应和给用户留言回复一个消息。 # 我的实现 我给微信定义了一个控制器,并且所以响应放在index方法里处理。 老规矩先上代码: ~~~ <?php // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK IT ] // +---------------------------------------------------------------------- // | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: 麦当苗儿 <zuojiazi@vip.qq.com> <http://www.zjzit.cn> // +---------------------------------------------------------------------- namespace Home\Controller; use Think\Controller; use Com\Wechat; use Com\WechatAuth; class WeixinController extends Controller{ public $wc; /** * 微信消息接口入口 * 所有发送到微信的消息都会推送到该操作 * 所以,微信公众平台后台填写的api地址则为该操作的访问地址 */ public function index($id = ''){ $token = C('WEIXIN.TOKEN'); //微信后台填写的TOKEN /* 加载微信SDK */ $this->wc = $wechat = new Wechat($token); /* 获取请求信息 */ $data = $wechat->request(); slog($data); if($data && is_array($data)){ switch ($data['MsgType']) { //事件 case Wechat::MSG_TYPE_EVENT: switch ($data['Event']) { case Wechat::MSG_EVENT_SUBSCRIBE: $wechat->replyText('欢迎关注freelog, 你可以留言引号内内容获得本账号的某些服务比如: 回复"听大白", 会收到一条语音消息, 回复“看视频”,会收到JobDeer官方介绍视频,回复"看图片",看到一个Jobdeer的三行广告,回复“推荐文章”,收到一个推荐的图文消息,回复“功能菜单”,收到欢迎文本'); break; //退订 case Wechat::MSG_EVENT_UNSUBSCRIBE: # TODO 添加微信消息记录日志里去 break; } break; case Wechat::MSG_TYPE_TEXT: $this->onText($data['Content']); break; default: $wechat->response('其他功能尚在开发中', Wechat::MSG_TYPE_TEXT); break; } /** * 你可以在这里分析数据,决定要返回给用户什么样的信息 * 接受到的信息类型有9种,分别使用下面九个常量标识 * Wechat::MSG_TYPE_TEXT //文本消息 * Wechat::MSG_TYPE_IMAGE //图片消息 * Wechat::MSG_TYPE_VOICE //音频消息 * Wechat::MSG_TYPE_VIDEO //视频消息 * Wechat::MSG_TYPE_MUSIC //音乐消息 * Wechat::MSG_TYPE_NEWS //图文消息(推送过来的应该不存在这种类型,但是可以给用户回复该类型消息) * Wechat::MSG_TYPE_LOCATION //位置消息 * Wechat::MSG_TYPE_LINK //连接消息 * Wechat::MSG_TYPE_EVENT //事件消息 * * 事件消息又分为下面五种 * Wechat::MSG_EVENT_SUBSCRIBE //订阅 * Wechat::MSG_EVENT_SCAN //二维码扫描 * Wechat::MSG_EVENT_LOCATION //报告位置 * Wechat::MSG_EVENT_CLICK //菜单点击 * Wechat::MSG_EVENT_MASSSENDJOBFINISH //群发消息成功 */ $content = '这里是Freelog'; //回复内容,回复不同类型消息,内容的格式有所不同 $type = Wechat::MSG_TYPE_TEXT; //回复消息的类型 /* 响应当前请求(自动回复) */ $wechat->response($content, $type); /** * 响应当前请求还有以下方法可以只使用 * 具体参数格式说明请参考文档 * * $wechat->replyText($text); //回复文本消息 * $wechat->replyImage($media_id); //回复图片消息 * $wechat->replyVoice($media_id); //回复音频消息 * $wechat->replyVideo($media_id, $title, $discription); //回复视频消息 * $wechat->replyMusic($title, $discription, $musicurl, $hqmusicurl, $thumb_media_id); //回复音乐消息 * $wechat->replyNews($news, $news1, $news2, $news3); //回复多条图文消息 * $wechat->replyNewsOnce($title, $discription, $url, $picurl); //回复单条图文消息 * */ } } public function onText($text){ slog($text); $wechat = $this->wc; //以下媒体id 是写死的,而且除了音乐调用成功,其他的视频和图片,完全不能正常返回消息。因为不是认证用户没有权限使用接口 if(false !== strpos('听大白', $text)){ //回复音频消息 $wechat->replyMusic('大白balala', '超能陆战队', 'http://att.chinauui.com/day_150309/20150309_aadb238f5998c1a79953qvZzAB41QvBj.wav', 'http://att.chinauui.com/day_150309/20150309_aadb238f5998c1a79953qvZzAB41QvBj.wav'); }else if(false !== strpos('看视频', $text)){ //回复视频消息 $wechat->replyVideo(204247676, 'JobDeer官方视频', '欢迎大家观看视频,了解竞鹿如何帮助候选人快速换工作的。'); }else if(false !== strpos('看图片', $text)){ //回复图片消息 $wechat->replyImage(204248824); }else if(false !== strpos('推荐文章', $text)){ //回复单条图文消息 $wechat->replyNewsOnce('最新一篇文章', 'Hello, Weixin', 'http://freelog.coding.io/Post/44.html', 'http://freelog.coding.io/Uploads/ueditor/image/20150326/551419ea33999.jpg'); }else{ $wechat->replyText('欢迎关注freelog, 你可以留言引号内内容获得本账号的某些服务比如: 回复"听大白", 会收到一条语音消息, 回复“看视频”,会收到JobDeer官方介绍视频,回复"看图片",看到一个Jobdeer的三行广告,回复“推荐文章”,收到一个推荐的图文消息,回复“功能菜单”,收到欢迎文本'); } } //获取带参二维码 目前没权限,暂时不使用 public function weixinQr($sence_id, $expire_seconds = 0){ $wechatauth = new WechatAuth(C('WEIXIN.APPID'), C('WEIXIN.SECRET')); $result = $wechatauth->qrcodeCreate($sence_id, $expire_seconds); if(isset($result['errcode'])){ return false; }else{ return $wechatauth->showqrcode($result['ticket']); } } } ~~~ ~~~ $token = C('WEIXIN.TOKEN'); //微信后台填写的TOKEN /* 加载微信SDK */ $this->wc = $wechat = new Wechat($token); /* 获取请求信息 */ $data = $wechat->request(); slog($data); ~~~ 首先是实例化wechat类和获取响应事件。关注和解除关注也是一种事件。 然后就是根据事件的类型进行处理。 ~~~ if($data && is_array($data)){ switch ($data['MsgType']) { //事件 case Wechat::MSG_TYPE_EVENT: switch ($data['Event']) { case Wechat::MSG_EVENT_SUBSCRIBE: $wechat->replyText('欢迎关注freelog, 你可以留言引号内内容获得本账号的某些服务比如: 回复"听大白", 会收到一条语音消息, 回复“看视频”,会收到JobDeer官方介绍视频,回复"看图片",看到一个Jobdeer的三行广告,回复“推荐文章”,收到一个推荐的图文消息,回复“功能菜单”,收到欢迎文本'); break; //退订 case Wechat::MSG_EVENT_UNSUBSCRIBE: # TODO 添加微信消息记录日志里去 break; } break; case Wechat::MSG_TYPE_TEXT: $this->onText($data['Content']); break; default: $wechat->response('其他功能尚在开发中', Wechat::MSG_TYPE_TEXT); break; ~~~ 接收到的消息类型 接受到的信息类型有9种,分别使用下面九个常量标识 - Wechat::MSG_TYPE_TEXT //文本消息 - Wechat::MSG_TYPE_IMAGE //图片消息 - Wechat::MSG_TYPE_VOICE //音频消息 - Wechat::MSG_TYPE_VIDEO //视频消息 - Wechat::MSG_TYPE_MUSIC //音乐消息 - Wechat::MSG_TYPE_NEWS //图文消息(推送过来的应该不存在这种类型,但是可以给用户回复该类型消息) - Wechat::MSG_TYPE_LOCATION //位置消息 - Wechat::MSG_TYPE_LINK //连接消息 - Wechat::MSG_TYPE_EVENT //事件消息 事件消息又分为下面五种: - Wechat::MSG_EVENT_SUBSCRIBE //订阅 - Wechat::MSG_EVENT_SCAN //二维码扫描 - Wechat::MSG_EVENT_LOCATION //报告位置 - Wechat::MSG_EVENT_CLICK //菜单点击 - Wechat::MSG_EVENT_MASSSENDJOBFINISH //群发消息成功 默认关注,提示首次关注信息,其他文字调用onText处理响应。 index 里 其他的注释是 使用示列,我写出来方便大家自己参照调用。 我们,看一下onText 方法: ~~~ public function onText($text){ slog($text); $wechat = $this->wc; //以下媒体id 是写死的,而且除了音乐调用成功,其他的视频和图片,完全不能正常返回消息。因为不是认证用户没有权限使用接口 if(false !== strpos('听大白', $text)){ //回复音频消息 $wechat->replyMusic('大白balala', '超能陆战队', 'http://att.chinauui.com/day_150309/20150309_aadb238f5998c1a79953qvZzAB41QvBj.wav', 'http://att.chinauui.com/day_150309/20150309_aadb238f5998c1a79953qvZzAB41QvBj.wav'); }else if(false !== strpos('看视频', $text)){ //回复视频消息 $wechat->replyVideo(204247676, 'JobDeer官方视频', '欢迎大家观看视频,了解竞鹿如何帮助候选人快速换工作的。'); }else if(false !== strpos('看图片', $text)){ //回复图片消息 $wechat->replyImage(204248824); }else if(false !== strpos('推荐文章', $text)){ //回复单条图文消息 $wechat->replyNewsOnce('最新一篇文章', 'Hello, Weixin', 'http://freelog.coding.io/Post/44.html', 'http://freelog.coding.io/Uploads/ueditor/image/20150326/551419ea33999.jpg'); }else{ $wechat->replyText('欢迎关注freelog, 你可以留言引号内内容获得本账号的某些服务比如: 回复"听大白", 会收到一条语音消息, 回复“看视频”,会收到JobDeer官方介绍视频,回复"看图片",看到一个Jobdeer的三行广告,回复“推荐文章”,收到一个推荐的图文消息,回复“功能菜单”,收到欢迎文本'); } } ~~~ 其实就是根据留言的消息里,文本内容来做switch 分支菜单。没菜单权限的订阅号只能这么做了。 里面注意的是,媒体资源的媒体id,只能在公众平台里的素材库里先准备好。 比方说 我回复视频时的204247676,是从下面图片上id部分获得的: ![2015-07-06/5599665dc968c](http://box.kancloud.cn/2015-07-06_5599665dc968c.png) 这样,即使没有管理素材的权限,我们也可以人工的获取媒体id。 上面说的是错误的(都是我在文档不全的情况下猜测的),那个不是真正的媒体id,那样写的我的视频放不出来。 我请教了微信类的作者左家梓,他说媒体id一般通过媒体上传接口返回过来。不是数字。像这样的: ![2015-07-30/55ba47e310035](http://box.kancloud.cn/2015-07-30_55ba47e310035.png) 总算见到猪跑了。 顺便贴一下他的demo,https://github.com/Aoiujz/WechatSDK 之前sdk都没有git没法提issue和讨论。还是没文档差评。 然并卵,我们个人订阅号无法认证,没权限上传和获取,微信平台真坑人,无法微信认证,开发者认证还有啥用。 ![2015-07-30/55ba4862140c1](http://box.kancloud.cn/2015-07-30_55ba4862140c1.png) 我只好求助搜索引擎,结果真让我找到这么一个曲线救国的方法: ![2015-07-30/55ba48cecee58](http://box.kancloud.cn/2015-07-30_55ba48cecee58.png) 我自己往freelog订阅号里传了张图片,用我们的socketlog,观察,发现了mediaid ![2015-07-30/55ba4919820a8](http://box.kancloud.cn/2015-07-30_55ba4919820a8.png) 少年啊,我找你好多天了。 为了调试方便,我把default分支扩展了下: ~~~ default: $user_send_types = array(Wechat::MSG_TYPE_IMAGE, Wechat::MSG_TYPE_VOICE, Wechat::MSG_TYPE_VIDEO, Wechat::MSG_TYPE_SHORTVIDEO, Wechat::MSG_TYPE_MUSIC); if(in_array($data['MsgType'], $user_send_types)){ $wechat->replyText('用户传了媒体消息'.$data['MsgType']."媒体id为:{$data['MediaId']}"); }else{ $wechat->response('其他功能尚在开发中', Wechat::MSG_TYPE_TEXT); } break; ~~~ 这样获取的媒体id ,发图片没问题,小视频的媒体id 怎么都不行。 如果只是研究,可以使用测试平台,啥权限都有。如果是在想这些功能。少年,重头注册一个认证的公众号吧,或者找第三方公众平台。 还有,订阅号的服务器配置是可以随时停止和开启的。 然后,如果开启了服务器配置,表示所有的响应和自动回复,都通过我们程序接口处理。关闭了就不会进入程序处理逻辑。 像我们程序里的做的几件事: 关注回复、消息自动回复和关键词回复,都可以通过公众平台做到。 ![2015-07-06/55996775615b3](http://box.kancloud.cn/2015-07-06_55996775615b3.png) 这里被添加就是被关注。 而且,公众平台的好处是,自动回复的定制化支持表情、图片还有换行。 ![2015-07-06/559967e4360fa](http://box.kancloud.cn/2015-07-06_559967e4360fa.png) 而且,同时多个关键词 ![2015-07-06/55996819af5af](http://box.kancloud.cn/2015-07-06_55996819af5af.png) 所以,如果只是订阅号的话,完全可以在开发完接口自动回复和关注回复的时候。 再去公众平台实现同样的功能。这样,当你程序服务器接口出问题时。可以直接把接口停用,让公众平台处理,做个灾备。 # 出错的时候的调试 当用户留言时,微信提示“该公众号暂时无法提供服务,请稍后再试”,如下图的时候,就表示我们的程序没有响应正确的微信响应格式。 ![2015-07-07/559b1e8febe07](http://box.kancloud.cn/2015-07-07_559b1e8febe07.png) # 在线接口调试工具和测试号的使用 微信公众平台里有这么2个东西: ![2015-07-06/559968bc70515](http://box.kancloud.cn/2015-07-06_559968bc70515.png) ## 在线接口调试工具 它可以帮我们在没有写好接口时,通过自己的appid、secret_key等,去直接调用线上接口。然后我们根据响应结果,来观察并处理可能要开发的微信接口的数据结构。 像这样: ![2015-07-06/559969482df4e](http://box.kancloud.cn/2015-07-06_559969482df4e.png) 我们知道access_token的长度,和过期时间。 像这样,我手机留言了一条“测试”的文本消息。 ![2015-07-06/55996a685cb94](http://box.kancloud.cn/2015-07-06_55996a685cb94.png) 再通过调试工具,完全可以模拟测试各种内容: ![2015-07-06/55996b0e09639](http://box.kancloud.cn/2015-07-06_55996b0e09639.png) 我们只要伪造时间戳,内容和msgId,就可以重复测试多次。 ## 接口测试申请系统 这个是给你的网站应用可以配制一个测试微信接口地址。 有的时候你开发的接口消息功能消息,不想让线上微信订阅用户收到。 可以分配一个测试地址,和测试appid、AESKEY、和secret_key。 只要测试的服务器响应时调用的这些测试账号配置,那么微信消息响应和回复就会进入测试订阅号和测试关注者里去了。不会影响到线上,给开发者一个试验田。