1. 程式人生 > >微信公眾平臺萬能程式碼詳解-php語言(二)

微信公眾平臺萬能程式碼詳解-php語言(二)

1.基礎知識在上一篇地址有講解和圖片,內容大致包括微信開發者模式後臺配置、微信公眾開發者文件程式碼詳解。

2.本篇將粘貼出包括所有型別在內的訊息處理辦法,在開發者模式下用程式碼完成所有編輯模式的基礎內容。

3.本篇程式碼是最基礎的微信公眾平臺功能,大家要掌握如何套用。

===============================================萬能的閹割線================================================================

<?php
/*
    李凡的實驗
*/

define("TOKEN", "weixin");                                       //定義常量"TOKEN"為weixin,這裡的weixin和上圖Token值一致。
$wechatObj = new wechatCallbackapiTest();                      //將wechatCallbackapiTest類例項化,物件名為wechatObj。
/*
開發者文件——驗證訊息真實性:http://mp.weixin.qq.com/wiki/4/2ccadaef44fe1e4b0322355c2312bfa8.html
在開發者首次提交驗證申請時,微信伺服器將傳送GET請求到填寫的URL上,並且帶上四個引數(signature、timestamp、nonce、echostr),開發者通過對簽名(即signature)的效驗,來判斷此條訊息的真實性。此後,每次開發者接收使用者訊息的時候,微信也都會帶上前面三個引數(signature、timestamp、nonce)訪問開發者設定的URL,開發者依然通過對簽名的效驗判斷此條訊息的真實性。校驗方式與首次提交驗證申請一致。
*/
if (!isset($_GET['echostr'])) {                                //從微信伺服器(你的公眾號)獲取隨機字元$echostr;isset()判斷引數是否設定,引數存在且有值為true
    $wechatObj->responseMsg();                                 //若沒有echostr,表示已經通過驗證,直接呼叫responseMsg()方法
}else{
    $wechatObj->valid();                  //若存在echostr,表示第一次提交驗證申請,呼叫驗證方法valid(),判斷微信伺服器(你的公眾號)與網站伺服器的是否連通。
}

class wechatCallbackapiTest
{
    //驗證訊息
    public function valid()
    {
        $echoStr = $_GET["echostr"];       //微信伺服器傳送來的字串,驗證通過,將該字串原樣輸出,表示驗證成功!
        if($this->checkSignature()){       //呼叫checkSignature()方法檢查簽名(Signature)是否一致
            echo $echoStr;
            exit;
        }
    }

    //檢查簽名
    //官網可下載程式碼——http://mp.weixin.qq.com/wiki/4/2ccadaef44fe1e4b0322355c2312bfa8.html
    private function checkSignature()
    {
        $signature = $_GET["signature"];  //從微信伺服器(你的公眾號)獲取簽名
        $timestamp = $_GET["timestamp"]; //從微信伺服器獲取時間戳
        $nonce = $_GET["nonce"];         //從微信伺服器獲取隨機數
        $token = TOKEN;                  //將自己核心程式碼中定義的Token賦值到這裡
        $tmpArr = array($token, $timestamp, $nonce);  //建立陣列變數——token+timestamp+nonce
        sort($tmpArr, SORT_STRING);                  //對$tmpArr陣列中的 引數 排序;SORT_STRING:把值作為字串來處理。        $tmpStr = implode($tmpArr);                  //把陣列中的 引數 組合為一個字串——$tmpStr=$token+$timestamp+$nonce
        $tmpStr = sha1($tmpStr);                     //對字串$tmpStr進行sha1加密。沒有問題的話它會和 $signature 一致

        if($tmpStr == $signature){                  //驗證Token一致,通過驗證,返回true
            return true;
        }else{
            return false;
        }
    }
//================================================請求校驗結束,相應訊息一步曲開始========================================================
    //響應訊息
    public function responseMsg()
    {
        $postStr = $GLOBALS["HTTP_RAW_POST_DATA"];               //獲取微信端傳送的訊息;因為訊息是XML資料格式,使用$_POST無法解析,故使用此方法獲取
        if (!empty($postStr)){                                   //不是空內容,即有訊息傳送過來的話,就...
            
            $postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
/*將$postStr變數進行解析並將 解析後所有資料 賦予 新物件$postObj。
simplexml_load_string():PHP中解析XML的函式;
第一個引數:要解析的XML字串;
第二個引數:規定新物件所屬類——SimpleXMLElement;
第三個引數:將CDATA設定為文字節點,CDATA標籤中的文字XML不解析。*/
            $RX_TYPE = trim($postObj->MsgType); //從$postObj物件獲取訊息型別 MsgType。包括文字、圖片、語音、視訊、位置、連結 + 事件

            switch ($RX_TYPE)        //根據不同的訊息型別,進行不同的處理
            {
                case "event":
                    $result = $this->receiveEvent($postObj);       //訊息型別屬於事件(event),呼叫 接收到事件 方法,將包含所有資料的$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":
                    $result = $this->receiveVideo($postObj);       //使用者傳送的是 視訊,呼叫 接收到視訊 方法
                    break;
                case "link":
                    $result = $this->receiveLink($postObj);        //使用者傳送的是 連結,呼叫 接收到連結 方法
                    break;
                default:
                    $result = "unknown msg type: ".$RX_TYPE;        //未知訊息型別
                    break;
            }
            echo $result;                                           //輸出回覆訊息,即 傳送微信。
        }else {
            echo "";
            exit;
        }
    }
//===================================================響應訊息二部曲開始,核心程式碼的核心===================================================
    //接收事件型別訊息——關注;取消關注;掃描帶引數二維碼;上報地理位置;自定義選單;點選選單拉取訊息;點選選單跳轉連結
    private function receiveEvent($object)                   //這裡的$object來自$postObj————包含解析了微信訊息 的物件
    {
        $content = "";                                       //為文字變數賦初值
        switch ($object->Event)                              //獲取事件型別
        {
            case "subscribe":                                    //1.關注事件
                $content = "歡迎關注柯南大學人民武裝學院官方微信公眾號,學院微訊號正處於開發者試驗階段,歡迎提出寶貴意見! ";//關注後回覆給使用者的訊息
                $content .= (!empty($object->EventKey))?("\n來自二維碼場景 ".str_replace("qrscene_","",$object->EventKey)):"";
                /*第二個content:高階功能,未關注公眾號時使用者掃描 帶引數二維碼 回覆內容
                break;
            case "unsubscribe":
                $content = "取消關注";                          //2.取消關注事件,可以不寫content
                break;
            case "SCAN":
                $content = "掃描場景 ".$object->EventKey;       //使用者已關注公眾號,掃描 帶引數二維碼 回覆內容。
                break;
            case "CLICK":                                       // 自定義選單事件之拉取訊息回覆
                switch ($object->EventKey)                      //點選選單拉取訊息,EventKey為 click型別 選單按鈕的key值
                {
                    case "jianjie":
                         $content = array();
                         $content[] = array("Title"=>"學院簡介","Description"=>"河南大學人民武裝學院,是河南省軍區與河南大學聯合創辦,我省唯一的人民武裝類高等院校。", "PicUrl"=>"http://henurenwu.duapp.com/images/xueyuan.jpg", "Url" =>"http://henurenwu.duapp.com/about/jianjie.html");
                         break;                               //點選"jianjie"click按鈕,設定推送 圖文訊息
                    case "gonggao":
                    	$content = "最新通告:\n\n恭喜我校本年度有38名同學考取研究生!\n\n更多公告請點選:\n\nhttp://henurenwu.duapp.com/gonggao/xueyuan_gonggao.html";
                    	break;                                //這裡超連結會點選跳轉
                    case "zhaopin":
                    	$content = "點選檢視最新招聘資訊\n\nhttp://henurenwu.duapp.com/zhaopin/2015-2-14.html";
                    	break;
                    case "yijianfankui":
                    	$content = "請用‘@+您的意見’的形式將你的意見傳送到公眾號:";
                    	break;
                    case "game2048":
                    	$content = "點選將跳轉到Game Box,盡情玩耍吧!(遊戲過程不消耗流量)<a href='http://henurenwu.duapp.com/GameBox/GameBox.html'>點選進入Game Box</a>";
                    	break;                                  //加入超連結符號後文字會添上超連結
                    default:
                        $content = "點選選單:".$object->EventKey; //沒有設定key和超連結的 空白按鈕,點選後回覆訊息
                        break;
                }
                break;
            case "LOCATION":                                     //地理位置事件——對公眾號傳送位置
                $content = "上傳位置:緯度 ".$object->Latitude.";經度 ".$object->Longitude;    //回覆地理位置
                break;
            case "VIEW":
                $content = "跳轉連結 ".$object->EventKey;        //自定義選單之跳轉連結事件——如果設定了連結就不會回覆這句話
                break;
            default:
                $content = "receive a new event: ".$object->Event;  //出現新的事件型別回覆訊息,目前還沒出現
                break;
        }
        if(is_array($content)){                                  //判斷$content是否為陣列型別——回覆資訊為圖文、音樂型別$content會是陣列格式,正好區分
            if (isset($content[0]['PicUrl'])){                   //圖文訊息,[0]['PicUrl']:第一條訊息的PicUrl列;[1]['PicUrl']表示第二條訊息的PicUrl列
                $result = $this->transmitNews($object, $content);//呼叫 傳輸圖文 方法,將包含訊息的$postObj,回覆訊息$content進行傳參
            }else if (isset($content['MusicUrl'])){              //isset():引數存在且非空時為true
                $result = $this->transmitMusic($object, $content);//呼叫 傳輸音樂 方法
            }
        }else{
            $result = $this->transmitText($object, $content);     //呼叫 傳輸文字 方法
        }
        return $result;                                           //返回結果
    }

    //接收文字訊息
    private function receiveText($object)
    {
        switch ($object->Content)                                  // 關鍵字回覆
        {
            case "文字":                                           //使用者傳送內容是“文字”
                $content = "這是個文字訊息";                       //回覆訊息
                break;
            case "圖文":
            case "單圖文":                                         //使用者傳送內容為“單圖文”
                $content = array();                                //圖文訊息需先建立陣列
                $content[] = array("Title"=>"單圖文標題",  "Description"=>"單圖文內容", "PicUrl"=>"http://discuz.comli.com/weixin/weather/icon/cartoon.jpg", "Url" =>"http://m.cnblogs.com/?u=txw1958");                    //單圖文,只寫一個$content,裡面的內容是根據 文字訊息XML資料格式 編寫
                break;
            case "多圖文":
                $content = array();
                $content[] = array("Title"=>"多圖文1標題", "Description"=>"", "PicUrl"=>"http://discuz.comli.com/weixin/weather/icon/cartoon.jpg", "Url" =>"http://m.cnblogs.com/?u=txw1958");
                $content[] = array("Title"=>"多圖文2標題", "Description"=>"", "PicUrl"=>"http://d.hiphotos.bdimg.com/wisegame/pic/item/f3529822720e0cf3ac9f1ada0846f21fbe09aaa3.jpg", "Url" =>"http://m.cnblogs.com/?u=txw1958");
                $content[] = array("Title"=>"多圖文3標題", "Description"=>"", "PicUrl"=>"http://g.hiphotos.bdimg.com/wisegame/pic/item/18cb0a46f21fbe090d338acc6a600c338644adfd.jpg", "Url" =>"http://m.cnblogs.com/?u=txw1958");
                break;                                            //多圖文,最多10條
            case "音樂":
                $content = array("Title"=>"最炫民族風", "Description"=>"歌手:鳳凰傳奇", "MusicUrl"=>"http://121.199.4.61/music/zxmzf.mp3", "HQMusicUrl"=>"http://121.199.4.61/music/zxmzf.mp3");                          //音樂,和單圖文結構相近,陣列內容根據 音樂訊息XML資料格式 編寫
                break;
            case "@":                                           //傳送訊息包含@符號
            	$content = "感謝您的反饋,讓我們一同建設美好的校園!";//回覆文字訊息
            	break;
            default:                                            //傳送文字內容不在上述內容,預設回覆以下訊息
                $content = "請回復其它關鍵詞/從選單獲取資訊\n\n".date("Y-m-d H:i:s",time())."\n河南大學人民武裝學院";
                break;
        }
        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 receiveImage($object)
    {
        $content = array("MediaId"=>$object->MediaId);                    //使用者向公眾號傳送圖片訊息,提取媒體ID。所有的$content都供傳參到XML資料中使用
        $result = $this->transmitImage($object, $content);                //呼叫 傳輸圖片 方法
        return $result;
    }

    //接收位置訊息
    private function receiveLocation($object)
    {
        $content = "你傳送的是位置,緯度為:".$object->Location_X.";經度為:".$object->Location_Y.";縮放級別為:".$object->Scale.";位置為:".$object->Label;                                                                    //從$object物件(=$postObj物件)獲取位置引數
        $result = $this->transmitText($object, $content);                //呼叫 傳輸文字 方法
        return $result;
    }

    //接收語音訊息
    private function receiveVoice($object)
    {
        if (isset($object->Recognition) && !empty($object->Recognition)){       //使用者傳送的語音訊息,能夠識別且識別結果非空(公眾號需開通語音識別功能)
            $content = "你剛才說的是:".$object->Recognition;                   //回覆文字,將識別結果回覆給使用者
            $result = $this->transmitText($object, $content);                   //呼叫 回覆文字 方法
        }else{
            $content = array("MediaId"=>$object->MediaId);               //建立陣列,內容"MediaId",資料來源:語音訊息的MediaId
            $result = $this->transmitVoice($object, $content);           //呼叫 傳輸語音 方法
        }

        return $result;
    }

    //接收視訊訊息
    private function receiveVideo($object)
    {
        $content = array("MediaId"=>$object->MediaId, "ThumbMediaId"=>$object->ThumbMediaId, "Title"=>"", "Description"=>"");
        $result = $this->transmitVideo($object, $content);
        return $result;
    }

    //接收連結訊息
    private function receiveLink($object)
    {
        $content = "你傳送的是連結,標題為:".$object->Title.";內容為:".$object->Description.";連結地址為:".$object->Url;
        $result = $this->transmitText($object, $content);
        return $result;
    }
//====================================================修改程式碼三部曲,官方文件上臺========================================================
    //回覆文字訊息
    private function transmitText($object, $content)           //以下XML資料格式由微信規定,不可更改
    {
        $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);
<pre name="code" class="php">/*將xml格式中的資料分別賦值;
sprintf()為變參函式:第一個引數$textTpl表示對它改變引數;
第二個引數叫$fromUsername(它存的是使用者的OpenID),因為資料傳輸方向掉頭了——原來是使用者給伺服器傳送訊息,ToUserName表示伺服器;現在伺服器要傳送資料給使用者(OpenID),ToUserName表示使用者;
第三個引數和第二個引數道理一樣;
第四個引數$time:訊息建立時間;
第五個引數:訊息型別,這裡表示文字;
第六個引數:訊息內容:伺服器向用戶傳送的訊息
*/
return $result; } 
//回覆圖片訊息
    private function transmitImage($object, $imageArray)
    {
        $itemTpl = "<Image>
    <MediaId><![CDATA[%s]]></MediaId>                 //其它資料型別都有獨有的部分,獨有的部分從前面傳參得到
</Image>";


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


        $textTpl = "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>              //當然也有通用的部分
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[image]]></MsgType>
$item_str                                           //將獨有的部分放置在合適的位置,不能破壞微信文件規定的格式。以下類同
</xml>";


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


    //回覆語音訊息
    private function transmitVoice($object, $voiceArray)
    {
        $itemTpl = "<Voice>
    <MediaId><![CDATA[%s]]></MediaId>
</Voice>";


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


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


        $result = sprintf($textTpl, $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']);


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


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


    //回覆圖文訊息
    private function transmitNews($object, $newsArray)
    {
        if(!is_array($newsArray)){
            return;
        }
        $itemTpl = "    <item>
        <Title><![CDATA[%s]]></Title>
        <Description><![CDATA[%s]]></Description>
        <PicUrl><![CDATA[%s]]></PicUrl>
        <Url><![CDATA[%s]]></Url>
    </item>
";
        $item_str = "";
        foreach ($newsArray 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($newsArray));
        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;
    }

===================================================結尾小結===============================================================

總結一下,整體來看基礎的訊息處理程式碼都在這裡了,用圖片對整體再進行了解一下

我用註釋的方式進行講解,對大家查閱程式碼造成一定不便請大家諒解。

有問題或願意共同進行微信公眾平臺開發研究的夥伴請聯絡郵箱:[email protected],歡迎!

因為之前反覆修改,導致內容錯亂,2015年2月25日00:46:47重新修改。