微信公众号
2018-03-30 本文已影响17人
平安喜乐698
目录
1. 概念
1.1. 微信小程序和公众号的区别
1.2. 分类(3种)
1.3. 模式
1. 概念
1.1 微信小程序和公众号的区别
1. 技术上:
公众号基于H5,小程序基于微信自己的开发环境和语言
2. 交互上:
小程序比公众号交互性体验更好
3. 定位上:
公众号用来信息展示和营销,小程序面向产品和服务
1.2. 分类(3种)
分为:
1.订阅号
订阅号用于提供信息资讯.
2.服务号
服务号用于提供服务——给企业提供更强大的业务服务与用户管理能力。
3.企业号
企业号为企业提供移动应用入口,帮助企业建立与员工、上下游供应链及企业应用间的连接。
1.3 模式(2种)
分为:
1.开发模式
通过界面编辑来设置自动回复、服务号及底部自定义菜单功能。
1.1 接收消息
用来接收普通用户发送的文本消息、图片消息、语音消息、视频消息、小视频消息、地理位置消息、链接消息
1.2 回复消息
用来向用户回复文本消息、图片消息、语音消息、视频消息、小视频消息、地理位置消息、链接消息
1.3 消息推送
用户关注和取消关注微信公众账号时将触发关注和取消关注事件
2.编辑模式
通过公众平台提供的接口实现自动回复、获取订阅者、自定义菜单功能
2. 使用
微信公众号开放平台
新浪云服务注册
微信公众号测试账号
微信公众号在线测试接口
2.1 新浪云服务平台
注册账号
控制台|创建应用( 二级域名:自定义)
|创建版本 拿到URL
|点击 上传代码包
|点击 编辑代码
代码包(将以下php文件打包成zip)
index.php
<?php
header('Content-type:text');
// 需和微信公众号token一致
define("TOKEN", "weixin");
$wechatObj = new wechatCallbackapiTest();
if (!isset($_GET['echostr'])) {
$wechatObj->responseMsg();
}else{
$wechatObj->valid();
}
class wechatCallbackapiTest
{
public function valid()
{
// 随机字符串
$echoStr = $_GET["echostr"];
// 验证消息是否来自微信服务器
if($this->checkSignature()){
echo $echoStr;
exit;
}
}
// 验证消息是否来自微信服务器
private function checkSignature()
{
// 微信加密签名
$signature = $_GET["signature"];
// 时间戳
$timestamp = $_GET["timestamp"];
// 随机数
$nonce = $_GET["nonce"];
$token = TOKEN;
$tmpArr = array($token, $timestamp, $nonce);
sort($tmpArr);
$tmpStr = implode($tmpArr);
$tmpStr = sha1($tmpStr);
if($tmpStr == $signature){
return true;
}else{
return false;
}
}
public function responseMsg()
{
$postStr = $GLOBALS["HTTP_RAW_POST_DATA"];
if (!empty($postStr)){
$this->logger("R ".$postStr);
$postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
$RX_TYPE = trim($postObj->MsgType);
switch ($RX_TYPE)
{
case "event":
$result = $this->receiveEvent($postObj);
break;
case "text":
$result = $this->receiveText($postObj);
break;
}
$this->logger("T ".$result);
echo $result;
}else {
echo "";
exit;
}
}
// 接收到事件
private function receiveEvent($object)
{
$content = "";
switch ($object->Event)
{
case "subscribe": // 关注事件
$content = "欢迎关注";
break;
case "unsubscribe": // 取消关注事件
$content = "取消关注";
break;
}
// 发送消息
$result = $this->transmitText($object, $content);
return $result;
}
//接收文本消息
private function receiveText($object)
{
$keyword = trim($object->Content);
$content = date("Y-m-d H:i:s",time())."\n技术支持";
if(is_array($content)){
if (isset($content[0]['PicUrl'])){
$result = $this->transmitNews($object, $content);
}else if (isset($content['MusicUrl'])){
$result = $this->transmitMusic($object, $content);
}
}else{
$result = $this->transmitText($object, $content);
}
return $result;
}
private function transmitText($object, $content)
{
$textTpl = "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[%s]]></Content>
</xml>";
$result = sprintf($textTpl, $object->FromUserName, $object->ToUserName, time(), $content);
return $result;
}
private function transmitNews($object, $arr_item)
{
if(!is_array($arr_item))
return;
$itemTpl = " <item>
<Title><![CDATA[%s]]></Title>
<Description><![CDATA[%s]]></Description>
<PicUrl><![CDATA[%s]]></PicUrl>
<Url><![CDATA[%s]]></Url>
</item>
";
$item_str = "";
foreach ($arr_item as $item)
$item_str .= sprintf($itemTpl, $item['Title'], $item['Description'], $item['PicUrl'], $item['Url']);
$newsTpl = "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[news]]></MsgType>
<Content><![CDATA[]]></Content>
<ArticleCount>%s</ArticleCount>
<Articles>
$item_str</Articles>
</xml>";
$result = sprintf($newsTpl, $object->FromUserName, $object->ToUserName, time(), count($arr_item));
return $result;
}
private function transmitMusic($object, $musicArray)
{
$itemTpl = "<Music>
<Title><![CDATA[%s]]></Title>
<Description><![CDATA[%s]]></Description>
<MusicUrl><![CDATA[%s]]></MusicUrl>
<HQMusicUrl><![CDATA[%s]]></HQMusicUrl>
</Music>";
$item_str = sprintf($itemTpl, $musicArray['Title'], $musicArray['Description'], $musicArray['MusicUrl'], $musicArray['HQMusicUrl']);
$textTpl = "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[music]]></MsgType>
$item_str
</xml>";
$result = sprintf($textTpl, $object->FromUserName, $object->ToUserName, time());
return $result;
}
private function logger($log_content)
{
if(isset($_SERVER['HTTP_APPNAME'])){ //SAE
sae_set_display_errors(false);
sae_debug($log_content);
sae_set_display_errors(true);
}else if($_SERVER['REMOTE_ADDR'] != "127.0.0.1"){ //LOCAL
$max_size = 10000;
$log_filename = "log.xml";
if(file_exists($log_filename) and (abs(filesize($log_filename)) > $max_size)){unlink($log_filename);}
file_put_contents($log_filename, date('H:i:s')." ".$log_content."\r\n", FILE_APPEND);
}
}
}
?>
创建应用
创建版本
2.2 微信平台
微信测试号平台(个人测试)
注册账号
填写URL:http://1.qq号.applinzi.com/ (新浪云创建应用的链接)
token:weixin
提交
手机微信扫描测试公众号,并发送消息
微信公众平台
选择类型进行注册
订阅号 订阅号2 订阅号32.2.1 订阅号
功能|自动回复(可设置 :)
关键字回复(可设置随机内容)|收到消息回复|添加关注后立即回复
功能|自定义菜单(可设置:)
底部菜单栏及子栏 (点击---》发消息(图文、图片、语音、视频)|跳网页|跳小程序)
功能|投票
设置问题及选项(可查看投票详情)
功能|页面模版(放入文章链接)
用于菜单栏跳转到该页面
功能|原创声明
功能|添加其他功能
小程序|小程序管理
可管联或创建小程序
管理|消息管理
查看用户发的消息
管理|用户管理
查看用户列表和黑名单列表
管理|素材管理
查看素材信息(文字、图片、语音、视频)用于发布文章
推广|广告
推广|流量
统计|用户分析
用户增减、属性(性别,城市,终端,机型)
统计|图文分析
文章创建时间、阅读数、分享数
统计|菜单分析
菜单栏按钮点击数
统计|消息分析
消息关键字、发送人数
统计|接口分析
调用次数、失败率、耗时
统计|网页分析
访问量
设置|公众号设置(扫描二维码关注)
修改账号详情
设置|微信认证
个人账号无法认证
设置|安全中心
设置|违规记录
违规内容、时间
开发|基本配置
服务器url(http://1.qq号.applinzi.com/ (新浪云创建应用的链接))
token(需和代码中设置的token一致)
EncodingAESKey(随机生成)
开启后,自定义菜单栏、自动回复失效!!!!
开发|开发者工具
开发|运维中心
统计接口调用次数
开发|接口权限
查看已获得的接口权限
3.开启服务器配置
获取access token
1.临时获取
测试平台 | 选择 基础支持-access token
2.
https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=&secret=
3.1 消息管理
《1》 接收消息
《2》 自动回复
用户向公众号发送消息,微信服务器请求开发服务器,自动回复
若服务器无法保证在五秒内处理回复,则必须回复“success”或者“”(空串),否则微信后台会发起三次重试。
ToUserName 是 接收方帐号(收到的OpenID)
FromUserName 是 开发者微信号
CreateTime 是 消息创建时间 (整型)
MsgType 是 text
Content 是 回复的消息内容(换行:在content中能够换行,微信客户端就支持换行显示)
回复文本消息
<xml>
<ToUserName>< ![CDATA[粉丝号] ]></ToUserName>
<FromUserName>< ![CDATA[公众号] ]></FromUserName> <CreateTime>12345678</CreateTime>
<MsgType>< ![CDATA[text] ]></MsgType>
<Content>< ![CDATA[要回复的文本] ]></Content>
</xml>
回复图片消息
<xml>
<ToUserName><![CDATA[粉丝号]]></ToUserName>
<FromUserName><![CDATA[公众号]]></FromUserName>
<CreateTime>1460536576</CreateTime>
<MsgType><![CDATA[image]]></MsgType>
<Image> <MediaId><![CDATA[素材ID]]></MediaId> </Image>
</xml>
回复语音消息
<xml>
<ToUserName>< ![CDATA[粉丝号] ]></ToUserName>
<FromUserName>< ![CDATA[公众号] ]></FromUserName><CreateTime>12345678</CreateTime>
<MsgType>< ![CDATA[voice] ]></MsgType>
<Voice><MediaId>< ![CDATA[语音ID] ]></MediaId></Voice>
</xml>
回复视频消息
<xml><ToUserName>< ![CDATA[粉丝号] ]></ToUserName>
<FromUserName>< ![CDATA[公众号] ]></FromUserName><CreateTime>12345678</CreateTime>
<MsgType>< ![CDATA[video] ]></MsgType>
<Video><MediaId>< ![CDATA[视频ID] ]></MediaId><Title>< ![CDATA[标题] ]></Title><Description>< ![CDATA[内容描述] ]></Description></Video>
</xml>
回复音乐消息
<xml>
<ToUserName>< ![CDATA[粉丝号] ]></ToUserName>
<FromUserName>< ![CDATA[公众号] ]></FromUserName><CreateTime>12345678</CreateTime>
<MsgType>< ![CDATA[music] ]></MsgType>
<Music><Title>< ![CDATA[标题] ]></Title><Description>< ![CDATA[内容描述] ]></Description><MusicUrl>< ![CDATA[音乐URL] ]></MusicUrl><HQMusicUrl>< ![CDATA[高质量音乐URL] ]></HQMusicUrl><ThumbMediaId>< ![CDATA[音频ID] ]></ThumbMediaId></Music>
</xml>
回复图文消息
<xml>
<ToUserName>< ![CDATA[粉丝号] ]></ToUserName>
<FromUserName>< ![CDATA[公众号] ]></FromUserName><CreateTime>12345678</CreateTime>
<MsgType>< ![CDATA[news] ]></MsgType>
<ArticleCount>2</ArticleCount>
<Articles>
<item><Title>< ![CDATA[标题1] ]></Title> <Description>< ![CDATA[内容1] ]></Description><PicUrl>< ![CDATA[图片URL] ]></PicUrl><Url>< ![CDATA[点击图跳转URL] ]></Url></item>
<item><Title>< ![CDATA[标题2] ]></Title><Description>< ![CDATA[内容2] ]></Description><PicUrl>< ![CDATA[图片URL] ]></PicUrl><Url>< ![CDATA[点击图跳转URL] ]></Url></item>
</Articles>
</xml>
例1:根据文本回复文本
在receiveText方法中+以下代码片段并保存
if($object->MsgType=='text'){
if("1"==$object->Content){
$content = date("Y-m-d H:i:s",time())."\n2222技术支持111111";
}
}
例2:根据图片回复图片
// 返回响应数据
public function responseMsg()
{
$postStr = $GLOBALS["HTTP_RAW_POST_DATA"];
if (!empty($postStr)){
$this->logger("R ".$postStr);
$postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
$RX_TYPE = trim($postObj->MsgType);
switch ($RX_TYPE)
{
case "event":
$result = $this->receiveEvent($postObj);
break;
case "text":
$result = $this->receiveText($postObj);
case "image": // 添加处理图片方法
$result = $this->receiveImage($postObj);
break;
}
$this->logger("T ".$result);
echo $result;
}else {
echo "";
exit;
}
}
// 处理图片
private function receiveImage($object){
$result = $this->transmitImage($object, $object->MediaId);
return $result;
}
private function transmitImage($object, $content)
{
$textTpl = "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[image]]></MsgType>
<Image>
<MediaId><![CDATA[%s]]></MediaId>
</Image>
</xml>";
$result = sprintf($textTpl, $object->FromUserName, $object->ToUserName, time(), $content);
return $result;
}
《3》 接收事件推送
用户的某些操作(如:关注和取消关注)会推送事件给开发服务器。
1 关注/取消关注事件
开发服务器接收到的数据格式(分析后向用户发送消息)
subscribe(订阅)、unsubscribe(取消订阅)
<xml>
<ToUserName>< ![CDATA[公众号] ]></ToUserName>
<FromUserName>< ![CDATA[粉丝号] ]></FromUserName><CreateTime>123456789</CreateTime>
<MsgType>< ![CDATA[event] ]></MsgType>
<Event>< ![CDATA[subscribe] ]></Event>
</xml>
2 扫描带参数二维码事件
用户未关注时推送,开发服务器接收到的数据格式:
<xml>
<ToUserName>< ![CDATA[toUser] ]></ToUserName>
<FromUserName>< ![CDATA[FromUser] ]></FromUserName><CreateTime>123456789</CreateTime>
<MsgType>< ![CDATA[event] ]></MsgType>
<Event>< ![CDATA[subscribe] ]></Event>
<EventKey>< ![CDATA[qrscene_123123] ]></EventKey>
<Ticket>< ![CDATA[TICKET] ]></Ticket>
</xml>
用户已关注时推送,开发服务器接收到的数据格式:
<xml> <ToUserName>< ![CDATA[toUser] ]></ToUserName> <FromUserName>< ![CDATA[FromUser] ]></FromUserName> <CreateTime>123456789</CreateTime>
<MsgType>< ![CDATA[event] ]></MsgType>
<Event>< ![CDATA[事件类型SCAN] ]></Event>
<EventKey>< ![CDATA[事件KEY值 二维码scene_id SCENE_VALUE] ]></EventKey>
<Ticket>< ![CDATA[二维码的ticket,可用来换取二维码图片TICKET] ]></Ticket>
</xml>
3 上报地理位置事件
用户同意上报地理位置后,每次进入公众号会话时都会上报
开发服务器接收到的数据格式
<xml>
<ToUserName>< ![CDATA[公众号] ]></ToUserName>
<FromUserName>< ![CDATA[粉丝号] ]></FromUserName><CreateTime>123456789</CreateTime>
<MsgType>< ![CDATA[event] ]></MsgType>
<Event>< ![CDATA[事件类型LOCATION] ]></Event>
<Latitude>纬度23.137466</Latitude>
<Longitude>经度113.352425</Longitude>
<Precision>精度119.385040</Precision>
</xml>
4 自定义菜单事件
点击菜单弹出子菜单,不会产生上报
5 点击菜单拉取消息时的事件推送
开发服务器接收到的数据格式
<xml>
<ToUserName>< ![CDATA[公众号] ]></ToUserName>
<FromUserName>< ![CDATA[粉丝号] ]></FromUserName><CreateTime>123456789</CreateTime>
<MsgType>< ![CDATA[event] ]></MsgType>
<Event>< ![CDATA[事件类型CLICK] ]></Event>
<EventKey>< ![CDATA[事件key值EVENTKEY] ]></EventKey>
</xml>
6 点击菜单跳转链接时的事件推送
开发服务器接收到的数据格式
<xml><ToUserName>< ![CDATA[公众号] ]></ToUserName>
<FromUserName>< ![CDATA[粉丝号] ]></FromUserName><CreateTime>123456789</CreateTime>
<MsgType>< ![CDATA[event] ]></MsgType>
<Event>< ![CDATA[事件类型VIEW] ]></Event>
<EventKey>< ![CDATA[事件key值设置的跳转URLwww.qq.com] ]></EventKey>
</xml>
- 自定义菜单栏接口
注意:
1、一级菜单最多3个,一个一级菜单可包含最多5个二级菜单。
2、一级菜单最多4个汉字,二级菜单最多7个汉字,超出则以...代替。
3、在用户进入公众号会话页或公众号profile页时,如果发现上一次拉取菜单的请求在5分钟以前,就会拉取一下菜单,有变化则更新。
可实现以下类型按钮:
1、click类型:点击后,微信服务器会通过消息接口推送消息类型为event的结构给开发者,并且带上按钮中开发者填写的key值,开发者可以通过自定义的key值与用户进行交互;
2、view类型:点击后,打开按钮中填写的URL。可与网页授权获取用户基本信息接口结合,获得用户基本信息。
3、scancode_push类型:点击后,调起扫一扫,扫码后显示扫描结果(如果是URL,将进入URL),且会将扫码的结果传给开发者,开发者可以下发消息。
4、scancode_waitmsg类型:点击后,调起扫一扫,扫码后将扫码的结果传给开发者,同时收起扫一扫工具,然后弹出“消息接收中”提示框,随后可能会收到开发者下发的消息。
5、pic_sysphoto类型:点击后,调起相机,拍照后将照片发送给开发者,并推送事件给开发者,同时收起系统相机,随后可能会收到开发者下发的消息。
6、pic_photo_or_album类型:点击后,弹出选择器(拍照|相册)。
7、pic_weixin类型:点击后,调起相册,选择后将照片发送给开发者的服务器,并推送事件给开发者,同时收起相册,随后可能会收到开发者下发的消息。
8、location_select类型:点击后,调起地理位置选择工具,选择后将位置发送给开发者的服务器,同时收起位置选择工具,随后可能会收到开发者下发的消息。
9、media_id类型(用于订阅号):点击后,将开发者填写的永久素材id对应的素材下发给用户,永久素材类型可以是图片、音频、视频、图文消息。请注意:永久素材id必须是在“素材管理/新增永久素材”接口上传后获得的合法id。
10、view_limited类型(用于订阅号):点击后,打开开发者在按钮中填写的永久素材id对应的图文消息URL,永久素材类型只支持图文消息。请注意:永久素材id必须是在“素材管理/新增永久素材”接口上传后获得的合法id。