用微信来搞世界上最好的语言——消息收发SDK的实现

在上一章中实现了一文本消息的互动。本章将在上一篇基础上完成开发。

微信的基础消息接口包括三个部分:接收普通消息、发送被动回复消息、接收事件消息

4.1 文本消息 <MsgType><![CDATA[text]]></MsgType>

一个公众号接收用户的文本消息包括

<xml>
    <ToUserName><![CDATA[接收方账号]]></ToUserName>
    <FromUserName><![CDATA[发送者的openid]]></FromUserName>
    <CreateTime>时间整型</CreateTime>
    <MsgType><![CDATA[text]]></MsgType>
    <Content><![CDATA[内容]></Content>
    <MsgId>消息id</MsgId> <!-消息64位 -->
</xml>

微信用户接收公众号的文本消息组织包括:

<xml>
    <ToUserName><![CDATA[接收方账号(收到的openid)]]></ToUserName>
    <FromUserName><![CDATA[发送者的openid]]></FromUserName>
    <CreateTime>时间整型</CreateTime>
    <MsgType><![CDATA[text]]></MsgType>
    <Content><![CDATA[我是内容]></Content>
    <MsgId>消息id</MsgId> <!-消息64位 -->
</xml>

4.2 图片消息

一个公众号接收用户的图片消息包括

<xml>
    <!-只列出不同-->
    <MsgType><![CDATA[image]]></MsgType>
    <PicUrl><![CDATA[http://file.api.weixin.qq.com/cgi-bin/media/upload?access_token=10_5fQEan8J_3b09bXLjDaYFmjjKqjem8tD6om2oxyUF_zKIt5pEjp7xNU_KiCyWokEnN3QcklwVXWIEyh4qhN-7idad2TRsrHGVt9VBZCxeL7mhUapJ-iSE2owvuvBmOMk4gFwk_iVW0Qak9x9XJTiAIATFP&type=image]]></PicUrl>
    <MediaId><![CDATA[媒体id]]></MediaId>
</xml>

PicUrl就是图片地址。

媒体id可以从多媒体文件下载接口拉取。

一个公众号回复用户的图片消息包括:

<xml>
    <!-只列出不同-->
    <MsgType><![CDATA[image]]></MsgType>
    <Image>
        <MediaId><![CDATA[媒体id]]></MediaId>
    </Image>

    <MediaId><![CDATA[媒体id]]></MediaId>
</xml>

4.3 语音消息

语音消息的MsgType为:voice。

一个公众号接收用户的语音消息包括

<xml>
    <!-只列出不同-->
    <MsgType><![CDATA[voice]]></MsgType>
    <MediaId><![CDATA[xxxxxxxx]]></MediaId>
    <Format><![CDATA[amr/speex]]></Format>
    <Recognition><![CDAATA[]]></Recognition>

</xml>

一个公众号回复用户的语音消息包括:

<xml>
    <!-只列出不同-->
    <MsgType><![CDATA[voice]]></MsgType>
    <Voice>
        <MediaId><![CDATA[媒体id]]></MediaId>
    </Voice>


</xml>

4.4 视频消息

视频消息的MsgType为:video。

一个公众号接收用户的语音消息包括

<xml>
    <!-只列出不同-->
    <MsgType><![CDATA[video]]></MsgType>
    <MediaId><![CDATA[xxxxxxxx]]></MediaId>

    <ThumbMediaId><![CDATA[缩略图媒体id]]></ThumbMediaId> 

</xml>

一个公众号回复用户的语音消息包括:

<xml>
    <!-只列出不同-->
    <MsgType><![CDATA[video]]></MsgType>
    <Video>
        <MediaId><![CDATA[xxxx]]></MediaId>
        <ThumbMediaId><![CDATA[缩略图媒体id]]></ThumbMediaId>
        <Titile><![CDATA[标题]]></Titile>
        <Description><![CDATA[描述]]></Description>
    </Video>


</xml>

4.5 用户发送给公众号的地理位置消息

地理位置消息的MsgType为:location。

<xml>
    <!-只列出不同-->
    <MsgType><![CDATA[location]]></MsgType>
    <Location_X>纬度数字</Location_X>
    <Location_Y>经度数字</Location_Y>
    <Scale>放大倍数比如16</Scale>
    <Label><![CDATA[中国北京天安门]]></Label>

</xml>

4.6 用户发送给公众号的链接消息

链接消息的title为link

<xml>
    <!-只列出不同-->
    <MsgType><![CDATA[location]]></MsgType>
    <Titile><![CDATA[标题]]></Titile>
    <Description><![CDATA[描述]]></Description>
    <Url><![CDATA[url地址]]></Url>

</xml>

4.7 公众号发回用户的音乐消息

音乐消息的type为music。、

<xml>
    <!--只列出不同-->
    <MsgType><![CDATA[music]]></MsgType>
    <Music>
        <Title><![CDATA[最炫民族风]]></Title>
        <Description>
            <![CDATA[凤凰传奇]]>
        </Description>
        <!--音乐的一般链接和Hq(高品质)链接-->
        <MusicUrl><![CDATA[http://adasfasfasfwsgvwe.vas.vsdvs]]></MusicUrl>
        <HQMusicUrl><![CDATA[http://adasfasfasfwsgvwe.vas.vsdvs]]></HQMusicUrl>
    </Music>
</xml>

4.8 公众号发给用户的图文消息

图文可以分为单图文和多图文,显示方式基本是一样的。

<xml>
    <ToUserName><![CDATA[发送的微信账号]]></ToUserName>
    <FromUserName><![CDATA[收到的微信账号]]></FromUserName>
    <CreateTime>时间戳</CreateTime>
    <MsgType><![CDATA[news]]></MsgType>
    <Content><![CDATA[内容]]></Content>
    <ArticleCount>1</ArticleCount>

    <Articles>
        <item>
            <Title>标题</Title>
            <Description>摘要</Description>

            <PicUrl> <![CDATA[题图地址]]></PicUrl>
            <Url><![CDATA[链接地址]]></Url>
        </item>
        <!--如果是多图文,将有几个不同的item-->
    </Articles>
</xml>

4.9 接收事件

基础接口的事件只有两个,就是关注和取消关注。 msgType为event。

用户点击关注公众号->

<xml>
    <ToUserName><![CDATA[发送的微信账号]]></ToUserName>
    <FromUserName><![CDATA[收到的微信账号]]></FromUserName>
    <CreateTime>时间戳</CreateTime>
    <MsgType><![CDATA[event]]></MsgType>

    <Event><![CDATA[subscribe]]></Event><!--订阅-->
    <EventKey><![CDATA[]]></EventKey><!--为空-->

</xml>

用户取关->

<xml>
    <ToUserName><![CDATA[发送的微信账号]]></ToUserName>
    <FromUserName><![CDATA[收到的微信账号]]></FromUserName>
    <CreateTime>时间戳</CreateTime>
    <MsgType><![CDATA[event]]></MsgType>

     <Event><![CDATA[unsubscribe]]></Event><!--取消订阅-->
     <EventKey><![CDATA[]]></EventKey><!--为空-->
</xml>

4.10 写基础消息的SDK

【需求】根据之前的消息范例,写一个微信公众号的SDK。

4.10.1 消息流程

基础消息的SDK将前面章节的各种接收消息类型进行了处理,另外对被动发送消息类型进行了定义。

responseMsg()方法中,先提取消息类型 $postObj->MsgType,从而实现各种消息类型的分离。在类wechatCallbackapiTest中,为每种消息定型定义了接收方法函数。在每个方法里面,返回消息的主要特征值,组成文本信息作为内容回复。   

在接收到文本指令回复文本、图文(包括单图文和多图文)、音乐三种消息时,是使用直接构造相应消息类型实现的,而图片、语音、视频三种消息需要MediaId参数,在这里直接使用用户发送过来的消息中的MediaId,然后组装成响应消息回复。

由之前的原理可得:

用户发出消息=>校验=>判断消息类型,跳转不同业务逻辑=>根据不同消息类型,制定不同的消息。

和上一章一样,定义一个 wechatCallbackapiTest类:

<?php 
/**
 * 微信第一个SDK
 */

header('Content-type:text');
define('TOKEN','weixin');

$wechatObj=new wechatCallbackapiTest();

if(!isset($_GET['echostr'])){
    $wechatObj->responseMsg();
}else{
    $wechatObj->valid();
}

public wechatCallbackapiTest{
    // ...
}

?>

4.10.2 响应消息

收到消息,先判断MsgType。再根据类型转发到receiveXXX方法。

<?php

    // ...
    //响应消息
    public function responseMsg(){
        $postStr=$GLOBALS['HTTP_RAW_POST_DATA'];

        if(!empty($postStr)){
            // $this->logger("R \r\n.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;

                case 'image'://图片
                    $result=$this->receiveImage($postObj);
                    break;

                case 'location'://位置
                    $result=$this->receiveLocation($postObj);
                    break;

                case 'voice'://语音
                    $result=$this->receiveVoice($postObj);
                    break;

                case 'video':
                case 'shortVideo'://视频
                    $result=$this->receiveVideo($postObj);
                    break;

                case 'link':
                    $result=$this->receiveLink($postObj);
                    break;

                default:
                    $result='未知的消息类型。';
                    break;

            }

            // $this->logger("T \r\n".$result);

            echo $result;
        }else{
            echo '';
        }

    }   


?>

4.10.3 receiveXXX处理流程

receiveXXX就是针对每种消息进行分类处理好大部分恢复内容后,进入组装流程(transmitXXX)。

4.10.4 组装消息流程(transmitXXX)

<?php 
    // 。。。
    / 回复文本消息

        private function transmitText($object,$content){
            if(!isset($content)||empty($content)){
                return "";
            }
                $xmlTpl="
                    <xml>
                        <ToUserName><![CDATA[%s]]></ToUserName>
                        <FromUserName><![CDATA[%s]]></FromUserName>
                        <CreateTime>%s</CreateTime>
                        <MsgType><![CDATA[text]]></MsgType>
                        <Content><![CDATA[%s]]></Content>
                    </xml>
                ";
                $result=sprintf($xmlTpl,$object->FromUserName,$object->ToUserName,time(),$content);

            return $result;
        }


    //回复图文消息
       private function transmitNews($object,$content){
        if(!is_array($content)){
            return "";
        }
        $itemTpl="
        <item>
            <Title><![CDATA[%s]]></Title>
            <Description><![CDATA[%s]]></Description>
            <PicUrl><![CDATA[%s]]></PicUrl>
            <Url><![CDATA[%s]]></Url>
        </item>
        ";
        $item_str="";
        foreach ($content as $item){
            $item_str.=sprintf($itemTpl, $item['Title'], $item['Description'], $item['PicUrl'], $item['Url']);
        }
        $xmlTpl = "<xml>
                    <ToUserName><![CDATA[%s]]></ToUserName>
                    <FromUserName><![CDATA[%s]]></FromUserName>
                    <CreateTime>%s</CreateTime>
                    <MsgType><![CDATA[news]]></MsgType>
                    <ArticleCount>%s</ArticleCount>
                    <Articles>
                        $item_str    
                    </Articles>
                </xml>";

        $result=sprintf($xmlTpl,$object->FromUserName,$object->ToUserName,time(),count($content));
        return $result;
    }



    //回复音乐消息
        private function transmitMusic($object,$content){
            if(!is_array($content)){
                return '';
            }
            $itemTpl="
                <Music>
                    <Title><![CDATA[%s]]></Title>
                    <Description>
                        <![CDATA[%s]]>
                    </Description>
                    <MusicUrl><![CDATA[%s]]></MusicUrl>
                    <HQMusicUrl><![CDATA[%s]]></HQMusicUrl>
                </Music>
            ";

            $item_str=sprintf($itemTpl,$content['Title'],$content['Description'],$content['MusicUrl'],$content['HQMusicUrl']);

            $xmlTpl="
                <xml>
                    <ToUserName><![CDATA[%s]]></ToUserName>
                    <FromUserName><![CDATA[%s]]></FromUserName>
                    <CreateTime>%s</CreateTime>
                    <MsgType><![CDATA[music]]></MsgType>

                    $item_str

                </xml>
            ";

            $result=sprintf($xmlTpl,$object->FromUserName,$object->ToUserName,time());

            return $result;
        }

     //回复图片消息
        private function transmitImage($object,$content){
            $itemTpl="
                <Image>
                    <MediaId><![CDATA[%s]]></MediaId>
                </Image>
            ";

            $item_str=sprintf($itemTpl,$content['MediaId']);

            $xmlTpl="
                <xml>
                    <ToUserName><![CDATA[%s]]></ToUserName>
                    <FromUserName><![CDATA[%s]]></FromUserName>
                    <CreateTime>%s</CreateTime>
                    <MsgType><![CDATA[image]]></MsgType>
                    $item_str
                </xml>
            ";



            $result=sprintf($xmlTpl,$object->FromUserName,$object->ToUserName,time());

            return $result;
        }

        //回复语音
        private function transmitVoice($object,$content){
            $itemTpl="
                <Voice>
                    <MediaId><![CDATA[%s]]></MediaId>
                </Voice>
            ";

            $item_str=sprintf($itemTpl,$content['MediaId']);

            $xmlTpl="
                <xml>
                    <ToUserName><![CDATA[%s]]></ToUserName>
                    <FromUserName><![CDATA[%s]]></FromUserName>
                    <CreateTime>%s</CreateTime>
                    <MsgType><![CDATA[voice]]></MsgType>

                    $item_str
                </xml>
            ";


            $result=sprintf($xmlTpl,$object->FromUserName,$object->ToUserName,time());

            return $result;
        }

    //回复视频消息
    private function transmitVideo($object, $videoArray)
    {
        $itemTpl = "<Video>
        <MediaId><![CDATA[%s]]></MediaId>
        <ThumbMediaId><![CDATA[%s]]></ThumbMediaId>
        <Title><![CDATA[%s]]></Title>
        <Description><![CDATA[%s]]></Description>
    </Video>";

        $item_str = sprintf($itemTpl, $videoArray['MediaId'], $videoArray['ThumbMediaId'], $videoArray['Title'], $videoArray['Description']);

        $xmlTpl = "<xml>
    <ToUserName><![CDATA[%s]]></ToUserName>
    <FromUserName><![CDATA[%s]]></FromUserName>
    <CreateTime>%s</CreateTime>
    <MsgType><![CDATA[video]]></MsgType>
    $item_str
</xml>";

        $result = sprintf($xmlTpl, $object->FromUserName, $object->ToUserName, time());
        return $result;
    }

    // 。。。

?>

自此,一个基础微信的SDJK就完成了。

原文发布于微信公众号 - 一Li小麦(gh_c88159ec1309)

原文发表时间:2018-06-29

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券