PageRenderTime 51ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/PigCms/Lib/ORG/Wechat.class.php

https://gitlab.com/colin.luo/shbs
PHP | 323 lines | 247 code | 31 blank | 45 comment | 36 complexity | 93c831b2ed42a2c50eca9239902094b5 MD5 | raw file
  1. <?php
  2. class Wechat {
  3. public $token;
  4. public $wxuser;
  5. public $pigsecret;
  6. private $data = array();
  7. public function __construct($token, $wxuser = ''){
  8. $this->auth($token, $wxuser) || exit;
  9. $this->token = $token;
  10. $this->wxuser = $wxuser;
  11. if (!$this->wxuser['encoding_aes_key']) {
  12. $this->pigsecret = $this->token;
  13. }
  14. else{
  15. $this->pigsecret = $this->wxuser['encoding_aes_key'];
  16. }
  17. //https://wx.handday.com/appproxy/books/65804
  18. //658043CD96864573B8B1BAD1AC1ECC65
  19. //132009d373093fd544acdc00e2f260daf38fe41b000
  20. if (IS_GET) {
  21. $xml = file_get_contents("php://input");
  22. if ($this->wxuser['public_type'] == "企业号") {
  23. import("@.ORG.aes.WXBizMsgCrypt");
  24. $sReqMsgSig = $_GET['msg_signature'];
  25. $sReqTimeStamp = $_GET['timestamp'];
  26. $sReqNonce = $_GET['nonce'];
  27. $sReqData = $msg;
  28. $sEchoStr = "";
  29. $pc = new WXBizMsgCrypt($this->wxuser['token'], $this->pigsecret, $this->wxuser['app_id']);
  30. $errCode = $pc->VerifyURL($sReqMsgSig, $sReqTimeStamp, $sReqNonce, $_GET['echostr'], $sEchoStr);
  31. echo $sEchoStr;
  32. exit;
  33. }
  34. else if ($_GET['echostr']){
  35. echo $_GET['echostr'];
  36. exit;
  37. }
  38. else{
  39. \Log::write("@@@@@@@@@@@@@@@",'WARN');
  40. exit;
  41. }
  42. }else {
  43. $xml = file_get_contents("php://input");
  44. if ($this->wxuser['public_type'] == '企业号') {
  45. \Log::write("1111####",'WARN');
  46. $this->data = $this->decodeMsg($xml);
  47. }else {
  48. $xml = new SimpleXMLElement($xml);
  49. $xml || exit;
  50. foreach ($xml as $key => $value) {
  51. $this->data[$key] = strval($value);
  52. }
  53. }
  54. }
  55. }
  56. public function encodeMsg($sRespData) {
  57. $sReqTimeStamp = time();
  58. $sReqNonce = $_GET['nonce'];
  59. $encryptMsg = "";
  60. import("@.ORG.aes.WXBizMsgCrypt");
  61. $pc = new WXBizMsgCrypt($this->wxuser['token'], $this->pigsecret, $this->wxuser['app_id']);
  62. $sRespData = str_replace('<?xml version="1.0"?>', '', $sRespData);
  63. $errCode = $pc->encryptMsg($sRespData, $sReqTimeStamp, $sReqNonce, $encryptMsg);
  64. //\Log::write($errCode,'WARN');
  65. if ($errCode == 0) {
  66. return $encryptMsg;
  67. }else {
  68. return $errCode;
  69. }
  70. }
  71. public function decodeMsg($msg) {
  72. import("@.ORG.aes.WXBizMsgCrypt");
  73. $sReqMsgSig = $_GET['msg_signature'];
  74. $sReqTimeStamp = $_GET['timestamp'];
  75. $sReqNonce = $_GET['nonce'];
  76. $sReqData = $msg;
  77. $sMsg = "";
  78. \Log::write("decodeMsg:token=".$this->wxuser['token']
  79. ."secret=".$this->pigsecret."app_id=".$this->wxuser['app_id'],'WARN');
  80. $pc = new WXBizMsgCrypt($this->wxuser['token'], $this->pigsecret, $this->wxuser['app_id']);
  81. $errCode = $pc->decryptMsg($sReqMsgSig, $sReqTimeStamp, $sReqNonce, $sReqData, $sMsg);
  82. if ($errCode == 0) {
  83. $data = array();
  84. $xml = new SimpleXMLElement($sMsg);
  85. $xml || exit;
  86. foreach ($xml as $key => $value) {
  87. $data[$key] = strval($value);
  88. }
  89. return $data;
  90. }else {
  91. return $errCode;
  92. }
  93. }
  94. /**
  95. * 获取微信推送的数据
  96. * @return array 转换为数组后的数据
  97. */
  98. public function request(){
  99. return $this->data;
  100. }
  101. /**
  102. * * 响应微信发送的信息(自动回复)
  103. * @param string $to 接收用户名
  104. * @param string $from 发送者用户名
  105. * @param array $content 回复信息,文本信息为string类型
  106. * @param string $type 消息类型
  107. * @param string $flag 是否新标刚接受到的信息
  108. * @return string XML字符串
  109. */
  110. public function response($content, $type = 'text', $flag = 0){
  111. /* 基础数据 */
  112. $this->data = array(
  113. 'ToUserName' => $this->data['FromUserName'],
  114. 'FromUserName' => $this->data['ToUserName'],
  115. 'CreateTime' => NOW_TIME,
  116. 'MsgType' => $type,
  117. );
  118. /* 添加类型数据 */
  119. $this->$type($content);
  120. /* 转换数据为XML */
  121. $xml = new SimpleXMLElement('<xml></xml>');
  122. if ($this->wxuser['public_type'] == '企业号') {
  123. $this->data2xml($xml, $this->data);
  124. //\Log::write($xml->asXML(),'WARN');
  125. exit($this->encodeMsg($xml->asXML()));
  126. }else {
  127. /* 添加状态 */
  128. $this->data['FuncFlag'] = $flag;
  129. $this->data2xml($xml, $this->data);
  130. //\Log::write($xml->asXML(),'WARN');
  131. exit($xml->asXML());
  132. }
  133. }
  134. /**
  135. * 回复文本信息
  136. * @param string $content 要回复的信息
  137. */
  138. private function text($content){
  139. $this -> data['Content'] = $content;
  140. }
  141. /**
  142. * 回复音乐信息
  143. * @param string $content 要回复的音乐
  144. */
  145. private function music($music){
  146. list(
  147. $music['Title'],
  148. $music['Description'],
  149. $music['MusicUrl'],
  150. $music['HQMusicUrl']
  151. ) = $music;
  152. $this->data['Music'] = $music;
  153. }
  154. /**
  155. * 回复图文信息
  156. * @param string $news 要回复的图文内容
  157. */
  158. private function news($news){
  159. $articles = array();
  160. foreach ($news as $key => $value) {
  161. list(
  162. $articles[$key]['Title'],
  163. $articles[$key]['Description'],
  164. $articles[$key]['PicUrl'],
  165. $articles[$key]['Url']
  166. ) = $value;
  167. if($key >= 9) { break; } //最多只允许10调新闻
  168. }
  169. $this->data['ArticleCount'] = count($articles);
  170. $this->data['Articles'] = $articles;
  171. }
  172. private function transfer_customer_service($content){
  173. $this->data['Content'] = '';
  174. }
  175. private function data2xml($xml, $data, $item = 'item') {
  176. foreach ($data as $key => $value) {
  177. /* 指定默认的数字key */
  178. is_numeric($key) && $key = $item;
  179. /* 添加子元素 */
  180. if(is_array($value) || is_object($value)){
  181. $child = $xml->addChild($key);
  182. $this->data2xml($child, $value, $item);
  183. } else {
  184. if(is_numeric($value)){
  185. $child = $xml->addChild($key, $value);
  186. } else {
  187. $child = $xml->addChild($key);
  188. $node = dom_import_simplexml($child);
  189. $node->appendChild($node->ownerDocument->createCDATASection($value));
  190. }
  191. }
  192. }
  193. }
  194. private function auth($token, $wxuser = ''){
  195. $signature = $_GET["signature"];
  196. $timestamp = $_GET["timestamp"];
  197. $nonce = $_GET["nonce"];
  198. $tmpArr = array($token, $timestamp, $nonce);
  199. sort($tmpArr, SORT_STRING);
  200. $tmpStr = implode($tmpArr);
  201. $tmpStr = sha1($tmpStr);
  202. if(trim($tmpStr) == trim($signature)){
  203. return true;
  204. }else{
  205. return true;
  206. }
  207. return true;
  208. }
  209. public function getSignPackage() {
  210. $jsapiTicket = $this->getJsApiTicket();
  211. // 注意 URL 一定要动态获取,不能 hardcode.
  212. $protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://";
  213. $url = "$protocol$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";
  214. $timestamp = time();
  215. $nonceStr = $this->createNonceStr();
  216. // 这里参数的顺序要按照 key 值 ASCII 码升序排序
  217. $string = "jsapi_ticket=$jsapiTicket&noncestr=$nonceStr&timestamp=$timestamp&url=$url";
  218. $signature = sha1($string);
  219. $signPackage = array(
  220. "appId" => $this->appId,
  221. "nonceStr" => $nonceStr,
  222. "timestamp" => $timestamp,
  223. "url" => $url,
  224. "signature" => $signature,
  225. "rawString" => $string
  226. );
  227. return $signPackage;
  228. }
  229. private function createNonceStr($length = 16) {
  230. $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
  231. $str = "";
  232. for ($i = 0; $i < $length; $i++) {
  233. $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
  234. }
  235. return $str;
  236. }
  237. private function getJsApiTicket() {
  238. // jsapi_ticket 应该全局存储与更新,以下代码以写入到文件中做示例
  239. $data = json_decode(file_get_contents("jsapi_ticket.json"));
  240. if ($data->expire_time < time()) {
  241. $accessToken = $this->getAccessToken();
  242. // 如果是企业号用以下 URL 获取 ticket
  243. // $url = "https://qyapi.weixin.qq.com/cgi-bin/get_jsapi_ticket?access_token=$accessToken";
  244. $url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi&access_token=$accessToken";
  245. $res = json_decode($this->httpGet($url));
  246. $ticket = $res->ticket;
  247. if ($ticket) {
  248. $data->expire_time = time() + 7000;
  249. $data->jsapi_ticket = $ticket;
  250. $fp = fopen("jsapi_ticket.json", "w");
  251. fwrite($fp, json_encode($data));
  252. fclose($fp);
  253. }
  254. } else {
  255. $ticket = $data->jsapi_ticket;
  256. }
  257. return $ticket;
  258. }
  259. private function getAccessToken() {
  260. // access_token 应该全局存储与更新,以下代码以写入到文件中做示例
  261. $data = json_decode(file_get_contents("access_token.json"));
  262. if ($data->expire_time < time()) {
  263. // 如果是企业号用以下URL获取access_token
  264. // $url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=$this->appId&corpsecret=$this->appSecret";
  265. $url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=$this->appId&secret=$this->appSecret";
  266. $res = json_decode($this->httpGet($url));
  267. $access_token = $res->access_token;
  268. if ($access_token) {
  269. $data->expire_time = time() + 7000;
  270. $data->access_token = $access_token;
  271. $fp = fopen("access_token.json", "w");
  272. fwrite($fp, json_encode($data));
  273. fclose($fp);
  274. }
  275. } else {
  276. $access_token = $data->access_token;
  277. }
  278. return $access_token;
  279. }
  280. private function httpGet($url) {
  281. $curl = curl_init();
  282. curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
  283. curl_setopt($curl, CURLOPT_TIMEOUT, 500);
  284. curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
  285. curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
  286. curl_setopt($curl, CURLOPT_URL, $url);
  287. $res = curl_exec($curl);
  288. curl_close($curl);
  289. return $res;
  290. }
  291. }
  292. ?>