如何使用開發者服務器運維微信公衆號

很多人都有自己的服務器,特別是對於大學生而言,很多服務器公司都對學生有優惠,例如騰訊雲只要1元每月:http://blog.csdn.net/tiandixuanwuliang/article/details/56494528 ,那麼我們作爲一名程序員,總想把一切掌控在自己手中,<哈哈>,那麼如何使用我們開發者服務器去管理微信公衆號呢?這就是本文介紹的內容。
本文介紹以下內容:

  • (1)如何把微信公衆號授權給開發者服務器
  • (2)如何使用代碼把開發者服務器與微信服務器進行關聯
  • (3)實現接受和發送消息
  • (4)自定義菜單

1 如何把微信公衆號授權給開發者服務器

  • (1)進入微信公衆號平臺,https://mp.weixin.qq.com/,首先請取消其他第三方服務器的授權,方法如下:
    這裏寫圖片描述
    這裏寫圖片描述
    這裏寫圖片描述
    注:這裏也可以不取消第三方服務器的授權,不取消的話,公衆號粉絲髮送的數據會同時1發送到第三方服務器和開發者服務器,本人已經驗證了,有興趣可以自行研究
  • (2)回到微信公衆號管理平臺首頁,頁面往下拉,選擇“基本配置”,如圖:
    這裏寫圖片描述
  • (3)添加ip白名單
    這裏寫圖片描述
  • (4)選擇修改配置
    這裏寫圖片描述
  • (5)下圖中的url,指向你自己的服務器中正在運行的php地址,這是本文代碼開發的重點,具體內容請看下一章。token可以隨便寫,但是需要與上述php文件中配置的一樣,具體內容請看下一章
    這裏寫圖片描述

2 如何使用代碼把開發者服務器與微信服務器進行關聯

  • (0)這一章講解代碼的開發。第一章第5小節中的url指向自己的服務器中正在運行的php文件,本章將介紹這一個文件的內容。關於如何運行這個php文件,請看php教程http://blog.csdn.net/tiandixuanwuliang/article/category/7344088
  • (1)該php文件內容如下,下面的代碼實現了連接開發者服務器、關鍵字回覆、圖靈機器人功能,注:請把下面的token填寫爲第一章第5小節中截圖中設置的token
<?php
/**
 * 微信公衆號開發-入門
 *
 * api
 */
define("TOKEN",'we--xxxx');   //這裏和你微信公衆號開放平臺上的tonken填寫一樣的即可
$weixinApi=new WeixinApi();
if(isset($_GET["echostr"])){
    $weixinApi->valid();
}else{
    $weixinApi->responseMsg();
}

class WeixinApi{
    //驗證接口
    public function valid(){
        $echoStr = $_GET["echostr"];//從微信用戶端獲取一個隨機字符賦予變量echostr
        if($this->checkSignature()){
            echo $echoStr;
            exit;
        }
    }
    //檢查簽名
    private function checkSignature(){
        //1 接受微信服務器get請求發送過來的4個參數
        $signature = $_GET["signature"];//從用戶端獲取簽名賦予變量signature
        $timestamp = $_GET["timestamp"];//從用戶端獲取時間戳賦予變量timestamp
        $nonce = $_GET["nonce"];    //從用戶端獲取隨機數賦予變量nonce
        //2 加密和校驗請求
        //2.1 將token、timestamp、nonce三個參數進行字典序排序
        $tmpArr = array(TOKEN, $timestamp, $nonce);//簡歷數組變量tmpArr
        sort($tmpArr, SORT_STRING);//新建排序
        //2.2 將三個參數字符串拼接成一個字符串進行sha1加密
        $tmpStr = implode($tmpArr);//數組轉字符串
        $tmpStr = sha1($tmpStr);//shal加密
        //2.3 開發者獲得加密後的字符串可與signature對比,標識該請求來源於微信
        if ($tmpStr == $signature) {
            return true;
        } else {
            return false;
        }
    }
    //回覆消息
    public function responseMsg(){
        //3 以下代碼接受消息
        //3.1 接受微信服務器發送過來的原生的POST的數據包
//        $postData = $GLOBALS["HTTP_RAW_POST_DATA"];
        $postData = isset($GLOBALS['HTTP_RAW_POST_DATA']) ? $GLOBALS['HTTP_RAW_POST_DATA'] :file_get_contents("php://input");

        //3.2 處理數據包
        $xmlObj = simplexml_load_string($postData, "SimpleXMLElement", LIBXML_NOCDATA);
        $msgType = $xmlObj->MsgType;
        //4 根據消息類型進行業務處理
        switch ($msgType) {
            //接受事件消息
            case 'event':
                $this->disposeEvent($xmlObj);
                break;
            //接受文本消息
            case 'text':
                $this->disposeText($xmlObj);
                break;
            //接受圖片消息
            case 'image':
                $this->disposeImage($xmlObj);
                break;
        }
    }
    //處理接收的事件消息
    private function disposeEvent($xmlObj){
        switch ($xmlObj->Event){
            case 'subscribe'://訂閱事件
                $this->sendText('歡迎您的訂閱');
                break;
            case 'unsubscribe'://取消訂閱事件
                $this->sendText('good-bye');//該消息用戶其實是看不到的,取消訂閱事件一般用來清除數據庫記錄
                break;
        }
    }
    //處理接收的文本消息
    private function disposeText($xmlObj){
        $text=trim($xmlObj->Content);
        //包含關鍵字都不做處理
        if (!(
            strstr($text,'違規')    //這裏對違規的關鍵字做排除,不予理睬
        )){
            switch ($text){
                case '你好':
                    $this->sendText($xmlObj,'Hi 我是開發者服務器');
                    break;
                case 'new':
                    $newsArr=array(
                        array(
                            "title"=>"看到這條消息,你可以買彩票了",
                            "description"=>"本公衆號有許多小彩蛋,歡迎您的探索。",
                            "picUrl"=>"http://img.mp.itc.cn/upload/20170610/03d69e8df0524b8cb59fd16dc2fec989.jpg",
                            "url"=>"http://www.baidu.com"
                        )
                    );
                    $this->sendNews($xmlObj,$newsArr);
                    break;
                default:
                    $this->tuling123($xmlObj,trim($xmlObj->Content));   //圖靈機器人
            }
        }
    }
    //處理接收的圖片消息
    private function disposeImage($xmlObj){    //一般情況下,不會去處理用戶發送的圖片
        $this->sendImage($xmlObj,$xmlObj->PicUrl,$xmlObj->MediaId);
    }

    //發送文本的方法
    private function sendText($xmlObj,$content){
        $replyTextMsg="<xml>
                        <ToUserName><![CDATA[%s]]></ToUserName>
                        <FromUserName><![CDATA[%s]]></FromUserName>
                        <CreateTime>%s</CreateTime>
                        <MsgType><![CDATA[text]]></MsgType>
                        <Content><![CDATA[%s]]></Content>
                    </xml>";
        echo sprintf($replyTextMsg,$xmlObj->FromUserName,$xmlObj->ToUserName,time(),$content);
    }
    //發送圖片的方法
    private function sendImage($xmlObj,$mediaId){
        $replyImageMsg="<xml>
                        <ToUserName><![CDATA[%s]]></ToUserName>
                        <FromUserName><![CDATA[%s]]></FromUserName>
                        <CreateTime>%s</CreateTime>
                        <MsgType><![CDATA[image]]></MsgType>
                        <Image>
                            <MediaId><![CDATA[%s]]></MediaId>
                        </Image>
                    </xml>";
        echo sprintf($replyImageMsg,$xmlObj->FromUserName,$xmlObj->ToUserName,time(),$mediaId);
    }
    //發送圖文的方法
    private function sendNews($xmlObj,$newsArr){
        $newsTplHead = "<xml>
                        <ToUserName><![CDATA[%s]]></ToUserName>
                        <FromUserName><![CDATA[%s]]></FromUserName>
                        <CreateTime>%s</CreateTime>
                        <MsgType><![CDATA[news]]></MsgType>
                        <ArticleCount>%s</ArticleCount>
                        <Articles>";
        $newsTplBody = "<item>
                        <Title><![CDATA[%s]]></Title> 
                        <Description><![CDATA[%s]]></Description>
                        <PicUrl><![CDATA[%s]]></PicUrl>
                        <Url><![CDATA[%s]]></Url>
                    </item>";
        $newsTplFoot = "</Articles>
                    <FuncFlag>%s</FuncFlag>
                </xml>";
        $replyNewsMsg = sprintf($newsTplHead, $xmlObj->FromUserName, $xmlObj->ToUserName, time(),count($newsArr));
        foreach($newsArr as $key => $value){
            $replyNewsMsg .= sprintf($newsTplBody, $value['title'], $value['description'], $value['picUrl'], $value['url']);
        }
        $replyNewsMsg  .= sprintf($newsTplFoot, 0);
        echo $replyNewsMsg;
    }

    public function tuling123($xmlObj,$message){//這是是使用圖靈機器人
        $tuTonken='2d8aaa17141c443----xxx---fsa';   //請去圖靈網http://www.tuling123.com/自己申請一個tonken
        $tuUrl='http://www.tuling123.com/openapi/api?key='.$tuTonken.'&info='.$message.'&userid='.$xmlObj->FromUserName;
        $tuData='{  
            "key": "'.$tuTonken.'", 
            "info": "'.$message.'",
            "userid": "'.$xmlObj->FromUserName.'" 
            }';
        $results = $this->htts_request($tuUrl,$tuData);
//        print_r($results);
        if ($results['code']==100000){
            $text=$results['text'];
            $this->sendText($xmlObj,$text);
        }else{
            $this->sendText($xmlObj,'有問題,請輸入“幫助”');
        }
    }

    //https請求(get和post)
    private function htts_request($url,$data=array()){
        //1 初始化curl
        $ch=curl_init();
        //2 設置傳輸選項
        curl_setopt($ch,CURLOPT_URL,$url);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);//把頁面以文件流的形式返回
        if (!empty($data)) {
            curl_setopt($ch, CURLOPT_POST, true); //設置爲 POST 請求
            curl_setopt($ch, CURLOPT_POSTFIELDS, $data); //設置POST的請求數據
        }
        //3 執行curl請求
        $outopt=curl_exec($ch);
        $outoptArr=json_decode($outopt,true);
        //4 關閉curl
        curl_close($ch);
        return $outoptArr;
    }
}
?>
  • (2)上面代碼可以用下面的結構圖進行分析:
    這裏寫圖片描述
  • (3)下面是自定義菜單的代碼(不建議使用,原因請看下面的第5小節)
//獲取access_token
    private function getAccessToken(){
        //獲取微信接口憑證
        $appid="wxb4----xxx";//請在第一章第5小節的圖片中看
        $appsecret="21d---xxx";//請在第一章第5小節的圖片中看

        $data=json_decode(file_get_contents('./access_token.json'));
        if ($data->expires_time <time()){
            $url="https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={$appid}&secret={$appsecret}";
            $outoptArr=$this->htts_request($url,array(),false);
            $access_token=$outoptArr['access_token'];
            if (!empty($access_token)){
                //把access_token寫入文件
                $data->access_token=$outoptArr['access_token'];
                $data->expires_time=time()+7000;
                $fp=fopen('access_token.json','w');
                fwrite($fp,json_encode($data));
                fclose($fp);
            }else{
                echo '請求access_token錯誤';
            }
        }else{
            $access_token=$data->access_token;
        }
//        echo $access_token;
        return $access_token;
    }
//實現自定義菜單
    public function menu_create(){
        $access_token=$this->getAccessToken();
        $url="https://api.weixin.qq.com/cgi-bin/menu/create?access_token={$access_token}";
        $data='{
        "button": [
            {
                "type": "click",
                "name": "java",
                "key": "learn_java"
            },
            {
                "name":"chengxu",
                "sub_button":[
                {
                    "type": "view",
                    "name": "CSDN",
                    "url": "http://blog.csdn.net/tiandixuanwuliang/"
                },
                {
                    "type": "view",
                    "name": "Github",
                    "url": "https://github.com/wllfengshu/"
                },
                {
                    "type": "view",
                    "name": "jianshu",
                    "url": "https://www.jianshu.com/users/4d12e03d0a5f/timeline/"
                },
                {
                    "type": "view",
                    "name": "kaifazhe",
                    "url": "https://toutiao.io/u/431066/"
                },
                {
                    "type": "view",
                    "name": "yuyan",
                    "url": "http://www.baidu.com"
                }]
            },
            {
                "name":"jiaoliu",
                "sub_button":[
                {
                    "type": "view",
                    "name": "shuji",
                    "url": "http://blog.csdn.net/tiandixuanwuliang/"
                },
                {
                    "type": "view",
                    "name": "ziyuan",
                    "url": "https://github.com/wllfengshu/"
                },
                {
                    "type": "view",
                    "name": "sucai",
                    "url": "https://www.jianshu.com/users/4d12e03d0a5f/timeline/"
                },
                {
                    "type": "view",
                    "name": "daxuesheng",
                    "url": "https://toutiao.io/u/431066/"
                },
                {
                    "type": "click",
                    "name": "zuozhe",
                    "key": "about_author"
                }]
            }
        ]
    }';
        echo $url." ///// ".$data;
        $outoptArr=$this->htts_request($url,json_decode($data,true),true);
        echo '***';
        print_r($outoptArr);
    }
  • (4)下面是網頁授權,授權後我們纔可以在代碼中調用(不建議使用,原因請看下面的第5小節)
    //網頁授權-base型
    public function snsapi_base($redirect_uri){
        //以下是測試賬號
        $appid="wxb4----xxx";//請在第一章第5小節的圖片中看
        $appsecret="21da56-----xxx";//請在第一章第5小節的圖片中看

        //準備scope
        $snsapi_base_url="https://open.weixin.qq.com/connect/oauth2/authorize?appid={$appid}&redirect_uri={$redirect_uri}&response_type=code&scope=SCOPE&state=123#wechat_redirect";
        $code=$_GET['code'];
        //獲取code
        if (!isset($code)){
            header("Location:{$snsapi_base_url}");
        }
        //獲取access_token
        $url="https://api.weixin.qq.com/sns/oauth2/access_token?appid={$appid}&secret={$appsecret}&code={$code}&grant_type=authorization_code";
        return $this->htts_request($url);
    }
  • (5)但是由於個人註冊的訂閱號沒有自定義菜單的開發權限,所以我建議大家自定義菜單的功能交給第三方服務處理,這也是一個竅門,就是微信公衆號同時授權給第三方服務器和開發者服務器,這是一個bug,哈哈。請注意,一定要先授權給開發者服務器,再授權給第三方服務器,否則將不成功。原理圖如下:
    這裏寫圖片描述
    • 上圖中的第三方服務器具有關鍵字功能,我建議一些常用的關鍵字都交給第三方服務器做。一些具有邏輯性的關鍵字、需要存放到數據庫的關鍵字、或者私密性的關鍵字可以由開發者服務器做。但是由於微信公衆號粉絲髮送的數據會同時發送到兩個服務器,而且開發者服務器還具有圖靈機器人功能,可以採取屏蔽的方法,在任意一方屏蔽一次,這樣就避免了一條消息,回覆了兩次的問題。
  • (6)請把上述php文件,放到AppServ軟件安裝的根目錄下的www文件夾下,然後重啓AppServ中的服務,最後再把 http://服務器ip地址/index.php 填寫到第一章第5節的url中即可。可以開始玩了
    這裏寫圖片描述

本文地址:http://blog.csdn.net/tiandixuanwuliang/article/details/79438662

歡迎大家看我的另一篇文章,這篇文章從需求分析、系統設計、代碼實現等方面進行講解,歡迎大家批評指正,http://blog.csdn.net/tiandixuanwuliang/article/details/79438738

歡迎大家關注,裏面有很多資源分享:
這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章