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