微信开发之入门

微信公众号

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.2.1 订阅号

订阅号 订阅号2 订阅号3
功能|自动回复(可设置 :)
    关键字回复(可设置随机内容)|收到消息回复|添加关注后立即回复
    
功能|自定义菜单(可设置:)
    底部菜单栏及子栏 (点击---》发消息(图文、图片、语音、视频)|跳网页|跳小程序)

功能|投票
    设置问题及选项(可查看投票详情)

功能|页面模版(放入文章链接)
    用于菜单栏跳转到该页面

功能|原创声明

功能|添加其他功能
小程序|小程序管理
    可管联或创建小程序
管理|消息管理
    查看用户发的消息

管理|用户管理
    查看用户列表和黑名单列表

管理|素材管理
    查看素材信息(文字、图片、语音、视频)用于发布文章
推广|广告
推广|流量
统计|用户分析
    用户增减、属性(性别,城市,终端,机型)
统计|图文分析
    文章创建时间、阅读数、分享数
统计|菜单分析
    菜单栏按钮点击数
统计|消息分析
    消息关键字、发送人数
统计|接口分析
    调用次数、失败率、耗时
统计|网页分析
    访问量
设置|公众号设置(扫描二维码关注)
    修改账号详情
设置|微信认证
    个人账号无法认证
设置|安全中心
    
设置|违规记录
    违规内容、时间
开发|基本配置
    服务器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. 自定义菜单栏接口
注意:
    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。
上一篇下一篇

猜你喜欢

热点阅读