微信公众平台接口尝试——微信订阅号被动回复

为提升阅读效率,本文章默认禁用思源宋体

在寒假里接触了多方之间互相交换信息的方法以及其具体接口,譬如Servlet(JSP)与安卓设备通过Json来相互传递通讯,并借助对Mysql数据库来实现相关的业务功能;使用Python通过request扩展来爬取Api的Json数据并进行Mysql数据库记录。

可以说以上代表的两大阵营——Java和Python以及一种流行的数据交换格式——Json,我已经熟练地掌握了主要的逻辑功能和实现方法,这在很大程度上归功于出色的IDE支持,在本地我就能进行十分全面的测试工作,部署在服务器端运行时也有详细的日志来参考,然而今天面对的却是全然陌生的PHP语言和XML交换格式。

需求与背景

  • 计划实现的对微信订阅号中用户的交互行为通过自建的服务器接口API进行处理并实现相应的业务功能;
  • 初步计划实现当用户回复“xmr”时,服务器对数据库中数据表mine_log的最新记录以及两小时内统计数据返回至用户;
  • 需求来自最近尝试的XMR挖矿资源的监控;

二 代码实现

<?php
header('content-type:text/html;charset=utf-8');
 
define("TOKEN", "*****"); //define your token
$wx = new wechatCallbackapiTest();
 
if($_GET['echostr']){
 $wx->valid(); //如果发来了echostr则进行验证
}else{
 $wx->responseMsg(); //如果没有echostr,则返回消息
}
 
 
class wechatCallbackapiTest{
 
 public function valid(){ //valid signature , option
 
  $echoStr = $_GET["echostr"];
  if($this->checkSignature()){ //调用验证字段
   echo $echoStr;
   exit;
  }
 }
 
 public function responseMsg(){
 //get post data, May be due to the different environments
  //$postStr = $GLOBALS["HTTP_RAW_POST_DATA"]; //接收微信发来的XML数据
   $postStr=file_get_contents('php://input');

  //extract post data
 if(!empty($postStr)){
     
   //解析post来的XML为一个对象$postObj
   $postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
   //file_put_contents('abc.log', "/".$postObj->Content, FILE_APPEND);
   $fromUsername = $postObj->FromUserName; //请求消息的用户
   $toUsername = $postObj->ToUserName; //"我"的公众号id
   $keyword = trim($postObj->Content); //消息内容
   $time = time(); //时间戳
   $msgtype = 'text'; //消息类型:文本
   $textTpl = "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[%s]]></MsgType>
<Content><![CDATA[%s]]></Content>
</xml>"
;
 
  if($keyword == 'xmr'){
    include("xmr.php");
    $contentStr = getXmr();
    $resultStr = sprintf($textTpl, $fromUsername, $toUsername, $time, $msgtype, $contentStr);
    echo $resultStr;
    exit();          
   }else{
    $contentStr =$fromUsername;
    $resultStr = sprintf($textTpl, $fromUsername, $toUsername, $time, $msgtype, $contentStr);
    echo $resultStr;
    exit();
   }
 
  }else {
   echo "";
   exit;
  }
 }
 
 //验证字段
 private function checkSignature(){
 
  $signature = $_GET["signature"];
  $timestamp = $_GET["timestamp"];
  $nonce = $_GET["nonce"];
   
 $token = TOKEN;
 $tmpArr = array($token, $timestamp, $nonce);
 sort($tmpArr);
 $tmpStr = implode( $tmpArr );
 $tmpStr = sha1( $tmpStr );
 
 if( $tmpStr == $signature ){
 return true;
 }else{
 return false;
 }
 }
}


?>

请注意:

1) 为了获得进行接口开发的权限,我们首先需要进入订阅号后台的“开发”区块并对URL以及token进行配置。如果采用php语言进行编写,请注意此处的URL必须精确到php文件,微信平台进行验证时禁止出现301跳转,而且301跳转还有可能导致post与get类型的混淆。URL可以采用http或者https协议。

微信公众平台进行URL验证的截图

token由开发者自己设定,可在php中宏定义TOKEN=TOKEN.

2) $postStr = $GLOBALS["HTTP_RAW_POST_DATA"];$postStr=file_get_contents('php://input');都是获取post请求内容的方法,其中前者被php7.0以上弃用;在某些情况下可能需要修改php.ini中字段为 always_populate_raw_post_data = On ,详情可查看这篇博客

3) include("xmr.php");$contentStr = getXmr();中getXmr()为xmr.php中的函数,返回值为string类型,功能为从数据库查询信息并格式化,在此不作展开

三 技术思考

1.php相较Python与Java更加轻量,但程序调试与测试十分地不友好,微信的官方接口调试工具没有提供本地调试的工具, ,需要用到内网穿透等技术手段(以后细讲);而post一个xml并没有可靠的在线工具可供使用(相比之下,json的在线调试工具就丰富很多),需要本地编写一个程序对http的request-body进行定义,再加上xml的建立,十分麻烦。

在验证URL的时候我就遇到了麻烦,我的目录结构为“~/wx/api.php”,有相应的htaccess文件来实现301定向至index.php,api.php等文件的操作;最初采用“ ~/wx/ ”格式的URL,出现了 URL采用https地址后发现验证通过但是功能无法实现 的情况,排查首先从SSL证书入手,发现开启了强制SSL于是关闭,无用;采用http地址发现验证无法通过;于是一遍一遍检查php的语法并寻求外部测试….思路混乱了将近一个小时…..最终从访问日志入手,发现同一请求被重定向并存在301-162与200状态码,猜想如果采用301无法验证成功,最终改为http直链 “~/wx/api.php” ,问题解决。

2. xml—可扩展标记语言,标准通用标记语言的子集,简称XML。是一种用于标记电子文件使其具有结构性的标记语言。下面展示其与json结构上的区别与联系。

xml:
<note>
<to>George</to>
<from>John</from>
<heading>Reminder</heading>
<body>Don't forget the meeting!</body>
</note>
json:
{
    "to": "George",
    "from": "John",
    "heading": "Reminder",
    "body": "Don't forget the meeting!"
}

四 附件

最终功能示意图

《微信公众平台接口尝试——微信订阅号被动回复》上有1条评论

发表评论

电子邮件地址不会被公开。 必填项已用*标注