# 订阅号的注册
由于我们这个只是演示,我也不好拿公司的公众号来讲,所以只能自己注册一个订阅号 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。
只要测试的服务器响应时调用的这些测试账号配置,那么微信消息响应和回复就会进入测试订阅号和测试关注者里去了。不会影响到线上,给开发者一个试验田。
- 序
- 前言
- 内容简介
- 目录
- 基础知识
- 起步
- 控制器
- 模型
- 模板
- 命名空间
- 进阶知识
- 路由
- 配置
- 缓存
- 权限
- 扩展
- 国际化
- 安全
- 单元测试
- 拿来主义
- 调试方法
- 调试的步骤
- 调试工具
- 显示trace信息
- 开启调试和关闭调试的区别
- netbeans+xdebug
- Socketlog
- PHP常见错误
- 小黄鸭调试法,每个程序员都要知道的
- 应用场景
- 第三方登录
- 图片处理
- 博客
- SAE
- REST实践
- Cli
- ajax分页
- barcode条形码
- excel
- 发邮件
- 汉字转全拼和首字母,支持带声调
- 中文分词
- 浏览器useragent解析
- freelog项目实战
- 需求分析
- 数据库设计
- 编码实践
- 前端实现
- rest接口
- 文章发布
- 文件上传
- 视频播放
- 音乐播放
- 图片幻灯片展示
- 注册和登录
- 个人资料更新
- 第三方登录的使用
- 后台
- 微信的开发
- 首页及个人主页
- 列表
- 归档
- 搜索
- 分页
- 总结经验
- 自我提升
- 进行小项目的锻炼
- 对现有轮子的重构和移植
- 写技术博客
- 制作视频教程
- 学习PHP的知识和新特性
- 和同行直接沟通、交流
- 学好英语,走向国际
- 如何参与
- 浏览官网和极思维还有看云
- 回答ThinkPHP新手的问题
- 尝试发现ThinkPHP的bug,告诉官方人员或者push request
- 开发能提高效率的ThinkPHP工具
- 尝试翻译官方文档
- 帮新手入门
- 创造基于ThinkPHP的产品,进行连带推广
- 展望未来
- OneThink
- ThinkPHP4
- 附录