爱程序网

微信公众号开发总结

来源: 阅读:

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

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

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

“ 微信,也是一个生意方式 ”,在微信成为我们日常必备之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 void105      */106     protected function onUnsubscribe() {}107     108     /**109      * 用户自动上报地理位置触发,用于子类重写110      *111      * @return void112      */113     protected function onAutoloaction() {}114       115     /**116      * 用户点击菜单时触发,用于子类重写117      *118      * @return void119      */120     protected function onClick() {}121     122     /**123      * 用户点击跳转链接时触发,用于子类重写124      *125      * @return void126      */127     protected function onView() {}128 129     /**130      * 收到文本消息时触发,用于子类重写131      *132      * @return void133      */134     protected function onText() {}135 136     /**137      * 收到图片消息时触发,用于子类重写138      *139      * @return void140      */141     protected function onImage() {}142 143     /**144      * 收到地理位置消息时触发,用于子类重写145      *146      * @return void147      */148     protected function onLocation() {}149 150     /**151      * 收到链接消息时触发,用于子类重写152      *153      * @return void154      */155     protected function onLink() {}156     /**157      * 收到语音消息时触发,用于子类重写158      *159      * @return void160      */161     protected function onVoice() {}162 163     /**164      * 收到未知类型消息时触发,用于子类重写165      *166      * @return void167      */168     protected function onUnknown() {}169 170     /**171      * 回复文本消息172      *173      * @param  string  $content  消息内容174      * @param  integer $funcFlag 默认为0,设为1时星标刚才收到的消息175      * @return void176      */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 void190      */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 void200      */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 void209      */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 void218      */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 void282      */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 = <<<ERR307 PHP 报错啦!308 309 %s: %s310 File: %s311 Line: %s312 ERR;313 314       $this->responseText(sprintf($template,315         $error_type[$level],316         $msg,317         $file,318         $line319       ));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 = <<<XML352 <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->funcFlag374       );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 = <<<XML390 <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->funcFlag423       );424     }425 426   }427 428 429   /**430    * 用于回复的图文消息类型431    */432   class NewsResponse extends WechatResponse {433 434     protected $items = array();435 436     protected $template = <<<XML437 <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     %s445   </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->funcFlag463       );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 = <<<XML480 <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->url501       );502     }503 504   }

相关文章列表: