1,326   WordPress

WP自定义插件之前已经说过,这里着重讲述如何制作微信订阅号插件。

 

一,实现效果

 

1,用户在微信订阅号里输入任意内容;
2,微信服务器收到用户内容后,通过POST方式推送到WP服务器
3,WP根据微信推送过来的内容,进行文章搜索,然后把搜索到的文章返回给微信服务器;
4,微信服务器再把WP服务器返回的内容,发给指定用户;

其实就是把WP的搜索功能移植到微信订阅号中,非常简单的功能,只为了熟悉微信公众账号的开发流程

 

二,实现流程:首次验证

 

接入微信公众平台开发,在基本配置中,需要进行首次验证,保证服务器的可用性,详情请看这里:接入指南

 

1,在WP添加微信插件,在/wp-content/plugins新建微信插件目录luckybirdWeixin,在该luckybirdWeixin目录下新建微信插件文件luckybirdWeixin.php,并添加以下内容

 

/*
Plugin Name: luckybirdWeixin
Plugin URI: http://www.luckybird.me
Description: luckybirdWeixin
Version: 1.0
Author: luckybird
Author URI: http://www.luckybird.me
*/

// 挂载插件
add_action('init', 'luckybirdWeixin_init', 11);

// 调用插件
function luckybirdWeixin_init(){
    //define your token
    define("TOKEN", "weixin_token");
    $wechatObj = new luckybirdWeixin();
    $wechatObj->callBack();
}


class luckybirdWeixin{


    public function callBack(){
        if($this->checkSignature()){
	    // 信息推送,用POST方式
            if($_SERVER['REQUEST_METHOD'] == 'POST'){
                $this->responseMsg();
            }else{
		// 首次验证,用GET方式
                $this->valid();
            }
            exit;
        }

    }
    // 日志记录
    private function my_web_log($message){
        $file = '/var/log/test/luckybird-weixin.log';
        list($micro_second, $unix_time) = explode(" ", microtime());
        $log = '';
        $log .= date("Y-m-d H:i:s").' '.$micro_second;
        $log .= ' '.$_SERVER['SCRIPT_NAME'];
        $log .= ' '.$message;
        $log .="\r\n";
        error_log($log, 3,$file);
    }



    // 首次验证
    private function valid(){
        $echoStr = isset($_GET["echostr"])?$_GET["echostr"]:'';

        //valid signature , option
        echo $echoStr;
        
    }

   // 检验token
    private function checkSignature(){
        // you must define TOKEN by yourself
        if (!defined("TOKEN")) {
            throw new Exception('TOKEN is not defined!');
        }
        
        $signature = isset($_GET["signature"])?$_GET["signature"]:'';
        $timestamp = isset($_GET["timestamp"])?$_GET["timestamp"]:'';
        $nonce = isset($_GET["nonce"])?$_GET["nonce"]:'';

        $this->my_web_log('signature:'.$signature.',nonce:'.$nonce.',timestamp:'.$timestamp);

	$token = TOKEN;
	$tmpArr = array($token, $timestamp, $nonce);
	// use SORT_STRING rule
	sort($tmpArr, SORT_STRING);
	$tmpStr = implode( $tmpArr );
	$tmpStr = sha1( $tmpStr );
	
	if( $tmpStr == $signature ){
		return true;
	}else{
		return false;
	}
	}
}


2,在WP后台激活这个插件之后,就可以到微信订阅号的开发模式那里,进行服务器配置了,如下图所示

 

 

506110254

 

 

 

其中Token要与插件的Token对应,这是为了验证请求的合法性;

 

 

3,点击提交之后,微信服务器会发起GET方式的验证,你可以查看访问记录,类似以下格式,不出意外,应该可以验证通过了

 

 "GET /?signature=f94f50d995bc68895f58b5b99a5f5213ee10b98d&echostr=2489446644151205758&timestamp=1421708400&nonce=1233976199 HTTP/1.0" 200 19 "-" "Mozilla/4.0" "-"

 

 

三,实现过程:信息推送
首先接收微信服务器推送过来的信息,然后对信息进行解释,接着根据信息搜索文章内容,最后按照特定格式返回给微信服务器,微信会自动发送给对用户

 

1,接收微信服务器推送过来的信息,这里只演示接收text类型的信息,更多信息累心参考微信官网文档
在luckybirdWeixin.php文件的luckybirdWeixin类中添加以下方法,来获取微信推送过来的内容,转化为对象

    

   // 微信发送过来的内容
    private function getRequest(){
        //get post data, May be due to the different environments
        $postStr = isset($GLOBALS["HTTP_RAW_POST_DATA"])?$GLOBALS["HTTP_RAW_POST_DATA"]:'';
        $this->my_web_log('postStr:'.$postStr);
        //extract post data
        $request = NULL;
        if (!empty($postStr)){
                /* libxml_disable_entity_loader is to prevent XML eXternal Entity Injection,
                   the best way is to check the validity of xml by yourself */

                libxml_disable_entity_loader(true);
                $request = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
                

        }
        return $request;
    }

 

 

2,根据微信推送过来的内容,在WP中搜索文章,添加以下方法

 

 

    // 查询文章
    private function query($keyword){
        $items = array();

        $post_number = 6;

        $post_types = get_post_types( array('exclude_from_search' => false) );
        unset($post_types['page']);
        unset($post_types['attachment']);

        $weixin_query_array = array(
            's'                     => $keyword, 
            'ignore_sticky_posts'   => true,
            'posts_per_page'        => $post_number, 
            'post_status'           => 'publish',
            'post_type'             => $post_types
        );


        global $wp_the_query;
        $wp_the_query->query($weixin_query_array);


        if($wp_the_query->have_posts()){
            while ($wp_the_query->have_posts()) {
                $wp_the_query->the_post();

                $Title  = get_the_title();
                $Description = $Title;
                $PicUrl = 'http://www.luckybird.me/wp-content/uploads/2014/04/20141102234845_s854Y-203x300.jpeg';
                $Url = get_permalink();

                $items[] = array(
                    'Title'=>$Title,
                    'Description'=>$Description,
                    'PicUrl'=>$PicUrl,
                    'Url'=>$Url);

            }
        }

        return $items;
    }

 

 

 

3,按照特定格式,把搜索到的文章内容,返回给微信服务器,详细信息格式请查看微信文档,信息格式组装方法如下:

 

 

 // 回复模板
 private function getBaseTpl($request){
 return "<ToUserName><![CDATA[".$request->FromUserName."]]></ToUserName>
 <FromUserName><![CDATA[".$request->ToUserName."]]></FromUserName>
 <CreateTime>".time()."</CreateTime>";
 }
 // 图文模板
 private function getPicTpl($request,$items){

 $items_str="";
 if($items){
 foreach($items as $item){
 $items_str.="<item>
 <Title><![CDATA[".$item['Title']."]]></Title> 
 <Description><![CDATA[".$item['Description']."]]></Description>
 <PicUrl><![CDATA[".$item['PicUrl']."]]></PicUrl>
 <Url><![CDATA[".$item['Url']."]]></Url>
 </item>";
 }
 }
 $baseTpl = $this->getBaseTpl($request);
 return "<xml>".$baseTpl."
 <MsgType><![CDATA[news]]></MsgType>
 <ArticleCount>".count($items)."</ArticleCount>
 <Articles>".$items_str."</Articles>
 </xml>";
 }

4,将以上流程和方法整合在一起

 

 

    // 推送信息
    private function responseMsg(){
        $request = $this->getRequest();
        $response = '';
        
        $keyword = strtolower(trim($request->Content));
        $items = $this->query($keyword);
        $response = $this->getPicTpl($request,$items);
        $this->my_web_log('response:'.$response);
        echo $response;
    }

 

 

5,到这里,整个微信订阅号的插件已经开放完毕,下面来看看测试效果吧

 

06113148

 

 

完整代码如下:

/*
Plugin Name: luckybirdWeixin
Plugin URI: http://www.luckybird.me
Description: luckybirdWeixin
Version: 1.0
Author: luckybird
Author URI: http://www.luckybird.me
*/

// 挂载插件
add_action('init', 'luckybirdWeixin_init', 11);

// 调用插件
function luckybirdWeixin_init(){
 //define your token
 define("TOKEN", "weixin_token");
 $wechatObj = new luckybirdWeixin();
 $wechatObj->callBack();
}


class luckybirdWeixin{


 public function callBack(){
 if($this->checkSignature()){
 // 信息推送,用POST方式
 if($_SERVER['REQUEST_METHOD'] == 'POST'){
 $this->responseMsg();
 }else{
 // 首次验证,用GET方式
 $this->valid();
 }
 exit;
 }

 }
 // 日志记录
 private function my_web_log($message){
 $file = '/var/log/test/luckybird-weixin.log';
 list($micro_second, $unix_time) = explode(" ", microtime());
 $log = '';
 $log .= date("Y-m-d H:i:s").' '.$micro_second;
 $log .= ' '.$_SERVER['SCRIPT_NAME'];
 $log .= ' '.$message;
 $log .="\r\n";
 error_log($log, 3,$file);
 }

 // 推送信息
 private function responseMsg(){
 $request = $this->getRequest();
 $response = '';
 
 $keyword = strtolower(trim($request->Content));
 $items = $this->query($keyword);
 $response = $this->getPicTpl($request,$items);
 $this->my_web_log('response:'.$response);
 echo $response;
 }

 // 查询文章
 private function query($keyword){
 $items = array();

 $post_number = 6;

 $post_types = get_post_types( array('exclude_from_search' => false) );
 unset($post_types['page']);
 unset($post_types['attachment']);

 $weixin_query_array = array(
 's' => $keyword, 
 'ignore_sticky_posts' => true,
 'posts_per_page' => $post_number, 
 'post_status' => 'publish',
 'post_type' => $post_types
 );


 global $wp_the_query;
 $wp_the_query->query($weixin_query_array);


 if($wp_the_query->have_posts()){
 while ($wp_the_query->have_posts()) {
 $wp_the_query->the_post();

 $Title = get_the_title();
 $Description = $Title;
 $PicUrl = 'http://www.luckybird.me/wp-content/uploads/2014/04/20141102234845_s854Y-203x300.jpeg';
 $Url = get_permalink();

 $items[] = array(
 'Title'=>$Title,
 'Description'=>$Description,
 'PicUrl'=>$PicUrl,
 'Url'=>$Url);

 }
 }

 return $items;
 }

 // 回复模板
 private function getBaseTpl($request){
 return "<ToUserName><![CDATA[".$request->FromUserName."]]></ToUserName>
 <FromUserName><![CDATA[".$request->ToUserName."]]></FromUserName>
 <CreateTime>".time()."</CreateTime>";
 }
 // 图文模板
 private function getPicTpl($request,$items){

 $items_str="";
 if($items){
 foreach($items as $item){
 $items_str.="<item>
 <Title><![CDATA[".$item['Title']."]]></Title> 
 <Description><![CDATA[".$item['Description']."]]></Description>
 <PicUrl><![CDATA[".$item['PicUrl']."]]></PicUrl>
 <Url><![CDATA[".$item['Url']."]]></Url>
 </item>";
 }
 }
 $baseTpl = $this->getBaseTpl($request);
 return "<xml>".$baseTpl."
 <MsgType><![CDATA[news]]></MsgType>
 <ArticleCount>".count($items)."</ArticleCount>
 <Articles>".$items_str."</Articles>
 </xml>";
 }

 // 微信发送过来的内容
 private function getRequest(){
 //get post data, May be due to the different environments
 $postStr = isset($GLOBALS["HTTP_RAW_POST_DATA"])?$GLOBALS["HTTP_RAW_POST_DATA"]:'';
 $this->my_web_log('postStr:'.$postStr);
 //extract post data
 $request = NULL;
 if (!empty($postStr)){
 /* libxml_disable_entity_loader is to prevent XML eXternal Entity Injection,
 the best way is to check the validity of xml by yourself */

 libxml_disable_entity_loader(true);
 $request = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
 

 }
 return $request;
 }

 // 首次验证
 private function valid()
 {
 $echoStr = isset($_GET["echostr"])?$_GET["echostr"]:'';

 //valid signature , option
 echo $echoStr;
 
 }

 // 检验token
 private function checkSignature()
 {
 // you must define TOKEN by yourself
 if (!defined("TOKEN")) {
 throw new Exception('TOKEN is not defined!');
 }
 
 $signature = isset($_GET["signature"])?$_GET["signature"]:'';
 $timestamp = isset($_GET["timestamp"])?$_GET["timestamp"]:'';
 $nonce = isset($_GET["nonce"])?$_GET["nonce"]:'';

 $this->my_web_log('signature:'.$signature.',nonce:'.$nonce.',timestamp:'.$timestamp);

 $token = TOKEN;
 $tmpArr = array($token, $timestamp, $nonce);
 // use SORT_STRING rule
 sort($tmpArr, SORT_STRING);
 $tmpStr = implode( $tmpArr );
 $tmpStr = sha1( $tmpStr );
 
 if( $tmpStr == $signature ){
 return true;
 }else{
 return false;
 }
 }
}





Leave a Reply

Your email address will not be published. Required fields are marked *