|
Posted on 2013-08-24 16:02 saobaolu 閱讀(1255) 評論(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 沒有所謂的命運,只有不同的選擇!
|