zoukankan      html  css  js  c++  java
  • 微信公众号开发总结

    最近公司用到了微信公众平台,所以研究了一下微信公众号的开发技术,总体来说比较简单,结合现有的平台核技术,实现起来非常方便。

    首先先来了解一下微信公众平台。

    “微信,是一个生活方式” ,这是微信的自我评价,是不是觉得如果那天不在朋友圈里分享一下自己的最新状态, 
    并且收到几个赞和评价的话,会觉得空虚寂寞呢?它实实在在的改变了我们的生活方式。

    “ 微信,也是一个生意方式 ”,在微信成为我们日常必备之app的同时,它同样具备巨大的的商业 
    或许不应该称为潜力,因为有很多人已经获利,名人们在微信上开设公众账户来吸金,商家来做推广, 
    服务行业借此拓展渠道,甚至微信已经支持支付了, 还有越来越的自媒体在微信平台涌现出来。 

    这篇文章就是介绍如何快速的成为公众平台开发者,由于个人只能申请订阅号,因此本文是以订阅号为例。
    关于订阅号和服务号的区别,请参见 微信公众平台服务号、订阅号的相关说明

    从微信用户角度简单来说:

    订阅号 主要用于信息辐射,典型的如各家 新闻媒体 。 
    服务号 主要由于自助服务,典型的如 招商银行 。

    申请公众平台账户

    • 按照提示激活邮箱

    • 上传个人照片,需要有清晰的身份证照片

    • 选择公众账户的类型,对于个人账户只能选择 订阅号

    • 最后你会看到自己账户的所有信息,请上传账号的头像,否则无法完成开发者的申请

    • 等待审核通过,这个过程大约需要2~3天,当你收到如下通知,那么恭喜你,你已经成功的申请到了微信公众账户了

    关于微信公众帐号注册的步骤就不再多说了,可以找到大量的图文教程。

    帐号注册成功之后,需要验证自己的服务器,如果你没有自己的服务器,那可以用新浪SAE或者百度BAE,本文采用的是新浪SAE平台来搭建服务器。

    注册过程略,使用新浪SAE创建应用,可以选择应用开发框架,选项中有比较热门的开发框架,选择微信公众平台phpSDK,点击后跳转到介绍页面,点击安装框架,系统会生成一个搭建好的微信公众平台应用,为了方便开发,我们可以使用svn来管理此应用代码,关于svn搭建可参见sae代码部署手册

    使用新浪SAE是比较方便的,如果我们有自己的服务器,可以把代码clone到自己的服务器上,下面来看一下代码

    首先定义一个Wechat的基类

      1 <?php
      2 /**
      3  * 微信公众平台 PHP SDK
      4  *
      5  * @author hanc <congcongsky2010@gmail.com>
      6  */
      7 
      8   /**
      9    * 微信公众平台处理类
     10    */
     11   class Wechat {
     12 
     13     /**
     14      * 调试模式,将错误通过文本消息回复显示
     15      *
     16      * @var boolean
     17      */
     18     private $debug;
     19 
     20     /**
     21      * 以数组的形式保存微信服务器每次发来的请求
     22      *
     23      * @var array
     24      */
     25     private $request;
     26 
     27     /**
     28      * 初始化,判断此次请求是否为验证请求,并以数组形式保存
     29      *
     30      * @param string $token 验证信息
     31      * @param boolean $debug 调试模式,默认为关闭
     32      */
     33     public function __construct($token, $debug = FALSE) {
     34       if ($this->isValid() && $this->validateSignature($token)) {
     35         exit($_GET['echostr']);
     36       }
     37 
     38       $this->debug = $debug;
     39       set_error_handler(array(&$this, 'errorHandler'));
     40       // 设置错误处理函数,将错误通过文本消息回复显示
     41 
     42       $xml = (array) simplexml_load_string($GLOBALS['HTTP_RAW_POST_DATA'], 'SimpleXMLElement', LIBXML_NOCDATA);
     43 
     44       $this->request = array_change_key_case($xml, CASE_LOWER);
     45       // 将数组键名转换为小写,提高健壮性,减少因大小写不同而出现的问题
     46     }
     47 
     48     /**
     49      * 判断此次请求是否为验证请求
     50      *
     51      * @return boolean
     52      */
     53     private function isValid() {
     54       return isset($_GET['echostr']);
     55     }
     56 
     57     /**
     58      * 判断验证请求的签名信息是否正确
     59      *
     60      * @param  string $token 验证信息
     61      * @return boolean
     62      */
     63     private function validateSignature($token) {
     64       $signature = $_GET['signature'];
     65       $timestamp = $_GET['timestamp'];
     66       $nonce = $_GET['nonce'];
     67 
     68       $signatureArray = array($token, $timestamp, $nonce);
     69       sort($signatureArray);
     70 
     71       return sha1(implode($signatureArray)) == $signature;
     72     }
     73 
     74     /**
     75      * 获取本次请求中的参数,不区分大小
     76      *
     77      * @param  string $param 参数名,默认为无参
     78      * @return mixed
     79      */
     80     protected function getRequest($param = FALSE) {
     81       if ($param === FALSE) {
     82         return $this->request;
     83       }
     84 
     85       $param = strtolower($param);
     86 
     87       if (isset($this->request[$param])) {
     88         return $this->request[$param];
     89       }
     90 
     91       return NULL;
     92     }
     93 
     94     /**
     95      * 用户关注时触发,用于子类重写
     96      *
     97      * @return void
     98      */
     99     protected function onSubscribe() {}
    100 
    101     /**
    102      * 用户取消关注时触发,用于子类重写
    103      *
    104      * @return void
    105      */
    106     protected function onUnsubscribe() {}
    107     
    108     /**
    109      * 用户自动上报地理位置触发,用于子类重写
    110      *
    111      * @return void
    112      */
    113     protected function onAutoloaction() {}
    114       
    115     /**
    116      * 用户点击菜单时触发,用于子类重写
    117      *
    118      * @return void
    119      */
    120     protected function onClick() {}
    121     
    122     /**
    123      * 用户点击跳转链接时触发,用于子类重写
    124      *
    125      * @return void
    126      */
    127     protected function onView() {}
    128 
    129     /**
    130      * 收到文本消息时触发,用于子类重写
    131      *
    132      * @return void
    133      */
    134     protected function onText() {}
    135 
    136     /**
    137      * 收到图片消息时触发,用于子类重写
    138      *
    139      * @return void
    140      */
    141     protected function onImage() {}
    142 
    143     /**
    144      * 收到地理位置消息时触发,用于子类重写
    145      *
    146      * @return void
    147      */
    148     protected function onLocation() {}
    149 
    150     /**
    151      * 收到链接消息时触发,用于子类重写
    152      *
    153      * @return void
    154      */
    155     protected function onLink() {}
    156     /**
    157      * 收到语音消息时触发,用于子类重写
    158      *
    159      * @return void
    160      */
    161     protected function onVoice() {}
    162 
    163     /**
    164      * 收到未知类型消息时触发,用于子类重写
    165      *
    166      * @return void
    167      */
    168     protected function onUnknown() {}
    169 
    170     /**
    171      * 回复文本消息
    172      *
    173      * @param  string  $content  消息内容
    174      * @param  integer $funcFlag 默认为0,设为1时星标刚才收到的消息
    175      * @return void
    176      */
    177     protected function responseText($content, $funcFlag = 0) {
    178       exit(new TextResponse($this->getRequest('fromusername'), $this->getRequest('tousername'), $content, $funcFlag));
    179     }
    180 
    181     /**
    182      * 回复音乐消息
    183      *
    184      * @param  string  $title       音乐标题
    185      * @param  string  $description 音乐描述
    186      * @param  string  $musicUrl    音乐链接
    187      * @param  string  $hqMusicUrl  高质量音乐链接,Wi-Fi 环境下优先使用
    188      * @param  integer $funcFlag    默认为0,设为1时星标刚才收到的消息
    189      * @return void
    190      */
    191     protected function responseMusic($title, $description, $musicUrl, $hqMusicUrl, $funcFlag = 0) {
    192       exit(new MusicResponse($this->getRequest('fromusername'), $this->getRequest('tousername'), $title, $description, $musicUrl, $hqMusicUrl, $funcFlag));
    193     }
    194 
    195     /**
    196      * 回复图文消息
    197      * @param  array   $items    由单条图文消息类型 NewsResponseItem() 组成的数组
    198      * @param  integer $funcFlag 默认为0,设为1时星标刚才收到的消息
    199      * @return void
    200      */
    201     protected function responseNews($items, $funcFlag = 0) {
    202       exit(new NewsResponse($this->getRequest('fromusername'), $this->getRequest('tousername'), $items, $funcFlag));
    203     }
    204     /**
    205      * 回复语音识别消息
    206      * @param  array   $recognition  系统接收到语音后识别的字符串
    207      * @param  integer $funcFlag     默认为0,设为1时星标刚才收到的消息
    208      * @return void
    209      */
    210     protected function responseVoice($recognition, $funcFlag = 0) {
    211       exit(new TextResponse($this->getRequest('fromusername'), $this->getRequest('tousername'), $recognition, $funcFlag));
    212     }
    213 
    214     /**
    215      * 分析消息类型,并分发给对应的函数
    216      *
    217      * @return void
    218      */
    219     public function run() {
    220       switch ($this->getRequest('msgtype')) {
    221 
    222         case 'event':
    223           switch ($this->getRequest('event')) {
    224 
    225             case 'subscribe':
    226               $this->onSubscribe();
    227               break;
    228 
    229             case 'unsubscribe':
    230               $this->onUnsubscribe();
    231               break;
    232               
    233             case 'LOCATION':
    234               $this->onAutoloaction();
    235               break;
    236               
    237             case 'CLICK':
    238               $this->onClick();
    239               break;
    240               
    241             case 'VIEW':
    242               $this->onView();
    243               break;
    244 
    245           }
    246           break;
    247 
    248         case 'text':
    249           $this->onText();
    250           break;
    251 
    252         case 'image':
    253           $this->onImage();
    254           break;
    255 
    256         case 'location':
    257           $this->onLocation();
    258           break;
    259 
    260         case 'link':
    261           $this->onLink();
    262           break;
    263 
    264         case 'voice':
    265           $this->onVoice();
    266           break;
    267           
    268         default:
    269           $this->onUnknown();
    270           break;
    271 
    272       }
    273     }
    274 
    275     /**
    276      * 自定义的错误处理函数,将 PHP 错误通过文本消息回复显示
    277      * @param  int $level   错误代码
    278      * @param  string $msg  错误内容
    279      * @param  string $file 产生错误的文件
    280      * @param  int $line    产生错误的行数
    281      * @return void
    282      */
    283     protected function errorHandler($level, $msg, $file, $line) {
    284       if ( ! $this->debug) {
    285         return;
    286       }
    287 
    288       $error_type = array(
    289         // E_ERROR             => 'Error',
    290         E_WARNING           => 'Warning',
    291         // E_PARSE             => 'Parse Error',
    292         E_NOTICE            => 'Notice',
    293         // E_CORE_ERROR        => 'Core Error',
    294         // E_CORE_WARNING      => 'Core Warning',
    295         // E_COMPILE_ERROR     => 'Compile Error',
    296         // E_COMPILE_WARNING   => 'Compile Warning',
    297         E_USER_ERROR        => 'User Error',
    298         E_USER_WARNING      => 'User Warning',
    299         E_USER_NOTICE       => 'User Notice',
    300         E_STRICT            => 'Strict',
    301         E_RECOVERABLE_ERROR => 'Recoverable Error',
    302         E_DEPRECATED        => 'Deprecated',
    303         E_USER_DEPRECATED   => 'User Deprecated',
    304       );
    305 
    306       $template = <<<ERR
    307 PHP 报错啦!
    308 
    309 %s: %s
    310 File: %s
    311 Line: %s
    312 ERR;
    313 
    314       $this->responseText(sprintf($template,
    315         $error_type[$level],
    316         $msg,
    317         $file,
    318         $line
    319       ));
    320     }
    321 
    322   }
    323 
    324   /**
    325    * 用于回复的基本消息类型
    326    */
    327   abstract class WechatResponse {
    328 
    329     protected $toUserName;
    330     protected $fromUserName;
    331     protected $funcFlag;
    332 
    333     public function __construct($toUserName, $fromUserName, $funcFlag) {
    334       $this->toUserName = $toUserName;
    335       $this->fromUserName = $fromUserName;
    336       $this->funcFlag = $funcFlag;
    337     }
    338 
    339     abstract public function __toString();
    340 
    341   }
    342 
    343 
    344   /**
    345    * 用于回复的文本消息类型
    346    */
    347   class TextResponse extends WechatResponse {
    348 
    349     protected $content;
    350 
    351     protected $template = <<<XML
    352 <xml>
    353   <ToUserName><![CDATA[%s]]></ToUserName>
    354   <FromUserName><![CDATA[%s]]></FromUserName>
    355   <CreateTime>%s</CreateTime>
    356   <MsgType><![CDATA[text]]></MsgType>
    357   <Content><![CDATA[%s]]></Content>
    358   <FuncFlag>%s<FuncFlag>
    359 </xml>
    360 XML;
    361 
    362     public function __construct($toUserName, $fromUserName, $content, $funcFlag = 0) {
    363       parent::__construct($toUserName, $fromUserName, $funcFlag);
    364       $this->content = $content;
    365     }
    366 
    367     public function __toString() {
    368       return sprintf($this->template,
    369         $this->toUserName,
    370         $this->fromUserName,
    371         time(),
    372         $this->content,
    373         $this->funcFlag
    374       );
    375     }
    376 
    377   }
    378 
    379   /**
    380    * 用于回复的音乐消息类型
    381    */
    382   class MusicResponse extends WechatResponse {
    383 
    384     protected $title;
    385     protected $description;
    386     protected $musicUrl;
    387     protected $hqMusicUrl;
    388 
    389     protected $template = <<<XML
    390 <xml>
    391   <ToUserName><![CDATA[%s]]></ToUserName>
    392   <FromUserName><![CDATA[%s]]></FromUserName>
    393   <CreateTime>%s</CreateTime>
    394   <MsgType><![CDATA[music]]></MsgType>
    395   <Music>
    396     <Title><![CDATA[%s]]></Title>
    397     <Description><![CDATA[%s]]></Description>
    398     <MusicUrl><![CDATA[%s]]></MusicUrl>
    399     <HQMusicUrl><![CDATA[%s]]></HQMusicUrl>
    400   </Music>
    401   <FuncFlag>%s<FuncFlag>
    402 </xml>
    403 XML;
    404 
    405     public function __construct($toUserName, $fromUserName, $title, $description, $musicUrl, $hqMusicUrl, $funcFlag) {
    406       parent::__construct($toUserName, $fromUserName, $funcFlag);
    407       $this->title = $title;
    408       $this->description = $description;
    409       $this->musicUrl = $musicUrl;
    410       $this->hqMusicUrl = $hqMusicUrl;
    411     }
    412 
    413     public function __toString() {
    414       return sprintf($this->template,
    415         $this->toUserName,
    416         $this->fromUserName,
    417         time(),
    418         $this->title,
    419         $this->description,
    420         $this->musicUrl,
    421         $this->hqMusicUrl,
    422         $this->funcFlag
    423       );
    424     }
    425 
    426   }
    427 
    428 
    429   /**
    430    * 用于回复的图文消息类型
    431    */
    432   class NewsResponse extends WechatResponse {
    433 
    434     protected $items = array();
    435 
    436     protected $template = <<<XML
    437 <xml>
    438   <ToUserName><![CDATA[%s]]></ToUserName>
    439   <FromUserName><![CDATA[%s]]></FromUserName>
    440   <CreateTime>%s</CreateTime>
    441   <MsgType><![CDATA[news]]></MsgType>
    442   <ArticleCount>%s</ArticleCount>
    443   <Articles>
    444     %s
    445   </Articles>
    446   <FuncFlag>%s<FuncFlag>
    447 </xml>'
    448 XML;
    449 
    450     public function __construct($toUserName, $fromUserName, $items, $funcFlag) {
    451       parent::__construct($toUserName, $fromUserName, $funcFlag);
    452       $this->items = $items;
    453     }
    454 
    455     public function __toString() {
    456       return sprintf($this->template,
    457         $this->toUserName,
    458         $this->fromUserName,
    459         time(),
    460         count($this->items),
    461         implode($this->items),
    462         $this->funcFlag
    463       );
    464     }
    465 
    466   }
    467 
    468 
    469   /**
    470    * 单条图文消息类型
    471    */
    472   class NewsResponseItem {
    473 
    474     protected $title;
    475     protected $description;
    476     protected $picUrl;
    477     protected $url;
    478 
    479     protected $template = <<<XML
    480 <item>
    481   <Title><![CDATA[%s]]></Title>
    482   <Description><![CDATA[%s]]></Description>
    483   <PicUrl><![CDATA[%s]]></PicUrl>
    484   <Url><![CDATA[%s]]></Url>
    485 </item>
    486 XML;
    487 
    488     public function __construct($title, $description, $picUrl, $url) {
    489       $this->title = $title;
    490       $this->description = $description;
    491       $this->picUrl = $picUrl;
    492       $this->url = $url;
    493     }
    494 
    495     public function __toString() {
    496       return sprintf($this->template,
    497         $this->title,
    498         $this->description,
    499         $this->picUrl,
    500         $this->url
    501       );
    502     }
    503 
    504   }

    此基类我稍作了更改,包含了能实现的微信所有的接口,通过继承 `Wechat` 类进行扩展,例如通过重写 `onSubscribe()` 等方法响应关注等请求,下面是实现的示例代码:

      1 <?php
      2 /**
      3  * 微信公众平台 PHP SDK 示例文件
      4  *
      5  * @author hanc <congcongsky2010@gmail.com>
      6  */
      7 
      8   require('src/Wechat.php');
      9 
     10   /**
     11    * 微信公众平台演示类
     12    */
     13   class MyWechat extends Wechat {
     14 
     15     /**
     16      * 用户关注时触发,回复「欢迎关注」
     17      *
     18      * @return void
     19      */
     20     protected function onSubscribe() {
     21       $this->responseText('欢迎关注韩聪的微信号');
     22     }
     23 
     24     /**
     25      * 用户取消关注时触发
     26      *
     27      * @return void
     28      */
     29     protected function onUnsubscribe() {
     30       // 「悄悄的我走了,正如我悄悄的来;我挥一挥衣袖,不带走一片云彩。」
     31     }
     32 
     33     /**
     34      * 用户自动上报地理位置时触发
     35      *
     36      * @return void
     37      */
     38     protected function onAutoloaction() {
     39 
     40       $this->responseText('您的地理位置为:' . $this->getRequest('Latitude') . ',' . $this->getRequest('Longitude'));
     41     }
     42       
     43     /**
     44      * 用户点击菜单时触发
     45      *
     46      * @return void
     47      */
     48     protected function onClick() {
     49        $eventKey=$this->getRequest('EventKey');
     50        switch($eventKey){
     51          case 'C001':
     52            $this->responseText('我赢了');
     53            break;
     54          case 'C002':
     55            $this->responseText('我最近很好o(∩_∩)o ');
     56            break;
     57          case 'C003':
     58            $this->responseText('谢谢(*^__^*) 嘻嘻');
     59            break;
     60        }
     61     }
     62     
     63     /**
     64      * 收到文本消息时触发,回复收到的文本消息内容
     65      *
     66      * @return void
     67      */
     68     protected function onText() {
     69       $this->responseText('收到了文字消息:' . $this->getRequest('content'));
     70     }
     71 
     72     /**
     73      * 收到图片消息时触发,回复由收到的图片组成的图文消息
     74      *
     75      * @return void
     76      */
     77     protected function onImage() {
     78       $items = array(
     79         new NewsResponseItem('标题一', '描述一', $this->getRequest('picurl'), $this->getRequest('picurl')),
     80         new NewsResponseItem('标题二', '描述二', $this->getRequest('picurl'), $this->getRequest('picurl')),
     81       );
     82 
     83       $this->responseNews($items);
     84     }
     85 
     86     /**
     87      * 收到地理位置消息时触发,回复收到的地理位置
     88      *
     89      * @return void
     90      */
     91     protected function onLocation() {
     92         //$num = 1 / 0;
     93       // 故意触发错误,用于演示调试功能
     94 
     95       $this->responseText('收到了位置消息:' . $this->getRequest('location_x') . ',' . $this->getRequest('location_y'));
     96     }
     97 
     98     /**
     99      * 收到链接消息时触发,回复收到的链接地址
    100      *
    101      * @return void
    102      */
    103     protected function onLink() {
    104       $this->responseText('收到了链接:' . $this->getRequest('url'));
    105     }
    106       
    107      /**
    108      * 收到语音消息时触发,回复收到的语音
    109      *
    110      * @return void
    111      */
    112     protected function onVoice() {
    113       $this->responseVoice('收到了语音:' . $this->getRequest('recognition'));
    114     }
    115 
    116     /**
    117      * 收到未知类型消息时触发,回复收到的消息类型
    118      *
    119      * @return void
    120      */
    121     protected function onUnknown() {
    122       $this->responseText('收到了未知类型消息:' . $this->getRequest('msgtype'));
    123     }
    124 
    125   }
    126 
    127   $wechat = new MyWechat('hancong', TRUE);
    128   $wechat->run();

    以上代码部分功能需要开通服务号并且申请认证,比如语音识别,地理信息,添加菜单的功能,申请认证需要300元/年,可以享受微信所有的接口功能。

    注:如果验证服务器URL,需要修改一句代码

    $wechat = new MyWechat('hancong', TRUE);
    //$wechat->run();
    $wechat->validateSignature('hancong');//参数为填写的token

    验证完后回复调用run方法,validateSignature方法只是第一次验证服务器调用,验证完后即可删掉。

  • 相关阅读:
    android 访问SD卡的方法
    android 用Achartengine 作图
    hello
    IIS 7.0 "确认文件是否存在"功能
    test
    收藏:如何在Web页面上直接打开、编辑、创建Office文档
    JavaScript面向对象技术
    正则表达式30分钟入门教程
    JWT有状态登陆与无状态登陆
    20条JavaScript代码简洁的写法
  • 原文地址:https://www.cnblogs.com/hanc/p/3714186.html
Copyright © 2011-2022 走看看