Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.
 
 
 
 
 
 

534 řádky
17 KiB

  1. <?php
  2. /**
  3. *
  4. * ============================================================================
  5. * * 版权所有 运游通 * *
  6. * 网站地址: http://www.zhizhuchuxing.com
  7. * ----------------------------------------------------------------------------
  8. * 这不是一个自由软件!您只能在不用于商业目的的前提下对程序代码进行修改和
  9. * 使用;不允许对程序代码以任何形式任何目的的再发布。
  10. * ============================================================================
  11. * Author By: 倪宗锋
  12. * PhpStorm wxInterface.php
  13. * Create By 2017/1/4 10:55 $
  14. */
  15. namespace WxInterface\Service;
  16. use Util\Util\CurlInterface;
  17. use Util\Util\Util;
  18. use WxInterface\Model\WxInterfaceModel;
  19. class WxInterface
  20. {
  21. //配置参数
  22. private $request = array();
  23. private $response = false;
  24. private $logMsg = '';
  25. private $token = '';
  26. private $appid = '';
  27. private $appsecret = '';
  28. public function __construct()
  29. {
  30. $wxConfig = Util::getWxPayConfig();
  31. $this->token = $wxConfig['token'];
  32. $this->appid = $wxConfig['appid'];
  33. $this->appsecret = $wxConfig['appsecret'];
  34. $this->setLog(date('Y-m-d H:i:s'));
  35. }
  36. /**
  37. * Des:接收参数并处理返回值
  38. * Name: exec
  39. * @return string
  40. * @author 倪宗锋
  41. */
  42. public function exec()
  43. {
  44. $content = $this->getContent();//获取参数并解析
  45. if ($content['MsgType'] == 'text') {
  46. $this->response = $this->textMsg($content);
  47. } elseif ($content['MsgType'] == 'event') {
  48. $this->response = $this->eventMsg($content);
  49. }
  50. return $this->response;
  51. }
  52. /**
  53. * Des:用户输入内容处理
  54. * Name: textMsg
  55. * @param $content
  56. * @return bool|string
  57. * @author 倪宗锋
  58. */
  59. public function textMsg($content)
  60. {
  61. $word = $content['Content'];
  62. return $this->send($word, $content, 'text');
  63. }
  64. /**
  65. * Des:推送事件处理
  66. * Name: eventMsg
  67. * @param $content
  68. * @return string
  69. * @author 倪宗锋
  70. */
  71. public function eventMsg($content)
  72. {
  73. if ($content['Event'] == 'subscribe') {//微信关注事件 发送欢迎语
  74. $word = 'subscribe';
  75. if (empty($content['EventKey']) == false ) {
  76. $EventKey = explode('_',$content['EventKey']);
  77. $textConfig = require ROOT_PATH . '/data/wxConfig/Wx.event.config.php';
  78. if (empty($EventKey[1]) == false && empty($textConfig[$EventKey[1]]) == false) {
  79. $word = $EventKey[1];
  80. }
  81. }
  82. } elseif ($content['Event'] == 'unsubscribe') {//微信关注事件 发送欢迎语
  83. $word = 'unsubscribe';
  84. } elseif ($content['Event'] == 'SCAN') {//扫一扫
  85. $word = 'SCAN';
  86. if (empty($content['EventKey']) == false ) {
  87. $textConfig = require ROOT_PATH . '/data/wxConfig/Wx.event.config.php';
  88. if (empty($textConfig[$content['EventKey']]) == false) {
  89. $word = $content['EventKey'];
  90. }
  91. }
  92. } else if ($content['Event'] == 'VIEW' || empty($content['EventKey'])) {
  93. return false;
  94. } else {
  95. $word = $content['EventKey'];
  96. }
  97. if ($word == 'MSG_LIANXIKEFU') {
  98. return $this->callCuster($content);
  99. }
  100. return $this->send($word, $content, 'event');
  101. }
  102. /**
  103. * Des: 发送处理
  104. * Name: send
  105. * @param $word
  106. * @param $content
  107. * @param string $type 触发类型:text 用户输入 event:推送事件
  108. * @return string
  109. * @author 倪宗锋
  110. */
  111. public function send($word, $content, $type = 'text')
  112. {
  113. $textConfig = require ROOT_PATH . '/data/wxConfig/Wx.' . $type . '.config.php';
  114. if (empty($textConfig[$word]) == false) {//如果 有指定的配置就用指定的配置
  115. $msgSend = $textConfig[$word];
  116. } else if ($type == 'text') {//没有指定的配置 且 接收的是用户输入文本信息
  117. $info = new WxDoFunction();
  118. $getDoResult = $info->showOrderInfo($word);
  119. if ($getDoResult == '') {
  120. //默认联系客服
  121. $msgSend = $this->callCuster($content);
  122. return $msgSend;
  123. } else {
  124. $msgSend = $getDoResult;
  125. }
  126. } else {//没有指定配置 且接收的是按钮或扫一扫则直接返回关注自动回复信息
  127. $msgSend = $textConfig['subscribe'];
  128. }
  129. $this->setLog('sendMsg:' . print_r($msgSend, 1));//日志记录
  130. Util::setLogs(json_encode($msgSend));
  131. if (is_array($msgSend) && empty($msgSend['function']) == false) {//当推送事件有方法指定时,则调用该方法
  132. $wxDoFunction = new WxDoFunction();
  133. $function = $msgSend['function'];
  134. $wxDoFunction->$function($content);
  135. }
  136. if (isset($msgSend['type']) && $msgSend['type'] == 'news') {//如果是图文类型
  137. return $this->sendNews($content, $msgSend);
  138. } elseif (isset($msgSend['type']) && $msgSend['type'] == 'img') {//如果是图片类型
  139. return $this->sendImage($content, $msgSend['id']);
  140. } elseif (isset($msgSend['type']) && $msgSend['type'] == 'voice') {//如果是语音类型
  141. return $this->sendVoice($content, $msgSend['id']);
  142. } elseif (isset($msgSend['type']) && $msgSend['type'] == 'video') {//如果是视频类型
  143. return $this->sendVideo($content, $msgSend);
  144. } else {
  145. return $this->sendText($content, $msgSend);
  146. }
  147. }
  148. /**
  149. * Des:联系客服
  150. * Name: sendText
  151. * @param $content
  152. * @return string
  153. * @author 倪宗锋
  154. */
  155. private function callCuster($content)
  156. {
  157. $textTpl = '' . "
  158. <xml>
  159. <ToUserName><![CDATA[%s]]></ToUserName>
  160. <FromUserName><![CDATA[%s]]></FromUserName>
  161. <CreateTime>%s</CreateTime>
  162. <MsgType><![CDATA[transfer_customer_service]]></MsgType>
  163. </xml>";
  164. $resultStr = sprintf($textTpl, $content['FromUserName'], $content['ToUserName'], time());
  165. return $resultStr;
  166. }
  167. /**
  168. * Des:发送文字
  169. * Name: sendText
  170. * @param $content
  171. * @param $msgSend
  172. * @return string
  173. * @author 倪宗锋
  174. */
  175. private function sendText($content, $msgSend)
  176. {
  177. $textTpl = '' . "
  178. <xml>
  179. <ToUserName><![CDATA[%s]]></ToUserName>
  180. <FromUserName><![CDATA[%s]]></FromUserName>
  181. <CreateTime>%s</CreateTime>
  182. <MsgType><![CDATA[%s]]></MsgType>
  183. <Content><![CDATA[%s]]></Content>
  184. </xml>";
  185. $msgType = "text";
  186. if (is_array($msgSend)) {
  187. $msgSend = $msgSend['text'];
  188. }
  189. $resultStr = sprintf($textTpl, $content['FromUserName'], $content['ToUserName'], time(), $msgType, $msgSend);
  190. return $resultStr;
  191. }
  192. /**
  193. * Des:发送图文
  194. * Name: sendNews
  195. * @param $content array
  196. * @param $msgSend array
  197. * @return string
  198. * @author 倪宗锋
  199. */
  200. private function sendNews($content, $msgSend)
  201. {
  202. $news = $this->getNewsByMediaId($msgSend);
  203. return $this->transmitNews($content, $news);
  204. }
  205. /**
  206. * Des:发送图片
  207. * Name: sendImage
  208. * @param $content
  209. * @param $mediaId
  210. * @return string
  211. * @author 倪宗锋
  212. */
  213. private function sendImage($content, $mediaId)
  214. {
  215. $xmlTpl = '' . "<xml>
  216. <ToUserName><![CDATA[%s]]></ToUserName>
  217. <FromUserName><![CDATA[%s]]></FromUserName>
  218. <CreateTime>%s</CreateTime>
  219. <MsgType><![CDATA[image]]></MsgType>
  220. <Image>
  221. <MediaId><![CDATA[%s]]></MediaId>
  222. </Image>
  223. </xml>";
  224. $result = sprintf($xmlTpl, $content['FromUserName'], $content['ToUserName'], time(), $mediaId);
  225. return $result;
  226. }
  227. /**
  228. * Des:发送语音
  229. * Name: sendVoice
  230. * @param $content
  231. * @param $mediaId
  232. * @return string
  233. * @author 倪宗锋
  234. */
  235. private function sendVoice($content, $mediaId)
  236. {
  237. $xmlTpl = '' . "<xml>
  238. <ToUserName><![CDATA[%s]]></ToUserName>
  239. <FromUserName><![CDATA[%s]]></FromUserName>
  240. <CreateTime>%s</CreateTime>
  241. <MsgType><![CDATA[voice]]></MsgType>
  242. <Voice>
  243. <MediaId><![CDATA[%s]]></MediaId>
  244. </Voice>
  245. </xml>";
  246. $result = sprintf($xmlTpl, $content['FromUserName'], $content['ToUserName'], time(), $mediaId);
  247. return $result;
  248. }
  249. /**
  250. * Des:发送视频
  251. * Name: sendVideo
  252. * @param $content
  253. * @param $sendMsg
  254. * @return string
  255. * @author 倪宗锋
  256. */
  257. private function sendVideo($content, $sendMsg)
  258. {
  259. $xmlTpl = '' . "<xml>
  260. <ToUserName><![CDATA[%s]]></ToUserName>
  261. <FromUserName><![CDATA[%s]]></FromUserName>
  262. <CreateTime>%s</CreateTime>
  263. <MsgType><![CDATA[video]]></MsgType>
  264. <Video>
  265. <MediaId><![CDATA[%s]]></MediaId>
  266. <Title><![CDATA[%s]]></Title>
  267. <Description><![CDATA[%s]]></Description>
  268. </Video>
  269. </xml>";
  270. $result = sprintf($xmlTpl, $content['FromUserName'], $content['ToUserName'], time(), $sendMsg['id'], $sendMsg["title"], $sendMsg["des"]);
  271. return $result;
  272. }
  273. /**
  274. * Des:根据ID获取图文信息
  275. * Name: getNewsByMediaId
  276. * @param $msgSend array
  277. * @return array
  278. * @author 倪宗锋
  279. */
  280. public function getNewsByMediaId($msgSend)
  281. {
  282. $data_media_id = '{"media_id":"' . $msgSend['id'] . '"}';
  283. $url = "https://api.weixin.qq.com/cgi-bin/material/get_material?access_token=" . $this->getAccessToken();
  284. $response = $this->_requestPost($url, $data_media_id);
  285. $media = json_decode($response, true);
  286. $mediaArray = $media['news_item'];
  287. $content = array();
  288. foreach ($mediaArray as $k => $v) {
  289. if (isset($msgSend['url'])) {
  290. $v['url'] = $msgSend['url'];
  291. $v['content_source_url'] = $msgSend['url'];
  292. }
  293. if ($k == 0 || $k == 1) {
  294. $content[] = array("Title" => $v['title'], "Description" => $v['digest'], "PicUrl" => $v['thumb_url'], "Url" => $v['url']);
  295. }elseif ($k == 2) {
  296. $content[] = array("Title" => $v['title'], "Description" => $v['digest'], "PicUrl" => $v['thumb_url'], "Url" => $v['content_source_url']);
  297. } else
  298. $content[] = array("Title" => $v['title'], "Description" => $v['digest'], "PicUrl" => $v['thumb_url'], "Url" => $v['content_source_url']);
  299. }
  300. return $content;
  301. }
  302. /**
  303. * Des:图文推送数据处理
  304. * Name: transmitNews
  305. * @param $content
  306. * @param $newsArray
  307. * @return string
  308. * @author 倪宗锋
  309. */
  310. private function transmitNews($content, $newsArray)
  311. {
  312. if (!is_array($newsArray)) {
  313. return '';
  314. }
  315. $itemTpl = '' . "<item><Title><![CDATA[%s]]></Title>
  316. <Description><![CDATA[%s]]></Description>
  317. <PicUrl><![CDATA[%s]]></PicUrl>
  318. <Url><![CDATA[%s]]></Url></item>";
  319. $item_str = "";
  320. foreach ($newsArray as $item) {
  321. $item_str .= sprintf($itemTpl, $item['Title'], $item['Description'], $item['PicUrl'], $item['Url']);
  322. }
  323. $xmlTpl = '' . "<xml>
  324. <ToUserName><![CDATA[{$content['FromUserName']}]]></ToUserName>
  325. <FromUserName><![CDATA[{$content['ToUserName']}]]></FromUserName>
  326. <CreateTime>" . time() . "</CreateTime>
  327. <MsgType><![CDATA[news]]></MsgType>
  328. <ArticleCount>" . count($newsArray) . "</ArticleCount>
  329. <Articles>$item_str</Articles>
  330. </xml>";
  331. // $result = sprintf($xmlTpl, $content['FromUserName'], $content['ToUserName'], time(), count($newsArray));
  332. return $xmlTpl;
  333. }
  334. /*************************=========第一次请求校验==========***********************************/
  335. /**
  336. * Des:第一次校验
  337. * Name: valid
  338. * @return bool
  339. * @author 倪宗锋
  340. */
  341. public function valid()
  342. {
  343. $echoStr = $_GET["echostr"];
  344. if ($this->checkSignature()) {
  345. $this->response = $echoStr;
  346. }
  347. return $this->response;
  348. }
  349. /**
  350. * Des:数据校验
  351. * Name: checkSignature
  352. * @return bool
  353. * @author 倪宗锋
  354. */
  355. private function checkSignature()
  356. {
  357. $token = $this->token;
  358. $signature = isset($_GET["signature"]) ? $_GET["signature"] : "";
  359. $timestamp = isset($_GET["timestamp"]) ? $_GET["timestamp"] : "";
  360. $nonce = isset($_GET["nonce"]) ? $_GET["nonce"] : "";
  361. $tmpArr = array($token, $timestamp, $nonce);
  362. $this->setLog('param:' . print_r($tmpArr, 1));
  363. sort($tmpArr, SORT_STRING);
  364. $tmpStr = implode($tmpArr);
  365. $tmpStr = sha1($tmpStr);
  366. if ($tmpStr == $signature) {
  367. return true;
  368. } else {
  369. return false;
  370. }
  371. }
  372. /**
  373. * Des:参数解析
  374. * Name: getContent
  375. * @author 倪宗锋
  376. */
  377. private function getContent()
  378. {
  379. $content = file_get_contents("php://input");
  380. // $content = "<xml><ToUserName><![CDATA[gh_358ca80fc02a]]></ToUserName>\n<FromUserName><![CDATA[owEylwhtT-zr5klahSms6hPAfK1E]]></FromUserName>\n<CreateTime>1492567969</CreateTime>\n<MsgType><![CDATA[event]]></MsgType>\n<Event><![CDATA[subscribe]]></Event>\n<EventKey><![CDATA[]]></EventKey>\n</xml>";
  381. $this->setLog('content: ' . print_r($content, 1));
  382. libxml_disable_entity_loader(true);
  383. $this->request = (array)simplexml_load_string($content, 'SimpleXMLElement', LIBXML_NOCDATA);
  384. return $this->request;
  385. }
  386. /**
  387. * Des:获取token
  388. * Name: getAccessToken
  389. * @return string
  390. * @author 倪宗锋
  391. */
  392. public static function getAccessToken()
  393. {
  394. $wxConfig = Util::getWxPayConfig();
  395. $appid = $wxConfig['appid'];
  396. $appsecret = $wxConfig['appsecret'];
  397. $time = time();
  398. $data['appid'] = $appid;
  399. $data['appsecret'] = $appsecret;
  400. $data['time'] = $time;
  401. $param = [
  402. 'code' => Util::authCode(http_build_query($data), 'ENCODE'),
  403. 'time' => $time
  404. ];
  405. $curl = new CurlInterface($param, 4);
  406. $siteConfig = Util::getSiteConfig();
  407. $return = $curl->execute($siteConfig['wx_get_token'] . '/zzcx/interfaces/fx/get-wx-token', 'POST');
  408. return $return;
  409. }
  410. /**
  411. * Des:发起get请求
  412. * Name: _requestGet
  413. * @param $url string
  414. * @param bool|true $ssl
  415. * @return bool|mixed
  416. * @author 倪宗锋
  417. */
  418. public static function _requestGet($url, $ssl = true)
  419. {
  420. $curl = curl_init();
  421. curl_setopt($curl, CURLOPT_URL, $url);
  422. curl_setopt($curl, CURLOPT_AUTOREFERER, true);
  423. if ($ssl) {
  424. curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
  425. curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);
  426. }
  427. curl_setopt($curl, CURLOPT_HEADER, false);
  428. curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
  429. $response = curl_exec($curl);
  430. if ($response === false) {
  431. return false;
  432. }
  433. return $response;
  434. }
  435. /**
  436. * Des:发起post请求
  437. * Name: _requestPost
  438. * @param $url
  439. * @param $data
  440. * @param bool|true $ssl
  441. * @return bool|mixed
  442. * @author 倪宗锋
  443. */
  444. public static function _requestPost($url, $data, $ssl = true)
  445. {
  446. $curl = curl_init();
  447. curl_setopt($curl, CURLOPT_URL, $url);
  448. $user_agent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '';
  449. curl_setopt($curl, CURLOPT_USERAGENT, $user_agent);
  450. curl_setopt($curl, CURLOPT_AUTOREFERER, true);
  451. if ($ssl) {
  452. curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
  453. curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 1);
  454. }
  455. curl_setopt($curl, CURLOPT_POST, true);
  456. curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
  457. curl_setopt($curl, CURLOPT_HEADER, false);
  458. curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
  459. $response = curl_exec($curl);
  460. if ($response === false) {
  461. return false;
  462. }
  463. return $response;
  464. }
  465. /**
  466. * Des:获取
  467. * Name: httpRequest
  468. * @param $url
  469. * @param null $data
  470. * @return mixed
  471. * @author 倪宗锋
  472. */
  473. static function httpRequest($url, $data = null)
  474. {
  475. $ch = curl_init();
  476. curl_setopt($ch, CURLOPT_URL, $url);
  477. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
  478. curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
  479. if (!empty($data)) {
  480. curl_setopt($ch, CURLOPT_POST, 1);
  481. curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
  482. }
  483. curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  484. $output = curl_exec($ch);
  485. curl_close($ch);
  486. return $output;
  487. }
  488. public function setLog($logMsg)
  489. {
  490. $logMsg = str_replace(PHP_EOL, '', $logMsg);
  491. $logMsg = preg_replace("/\s(?=\s)/", "\\1", $logMsg);
  492. $this->logMsg .= $logMsg . PHP_EOL;
  493. }
  494. /**
  495. * 项目关闭 写入日志
  496. */
  497. public function __destruct()
  498. {
  499. $this->setLog(print_r($this->response, 1));//写入返回值
  500. $fileName = ROOT_PATH . '/data/log/WXLog/wxinterface' . date('Y-m-d') . '.log';
  501. file_put_contents($fileName, $this->logMsg . PHP_EOL, FILE_APPEND);
  502. }
  503. }