• 企业400电话
  • 微网小程序
  • AI电话机器人
  • 电商代运营
  • 全 部 栏 目

    企业400电话 网络优化推广 AI电话机器人 呼叫中心 网站建设 商标✡知产 微网小程序 电商运营 彩铃•短信 增值拓展业务
    PHP开发之用微信远程遥控服务器

     摘要

    微信公众好的开发很火,小程序更火。于是也凑个热闹,尝试了一把。

    大致的功能还是有的,不过是不全,很多地方我没有进行处理。不过对于纯文本方式的交流,已经没有问题啦。

    环境搭建

    下面大致的讲讲微信公众号的原理吧。可能我理解的有些不到位,如果有些许不当,欢迎批评指教。

    客户端发送给微信平台请求,微信平台将请求转发给私服,交给程序处理之后,获取到私服的处理结果,然后反馈给客户端。

    当然,这其中起到核心作用的自然是“微信公众平台”啦。相当于提供了一个舞台,一个能让各位能人异士展现出各自的特色的平台。其实,不仅微信如此,阿里同样是这样,如此各大电商才能一展手脚不是。

    开启配置

    这第一步,就是先申请一个微信开发者账号,个人的话选择订阅号就足够了。网上相关的资料很多,也很详细,我就不多说了。咱们直奔主题好了。

    首先登陆开发者账号成功后,开启服务器端的设置即可,如下图

    开启完成,根据自己服务器的情况进行一下设置即可。

    按需设置

    设置完,就可以启用了。这就好比家里的电线全部装修好了,现在要使用,按下开关一样。如下图

    启用服务器配置

    服务器环境

    关于服务器这块,官网上讲解的也是很详细的啦。

    https://mp.weixin.qq.com/wiki

    我们还可以下载官方的demo来模拟。

    官方样本

    代码也很简单。基本上学过了PHP基本语法的都能够看得懂。

    ?php
    /**
     * wechat php test
     */
    //define your token
    define("TOKEN", "weixin");
    $wechatObj = new wechatCallbackapiTest();
    $wechatObj->valid();
    class wechatCallbackapiTest
    {
     public function valid()
     {
     $echoStr = $_GET["echostr"];
     //valid signature , option
     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"];
     //extract post data
     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);
     $postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
     $fromUsername = $postObj->FromUserName;
     $toUsername = $postObj->ToUserName;
     $keyword = trim($postObj->Content);
     $time = time();
     $textTpl = "xml>
      ToUserName>![CDATA[%s]]>/ToUserName>
      FromUserName>![CDATA[%s]]>/FromUserName>
      CreateTime>%s/CreateTime>
      MsgType>![CDATA[%s]]>/MsgType>
      Content>![CDATA[%s]]>/Content>
      FuncFlag>0/FuncFlag>
      /xml>"; 
     if(!empty( $keyword ))
     {
      $msgType = "text";
      $contentStr = "Welcome to wechat world!";
      $resultStr = sprintf($textTpl, $fromUsername, $toUsername, $time, $msgType, $contentStr);
      echo $resultStr;
     }else{
      echo "Input something...";
     }
     }else {
     echo "";
     exit;
     }
     }
     private function checkSignature()
     {
     // you must define TOKEN by yourself
     if (!defined("TOKEN")) {
     throw new Exception('TOKEN is not defined!');
     }
     $signature = $_GET["signature"];
     $timestamp = $_GET["timestamp"];
     $nonce = $_GET["nonce"];
     $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;
     }
     }
    }
    ?>

    核心思路,无非检验一下签名,处理一下请求,反馈一下结果罢了。

    这里我不得不想说的就是,我觉得腾讯其实可以将那些个模板什么的去掉,直接暴露出黑盒模式,这样的话安全性会更高一点。很多时候,权限放的越开,效果可能越差。

    核心类

    接下来就是我自己的处理逻辑了,参照官方文档。微信公众好上有6大接收接口,三大回复接口。依据MsgType即可判定。

    接口详情

    验证

    private function checkSignature() {
     // you must define TOKEN by yourself
     if (! defined ( "TOKEN" )) {
     throw new Exception ( 'TOKEN is not defined!' );
     }
     $signature = $_GET ["signature"];
     $timestamp = $_GET ["timestamp"];
     $nonce = $_GET ["nonce"];
     $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;
     }
     }

    验证方法核心就是依据咱们之前网页上设置的TOKEN来工作的,所以代码上会用得到。

    回复

    回复的代码需要依据客户端发送的数据的类型来区分对待,类型这块微信平台会将数据打包好封装起来,我们住需要调用内部的MsgType进行处理即可。

    拓展

    拓展部分,是我自己异想天开往上加的。

    添加机器人

    调用一个机器人接口,来代替自己发送回复,技能让用户得到一个良好的用户体验,还能愉悦大众,何乐而不为?

    我这边测试了两个接口,一个是curl模式,一个是file_get_contents模式,都挺好用的啦。

    ?php
    /**
     * 图灵 机器人接口
     * 
     * 使用curl来进行浏览器模拟并抓取数据
     */
    function turing($requestStr) {
     // 图灵机器人接口
     $url = "http://www.tuling123.com/openapi/api";
     // 用于POST请求的数据
     $data = array(
     'key'=>"哈哈,这个key还是得你自己去申请的啦",
     'info'=>$requestStr,
     );
     // 构造curl下载器
     $ch = curl_init();
     curl_setopt($ch, CURLOPT_URL, $url);
     curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
     curl_setopt($ch, CURLOPT_POST, 1);
     curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
     $responseStr = curl_exec($ch);
     curl_close($ch);
     return $responseStr;
    }
    /**
     * 调用另外的接口
     * @param unknown $req
     * @return mixed
     */
    function test($req){
     $url = "http://api.qingyunke.com/api.php?key=freeappid=0msg=".$req;
     $result = file_get_contents($url);
     $result = json_decode($result, true);
     return $result['content'];
    }
    $req = 'hello';
    $res = test($req);
    echo $res;

    命令模式

    手机相对于电脑一个很大的优点就是便携,我们虽然不能随时随地携带电脑,但是却能使用手机来代替。很多时候对服务器的管理需要的命令很简单,但是远程登录的时候也不方便。这个时候就用微信来帮忙传话也是不错的啦。

    我平时喜欢使用Python写一些脚本,什么获取本地IP,聊天,查看内存,网速啥的,可谓是应有尽有。这下也终于能有用武之地了。利用微信的关键字匹配,就可以简单的让微信公众号当一个小小传话员啦。

    这里给个思路,具体实现起来也比较简单,当做是文本来处理即可。

    完整代码

    下面贴出我服务器上的完整代码,有些私密的地方我做了些更改,届时按照自己的情况进行修改即可。

    ?php
    /**
     * wechat php test
     */
    // define your token
    define ( "TOKEN", "您的TOKEN" );
    $wechatObj = new wechatCallbackapiTest ();
    // $wechatObj->valid();
    // 调用回复信息方法
    $wechatObj->responseMsg ();
    // 微信消息处理核心类
    class wechatCallbackapiTest {
     public function valid() {
     $echoStr = $_GET ["echostr"];
     // valid signature , option
     if ($this->checkSignature ()) {
     echo $echoStr;
     exit ();
     } else {
     echo "验证失败!";
     }
     }
     public function responseMsg() {
     // get post data, May be due to the different environments
     // 类似$_POST但是可以接受XML数据,属于增强型
     $postStr = $GLOBALS ["HTTP_RAW_POST_DATA"];
     // extract post data
     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
     */
     // 不解析外部数据,防止xxml漏洞
     libxml_disable_entity_loader ( true );
     $postObj = simplexml_load_string ( $postStr, 'SimpleXMLElement', LIBXML_NOCDATA );
     $fromUsername = $postObj->FromUserName;
     $toUsername = $postObj->ToUserName;
     $keyword = trim ( $postObj->Content );
     $time = time ();
     /*
     * 微信客户端发送信息的时候会附带一些参数,详见官方文档。所以要根据不同的类型,来分别做相关的处理。
     * 于是MsgType 就充当这样的一个区分的标记
     */
     $msgType = $postObj->MsgType;
     /*
     * 当有用户关注后者退订的时候,会触发相应的事件。所以再来个event事件的监听更为友好。
     * $event = $postObj->Event.
     * 具体的参数信息,官网上很详细。
     */
     $event = $postObj->Event;
     switch ($msgType) {
     // 文本消息 处理部分
     case "text" :
      if (! empty ( $keyword )) {
      // 在此处进行对关键字的匹配就可以实现:针对不同关键字组装的相应数据
      if($keyword=='音乐' || $keyword == "music") {
      $msgType = 'music';
      $musictitle = "The Mountain";
      $musicdescription = "夏日舒心清凉歌曲";
      $musicurl = "http://101.200.58.242/wx/themaintain.mp3";
      $hqmusicurl = "http://101.200.58.242/wx/themaintain.mp3";
      musicMessageHandle($fromUsername, $toUsername, $time, $msgType, $musictitle, $musicdescription, $musicurl, $hqmusicurl);
      }elseif($keyword == '1'){
      $msgType = 'text';
      $contentStr = "人生得意须尽欢,莫使金樽空对月!";
      textMessageHandle($fromUsername, $toUsername, $time, $msgType, $contentStr);
      }elseif($keyword == '命令模式'){
      $msgType = 'text';
      $contentStr = "进入命令模式,开始对服务器进行管理!\n接下来将依据您输入的命令对服务器进行管理!";
      textMessageHandle($fromUsername, $toUsername, $time, $msgType, $contentStr);
      }else {
      // 直接调用 机器人接口,与用户进行交流
      $msgType = "text";
      $contentStr = turing($keyword)!=""?turing($keyword):"这里是微信 纯文本测试数据!";
      textMessageHandle ( $fromUsername, $toUsername, $time, $msgType, $contentStr );
      }
      } else {
      echo "您得输入点数据,我才能回复不是!";
      }
      break;
     // 接收图片信息
     case "image" :
      if (! empty ( $keyword )) {
    //  $msgType = "image";
      $contentStr = "您发送的图片看起来还真不错!";
      textMessageHandle ( $fromUsername, $toUsername, $time, $msgType, $contentStr );
      } else {
      echo "服务器没能收到您发送的图片!";
      }
      break;
     // 接收语音信息
     case "voice" :
      if (! empty ( $keyword )) {
    //  $msgType = "voice";
      $contentStr = "您发送的语音听起来还真不错!";
      textMessageHandle ( $fromUsername, $toUsername, $time, $msgType, $contentStr );
      } else {
      echo "服务器没能收到您发送的语音!";
      }
      break;
     // 接收视频信息
     case "video" :
      if (! empty ( $keyword )) {
    //  $msgType = "video";
      $contentStr = "您发送的视频看起来还真不错!";
      textMessageHandle ( $fromUsername, $toUsername, $time, $msgType, $contentStr );
      } else {
      echo "服务器没能收到您发送的视频!";
      }
      break;
     // 接收视频信息
     case "shortvideo" :
      if (! empty ( $keyword )) {
    //  $msgType = "shortvideo";
      $contentStr = "您发送的小视频看起来还真不错!";
      textMessageHandle ( $fromUsername, $toUsername, $time, $msgType, $contentStr );
      } else {
      echo "服务器没能收到您发送的小视频!";
      }
      break;
     // 接收位置信息
     case "location" :
      if (! empty ( $keyword )) {
    //  $msgType = "location";
      $contentStr = "您发送的位置已被接收!";
      textMessageHandle ( $fromUsername, $toUsername, $time, $msgType, $contentStr );
      } else {
      echo "服务器没能收到您发送的位置!";
      }
      break;
     // 接收视频信息
     case "link" :
      if (! empty ( $keyword )) {
    //  $msgType = "link";
      $contentStr = "您发送的链接看起来还真不错!";
      textMessageHandle ( $fromUsername, $toUsername, $time, $msgType, $contentStr );
      } else {
      echo "服务器没能收到您发送的链接!";
      }
      break;
     // 对事件进行侦听
     case "event":
      switch ($event) {
      case "subscribe":
      // 发送一些消息!
      $msgType = 'text';
      $contentStr = "终于等到你!";
      textMessageHandle($fromUsername, $toUsername, $time, $msgType, $contentStr);
      break;
      }
      break;
     default :
      break;
     }
     } else {
     echo "";
     exit ();
     }
     }
     private function checkSignature() {
     // you must define TOKEN by yourself
     if (! defined ( "TOKEN" )) {
     throw new Exception ( 'TOKEN is not defined!' );
     }
     $signature = $_GET ["signature"];
     $timestamp = $_GET ["timestamp"];
     $nonce = $_GET ["nonce"];
     $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;
     }
     }
    }
    /**
     * 定义为心中想难关的六个接口的数据发送格式模板
     */
    function textMessageHandle($fromUsername, $toUsername, $time, $msgType, $contentStr) {
     $textTpl = "xml>
      ToUserName>![CDATA[%s]]>/ToUserName>
      FromUserName>![CDATA[%s]]>/FromUserName>
      CreateTime>%s/CreateTime>
      MsgType>![CDATA[%s]]>/MsgType>
      Content>![CDATA[%s]]>/Content>
      FuncFlag>0/FuncFlag>
     /xml>";
     $resultStr = sprintf ( $textTpl, $fromUsername, $toUsername, $time, $msgType, $contentStr );
     echo $resultStr;
    }
    function imageMessageHandle($fromUsername, $toUsername, $time, $msgType, $contentStr) {
     $imageTpl = "xml>
      ToUserName>![CDATA[%s]]>/ToUserName>
      FromUserName>![CDATA[%s]]>/FromUserName>
      CreateTime>%s/CreateTime>
      MsgType>![CDATA[%s]]>/MsgType>
      Content>![CDATA[%s]]>/Content>
      PicUrl>![CDATA[this is a url]]>/PicUrl>
      MediaId>![CDATA[media_id]]>/MediaId>
      MsgId>1234567890123456/MsgId>
      /xml>";
     $resultStr = sprintf ( $textTpl, $fromUsername, $toUsername, $time, $msgType, $contentStr );
     echo $resultStr;
    }
    function musicMessageHandle($fromUsername, $toUsername, $time, $msgType, $musictitle, $musicDescription, $musicurl, $hqmusicurl) {
     $musicTpl = "xml>
      ToUserName>![CDATA[%s]]>/ToUserName>
      FromUserName>![CDATA[%s]]>/FromUserName>
      CreateTime>%s/CreateTime>
      MsgType>![CDATA[%s]]>/MsgType>
      Music>
      Title>![CDATA[%s]]>/Title>
      Description>![CDATA[%s]]>/Description>
      MusicUrl>![CDATA[%s]]>/MusicUrl>
      HQMusicUrl>![CDATA[%s]]>/HQMusicUrl>
      /Music>
     /xml>";
     $resultStr = sprintf($musicTpl, $fromUsername, $toUsername, $time, $msgType, $musictitle, $musicDescription, $musicurl, $hqmusicurl);
     echo $resultStr;
    }
    /**
     * 图灵 机器人接口
     * 
     * 使用curl来进行浏览器模拟并抓取数据
     */
    function turing($requestStr) {
     /* // 图灵机器人接口
     $url = "http://www.tuling123.com/openapi/api";
     // 用于POST请求的数据
     $data = array(
     "key"=>"您在图灵机器人官网上申请的key",
     "info"=>$requestStr
     );
     // 构造curl下载器
     $ch = curl_init();
     curl_setopt($ch, CURLOPT_URL, $url);
     curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
     curl_setopt($ch, CURLOPT_POST, 1);
     curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
     $requestStr = curl_exec($ch);
     curl_close($ch);
     return responseStr; */
     $url = "http://api.qingyunke.com/api.php?key=freeappid=0msg=".$requestStr;
     $result = file_get_contents($url);
     $result = json_decode($result, true);
     return $result['content'];
    }
    ?>

    总结

    最后来回顾一下,本次试验用到了哪些知识点。

    其实,这些代码跟我一开始的设想还是差别挺大的,原本是想实现一个“遥控器”,晚上想睡觉之前,用微信发一条命令“打开电热毯”,半个小时后,电视看完了,去睡觉的时候发现被窝很暖和,是的,只要加上点硬件,这很容易实现啦再者冰箱了,电视了统统可以完成,那样估计就诊的是“智能家居”了吧。

    您可能感兴趣的文章:
    • 微信小程序上传图片到服务器实例代码
    • 本地搭建微信小程序服务器的实现方法
    • 微信小程序图片选择、上传到服务器、预览(PHP)实现实例
    • 微信小程序访问node.js接口服务器搭建教程
    • 微信小程序 消息推送php服务器验证实例详解
    • 微信公众平台开发-微信服务器IP接口实例(含源码)
    • 微信小程序 解决请求服务器手机预览请求不到数据的方法
    • 微信小程序 Windows2008 R2服务器配置TLS1.2方法
    • java微信开发API第一步 服务器接入
    • C#微信开发(服务器配置)
    上一篇:php实现统计二进制中1的个数算法示例
    下一篇:CI框架(CodeIgniter)操作redis的方法详解
  • 相关文章
  • 

    © 2016-2020 巨人网络通讯

    时间:9:00-21:00 (节假日不休)

    地址:江苏信息产业基地11号楼四层

    《增值电信业务经营许可证》 苏B2-20120278

    PHP开发之用微信远程遥控服务器 PHP,开发,之用,微信,远程,