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后台激活这个插件之后,就可以到微信订阅号的开发模式那里,进行服务器配置了,如下图所示

其中Token要与插件的Token对应,这是为了验证请求的合法性;
3,点击提交之后,微信服务器会发起GET方式的验证,你可以查看访问记录,类似以下格式,不出意外,应该可以验证通过了
"GET /?signature=f94f50d995bc68895f58b5b99a5f5213ee10b98d&echostr=2489446644151205758×tamp=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,到这里,整个微信订阅号的插件已经开放完毕,下面来看看测试效果吧

完整代码如下:
/* 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