php学习练习(2)-微信版宝宝睡前故事

小的功能需求在生活的周围存在很多,这些功能需求的编程实现是学习的一种良好方式。对于给孩子读睡前故事是现阶段我这个家庭的需求,买了不少故事书,也有读,就想着将这些故事放到手机上也是一个不错的选择。

时下比较火热的「微信」是手机上呈现的一个不错的方式,于是着手规划这个小的功能需求,这个小的需求分为两部分,第一部分是服务器端对于故事的组织与管理;第二部分是服务器端与微信公众号之间的接口实现。

服务器端需要一个存储故事的数据库,用于存储故事数据,一组页面及其脚本来完成故事的管理,完成对应于数据库的ADU相关操作。剩下的就是与微信的接口部分,通过微信公众号的自定义菜单获取每日睡前故事,通过脚本依据当日信息组成微信公众号的图文信息,点击后展现故事。

最终的阅读操作如图所示「如果你也有这样的需求,可通过微信搜索smallsoftware关注即可使用,也可在微信中扫描本Blog右侧二维码直接关注」:

babystorys

微信接口这部分主要是从数据库中获得数据,然后组织成图文信息即可,根据微信自定义菜单的KEY完成组装即可。

$postStr = $GLOBALS["HTTP_RAW_POST_DATA"];
if(!empty($postStr)) {
  $postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
  $fromUser = $postObj->FromUserName;
  //详细请参看微信公众帐号开发接口文档
  //...
  $fromMsgType = $postObj->MsgType;
  //...
  if($fromMsgType == "event") {
    $formEvent = $postObj->Event;
    if($formEvent == "CLICK") {
      $eventKey = $postObj->EventKey;
      if($eventKey == 'YOUR_KEY') {
        //取数据
        //组织图文信息数据
        //输出
      } else { //... }
    }
  }
//......

服务器端包含故事的添加、修改、删除、查看,用于后台对于故事的管理。使用了Bootstrap前端框架的部分内容,具体的结构如下。

babystory archite

数据库类基于PDO,故事类继承数据库类,完成故事的数据相关操作封装及故事的展现,admin类完成权限和管理的封装,前端页面通过init入口完成对于数据的管理工作,init入口部分完成数据的初始化工作与上下交互操作。

没有其他可供的选择,每天一篇睡前故事,对于选择性故事的定制阅读及过往的查询不支持,对于用户阅读这部分的统计也没有完成,可以说留下了不少的坑等着填。

至于微信自定义菜单,根据其接口文档中的说明,先要由appid和secret通过一个URL用Get方式获得AccessToken,然后将准备好的菜单和获得的AccessToken通过一个URL用POST的方式提交数据,从而创建自定义菜单。

<!--?php
  class WechatMenu {
    private $_appid = "";  //你的appid
    private $_secret = ""; //你的secret
    function __construct($menu) {
      //先获得AccessToken
      $result = $this--->getAccessToken();
      if(array_key_exists('errcode', $result)) {
       throw new Exception($result['errmsg'], 1);
      } else {
         $url = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=" . $result['access_token'];
         $result = $this-&gt;Post($url, $menu);
         if($result['errcode'] == 0) {
           //ok
         } else {
           throw new Exception($result['errcode'], 1);
         }
      }
    }
    
    private function Post($url, $data) {
      $ch = curl_init();
      curl_setopt($ch, CURLOPT_URL, $url);
      curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
      curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
      curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
      $data = curl_exec($ch);
      curl_close($ch);
      return json_decode($data,true);
    }

    private function Get($url) {
      $ch = curl_init();
      curl_setopt($ch, CURLOPT_URL, $url);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
      curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
      curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
      $data = curl_exec($ch);
      curl_close($ch);
      return json_decode($data,true);
    }

    private function getAccessToken() {
      $grant_type = "client_credential";
      $appid = $this-&gt;appid;
      $secret = $this-&gt;secret;
      $url = "https://api.weixin.qq.com/cgi-bin/token?grant_type={$grant_type}&amp;appid={$appid}&amp;secret={$secret}";
      $result = $this-&gt;Get($url);
      return $result;
    }
  }
?&gt;

调用 (1) 生成json格式的菜单数据 (2)new WechatMenu($menu);

wechatmenu

-EOF-