weixin.account.class.php 64 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973
  1. <?php
  2. /**
  3. * [WeEngine System] Copyright (c) 2014 WE7.CC
  4. * WeEngine is NOT a free software, it under the license terms, visited http://www.we7.cc/ for more details.
  5. */
  6. defined('IN_IA') or exit('Access Denied');
  7. class WeixinAccount extends WeAccount {
  8. protected $tablename = 'account_wechats';
  9. protected $menuFrame = 'account';
  10. protected $type = ACCOUNT_TYPE_OFFCIAL_NORMAL;
  11. protected $typeName = '公众号';
  12. protected $typeSign = ACCOUNT_TYPE_SIGN;
  13. public $types = array(
  14. 'view', 'click', 'scancode_push',
  15. 'scancode_waitmsg', 'pic_sysphoto', 'pic_photo_or_album',
  16. 'pic_weixin', 'location_select', 'media_id', 'view_limited',
  17. );
  18. protected function getAccountInfo($uniacid) {
  19. $account = table('account_wechats')->getAccount($uniacid);
  20. $account['encrypt_key'] = empty($account['key']) ? '' : $account['key'];
  21. return $account;
  22. }
  23. public function checkSign() {
  24. $token = $this->account['token'];
  25. $signkey = array($token, $_GET['timestamp'], $_GET['nonce']);
  26. sort($signkey, SORT_STRING);
  27. $signString = implode($signkey);
  28. $signString = sha1($signString);
  29. return $signString == $_GET['signature'];
  30. }
  31. public function checkSignature($encrypt_msg) {
  32. $str = $this->buildSignature($encrypt_msg);
  33. return $str == $_GET['msg_signature'];
  34. }
  35. public function local_checkSignature($packet) {
  36. $token = $this->account['token'];
  37. $array = array($packet['Encrypt'], $token, $packet['TimeStamp'], $packet['Nonce']);
  38. sort($array, SORT_STRING);
  39. $str = implode($array);
  40. $str = sha1($str);
  41. return $str == $packet['MsgSignature'];
  42. }
  43. public function local_decryptMsg($postData) {
  44. $token = $this->account['token'];
  45. $encodingaeskey = $this->account['encodingaeskey'];
  46. $appid = $this->account['encrypt_key'];
  47. if (43 != strlen($encodingaeskey)) {
  48. return error(-1, "微信公众平台返回接口错误. \n错误代码为: 40004 \n,错误描述为: " . $this->encryptErrorCode('40004'));
  49. }
  50. $key = base64_decode($encodingaeskey . '=');
  51. $packet = $this->local_xmlExtract($postData);
  52. if (is_error($packet)) {
  53. return error(-1, $packet['message']);
  54. }
  55. $istrue = $this->local_checkSignature($packet);
  56. if (!$istrue) {
  57. return error(-1, "微信公众平台返回接口错误. \n错误代码为: 40001 \n,错误描述为: " . $this->encryptErrorCode('40001'));
  58. }
  59. $ciphertext_dec = base64_decode($packet['Encrypt']);
  60. $iv = substr($key, 0, 16);
  61. $decrypted = openssl_decrypt($ciphertext_dec, 'AES-256-CBC', $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);
  62. $block_size = 32;
  63. $pad = ord(substr($decrypted, -1));
  64. if ($pad < 1 || $pad > 32) {
  65. $pad = 0;
  66. }
  67. $result = substr($decrypted, 0, (strlen($decrypted) - $pad));
  68. if (strlen($result) < 16) {
  69. return '';
  70. }
  71. $content = substr($result, 16, strlen($result));
  72. $len_list = unpack('N', substr($content, 0, 4));
  73. $xml_len = $len_list[1];
  74. $xml_content = substr($content, 4, $xml_len);
  75. $from_appid = substr($content, $xml_len + 4);
  76. if ($from_appid != $appid) {
  77. return error(-1, "微信公众平台返回接口错误. \n错误代码为: 40005 \n,错误描述为: " . $this->encryptErrorCode('40005'));
  78. }
  79. return $xml_content;
  80. }
  81. public function buildSignature($encrypt_msg) {
  82. $token = $this->account['token'];
  83. $array = array($encrypt_msg, $token, $_GET['timestamp'], $_GET['nonce']);
  84. sort($array, SORT_STRING);
  85. $str = implode($array);
  86. $str = sha1($str);
  87. return $str;
  88. }
  89. public function encryptMsg($text) {
  90. $token = $this->account['token'];
  91. $encodingaeskey = $this->account['encodingaeskey'];
  92. $appid = $this->account['encrypt_key'];
  93. $key = base64_decode($encodingaeskey . '=');
  94. $text = random(16) . pack('N', strlen($text)) . $text . $appid;
  95. $iv = substr($key, 0, 16);
  96. $block_size = 32;
  97. $text_length = strlen($text);
  98. $amount_to_pad = $block_size - ($text_length % $block_size);
  99. if (0 == $amount_to_pad) {
  100. $amount_to_pad = $block_size;
  101. }
  102. $pad_chr = chr($amount_to_pad);
  103. $tmp = '';
  104. for ($index = 0; $index < $amount_to_pad; ++$index) {
  105. $tmp .= $pad_chr;
  106. }
  107. $text = $text . $tmp;
  108. $encrypted = openssl_encrypt($text, 'AES-256-CBC', $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);
  109. $encrypt_msg = base64_encode($encrypted);
  110. $signature = $this->buildSignature($encrypt_msg);
  111. return array($signature, $encrypt_msg);
  112. }
  113. public function decryptMsg($postData) {
  114. $token = $this->account['token'];
  115. $encodingaeskey = $this->account['encodingaeskey'];
  116. $appid = $this->account['encrypt_key'];
  117. $key = base64_decode($encodingaeskey . '=');
  118. if (43 != strlen($encodingaeskey)) {
  119. return error(-1, "微信公众平台返回接口错误. \n错误代码为: 40004 \n,错误描述为: " . $this->encryptErrorCode('40004'));
  120. }
  121. $packet = $this->xmlExtract($postData);
  122. if (is_error($packet)) {
  123. return error(-1, $packet['message']);
  124. }
  125. $istrue = $this->checkSignature($packet['encrypt']);
  126. if (!$istrue) {
  127. return error(-1, "微信公众平台返回接口错误. \n错误代码为: 40001 \n,错误描述为: " . $this->encryptErrorCode('40001'));
  128. }
  129. $ciphertext_dec = base64_decode($packet['encrypt']);
  130. $iv = substr($key, 0, 16);
  131. $decrypted = openssl_decrypt($ciphertext_dec, 'AES-256-CBC', $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);
  132. $pad = ord(substr($decrypted, -1));
  133. if ($pad < 1 || $pad > 32) {
  134. $pad = 0;
  135. }
  136. $result = substr($decrypted, 0, (strlen($decrypted) - $pad));
  137. if (strlen($result) < 16) {
  138. return '';
  139. }
  140. $content = substr($result, 16, strlen($result));
  141. $len_list = unpack('N', substr($content, 0, 4));
  142. $xml_len = $len_list[1];
  143. $xml_content = substr($content, 4, $xml_len);
  144. $from_appid = substr($content, $xml_len + 4);
  145. if ($from_appid != $appid) {
  146. return error(-1, "微信公众平台返回接口错误. \n错误代码为: 40005 \n,错误描述为: " . $this->encryptErrorCode('40005'));
  147. }
  148. return $xml_content;
  149. }
  150. public function xmlDetract($data) {
  151. $xml['Encrypt'] = $data[1];
  152. $xml['MsgSignature'] = $data[0];
  153. $xml['TimeStamp'] = $_GET['timestamp'];
  154. $xml['Nonce'] = $_GET['nonce'];
  155. return array2xml($xml);
  156. }
  157. public function xmlExtract($message) {
  158. $packet = array();
  159. if (!empty($message)) {
  160. $obj = isimplexml_load_string($message, 'SimpleXMLElement', LIBXML_NOCDATA);
  161. if ($obj instanceof SimpleXMLElement) {
  162. $packet['encrypt'] = strval($obj->Encrypt);
  163. $packet['to'] = strval($obj->ToUserName);
  164. }
  165. }
  166. if (!empty($packet['encrypt'])) {
  167. return $packet;
  168. } else {
  169. return error(-1, "微信公众平台返回接口错误. \n错误代码为: 40002 \n,错误描述为: " . $this->encryptErrorCode('40002'));
  170. }
  171. }
  172. public function local_xmlExtract($message) {
  173. $packet = array();
  174. if (!empty($message)) {
  175. $obj = isimplexml_load_string($message, 'SimpleXMLElement', LIBXML_NOCDATA);
  176. if ($obj instanceof SimpleXMLElement) {
  177. $packet['Encrypt'] = strval($obj->Encrypt);
  178. $packet['MsgSignature'] = strval($obj->MsgSignature);
  179. $packet['TimeStamp'] = strval($obj->TimeStamp);
  180. $packet['Nonce'] = strval($obj->Nonce);
  181. }
  182. }
  183. if (!empty($packet)) {
  184. return $packet;
  185. } else {
  186. return error(-1, "微信公众平台返回接口错误. \n错误代码为: 40002 \n,错误描述为: " . $this->encryptErrorCode('40002'));
  187. }
  188. }
  189. public function menuCreate($menu) {
  190. global $_W;
  191. $token = $this->getAccessToken();
  192. if (is_error($token)) {
  193. return $token;
  194. }
  195. $url = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token={$token}";
  196. if (!empty($menu['matchrule'])) {
  197. $url = "https://api.weixin.qq.com/cgi-bin/menu/addconditional?access_token={$token}";
  198. }
  199. $data = urldecode(json_encode($menu));
  200. $response = ihttp_post($url, $data);
  201. if (is_error($response)) {
  202. return error(-1, "访问公众平台接口失败, 错误: {$response['message']}");
  203. }
  204. $result = @json_decode($response['content'], true);
  205. if (!empty($result['errcode'])) {
  206. return error(-1, "访问微信接口错误, 错误代码: {$result['errcode']}, 错误信息: {$result['errmsg']},错误详情:{$this->errorCode($result['errcode'])}");
  207. }
  208. return empty($result['menuid']) ? 0 : $result['menuid'];
  209. }
  210. public function menuBuild($data_array, $is_conditional = false) {
  211. $menu = array();
  212. if (empty($data_array) || empty($data_array['button']) || !is_array($data_array)) {
  213. return $menu;
  214. }
  215. foreach ($data_array['button'] as $button) {
  216. $temp = array();
  217. $temp['name'] = preg_replace_callback('/\:\:([0-9a-zA-Z_-]+)\:\:/', function ($matches) {
  218. return utf8_bytes(hexdec($matches[1]));
  219. }, $button['name']);
  220. $temp['name'] = urlencode($temp['name']);
  221. if (empty($button['sub_button'])) {
  222. $temp['type'] = $button['type'];
  223. if ('view' == $button['type']) {
  224. $temp['url'] = urlencode($button['url']);
  225. } elseif ('click' == $button['type']) {
  226. if (!empty($button['article_id'])) {
  227. if (!empty($button['article_id']) && empty($button['key'])) {
  228. $temp['article_id'] = urlencode($button['article_id']);
  229. $temp['type'] = 'article_id';
  230. } elseif (empty($button['article_id']) && !empty($button['key'])) {
  231. $temp['type'] = 'click';
  232. $temp['key'] = urlencode($button['key']);
  233. }
  234. } else {
  235. if (!empty($button['media_id']) && empty($button['key'])) {
  236. $temp['media_id'] = urlencode($button['media_id']);
  237. $temp['type'] = 'media_id';
  238. } elseif (empty($button['media_id']) && !empty($button['key'])) {
  239. $temp['type'] = 'click';
  240. $temp['key'] = urlencode($button['key']);
  241. }
  242. }
  243. } elseif ('media_id' == $button['type']) {
  244. $temp['media_id'] = urlencode($button['media_id']);
  245. } elseif ('article_id' == $button['type'] || 'article_view_limited' == $button['type']) {
  246. $temp['article_id'] = urlencode($button['article_id']);
  247. } elseif ('miniprogram' == $button['type']) {
  248. $temp['appid'] = trim($button['appid']);
  249. $temp['pagepath'] = urlencode($button['pagepath']);
  250. $temp['url'] = urlencode($button['url']);
  251. } else {
  252. $temp['key'] = urlencode($button['key']);
  253. }
  254. } else {
  255. $button['sub_button'] = !empty($button['sub_button']['list']) ? $button['sub_button']['list'] : $button['sub_button'];
  256. foreach ($button['sub_button'] as $sub_button) {
  257. $sub_temp = array();
  258. $sub_temp['name'] = preg_replace_callback('/\:\:([0-9a-zA-Z_-]+)\:\:/', function ($matches) {
  259. return utf8_bytes(hexdec($matches[1]));
  260. }, $sub_button['name']);
  261. $sub_temp['name'] = urlencode($sub_temp['name']);
  262. $sub_temp['type'] = $sub_button['type'];
  263. if ('view' == $sub_button['type']) {
  264. $sub_temp['url'] = urlencode($sub_button['url']);
  265. } elseif ('click' == $sub_button['type']) {
  266. if (!empty($sub_button['article_id'])) {
  267. if (!empty($sub_button['article_id']) && empty($sub_button['key'])) {
  268. $sub_temp['article_id'] = urlencode($sub_button['article_id']);
  269. $sub_temp['type'] = 'article_id';
  270. } elseif (empty($sub_button['article_id']) && !empty($sub_button['key'])) {
  271. $sub_temp['type'] = 'click';
  272. $sub_temp['key'] = urlencode($sub_button['key']);
  273. }
  274. } else {
  275. if (!empty($sub_button['media_id']) && empty($sub_button['key'])) {
  276. $sub_temp['media_id'] = urlencode($sub_button['media_id']);
  277. $sub_temp['type'] = 'media_id';
  278. } elseif (empty($sub_button['media_id']) && !empty($sub_button['key'])) {
  279. $sub_temp['type'] = 'click';
  280. $sub_temp['key'] = urlencode($sub_button['key']);
  281. }
  282. }
  283. } elseif ('media_id' == $sub_button['type']) {
  284. $sub_temp['media_id'] = urlencode($sub_button['media_id']);
  285. } elseif ('article_id' == $sub_button['type'] || 'article_view_limited' == $sub_button['type']) {
  286. $sub_temp['article_id'] = urlencode($sub_button['article_id']);
  287. } elseif ('miniprogram' == $sub_button['type']) {
  288. $sub_temp['appid'] = trim($sub_button['appid']);
  289. $sub_temp['pagepath'] = urlencode($sub_button['pagepath']);
  290. $sub_temp['url'] = urlencode($sub_button['url']);
  291. } else {
  292. $sub_temp['key'] = urlencode($sub_button['key']);
  293. }
  294. $temp['sub_button'][] = $sub_temp;
  295. }
  296. }
  297. $menu['button'][] = $temp;
  298. }
  299. if (empty($is_conditional) || empty($data_array['matchrule']) || !is_array($data_array['matchrule'])) {
  300. return $menu;
  301. }
  302. $data_array['matchrule']['group_id'] = empty($data_array['matchrule']['group_id']) ? 0 : $data_array['matchrule']['group_id'];
  303. $data_array['matchrule']['client_platform_type'] = empty($data_array['matchrule']['client_platform_type']) ? 0 : $data_array['matchrule']['client_platform_type'];
  304. if ($data_array['matchrule']['group_id'] != -1) {
  305. $menu['matchrule']['tag_id'] = $data_array['matchrule']['group_id'];
  306. }
  307. if ($data_array['matchrule']['client_platform_type'] > 0) {
  308. $menu['matchrule']['client_platform_type'] = $data_array['matchrule']['client_platform_type'];
  309. }
  310. return $menu;
  311. }
  312. public function menuDelete($menuid = 0) {
  313. $token = $this->getAccessToken();
  314. if (is_error($token)) {
  315. return $token;
  316. }
  317. if ($menuid > 0) {
  318. $url = "https://api.weixin.qq.com/cgi-bin/menu/delconditional?access_token={$token}";
  319. $data = array(
  320. 'menuid' => $menuid,
  321. );
  322. $response = ihttp_post($url, json_encode($data));
  323. } else {
  324. $url = "https://api.weixin.qq.com/cgi-bin/menu/delete?access_token={$token}";
  325. $response = ihttp_get($url);
  326. }
  327. if (is_error($response)) {
  328. return error(-1, "访问公众平台接口失败, 错误: {$response['message']}");
  329. }
  330. $result = @json_decode($response['content'], true);
  331. if (!empty($result['errcode'])) {
  332. return error(-1, "访问微信接口错误, 错误代码: {$result['errcode']}, 错误信息: {$result['errmsg']},错误详情:{$this->errorCode($result['errcode'])}");
  333. }
  334. return true;
  335. }
  336. public function menuModify($menu) {
  337. return $this->menuCreate($menu);
  338. }
  339. public function menuCurrentQuery() {
  340. $token = $this->getAccessToken();
  341. if (is_error($token)) {
  342. return $token;
  343. }
  344. $url = "https://api.weixin.qq.com/cgi-bin/get_current_selfmenu_info?access_token={$token}";
  345. return $this->requestApi($url);
  346. }
  347. public function menuQuery() {
  348. $token = $this->getAccessToken();
  349. if (is_error($token)) {
  350. return $token;
  351. }
  352. $url = "https://api.weixin.qq.com/cgi-bin/menu/get?access_token={$token}";
  353. $response = ihttp_get($url);
  354. if (is_error($response)) {
  355. return error(-1, "访问公众平台接口失败, 错误: {$response['message']}");
  356. }
  357. $result = @json_decode($response['content'], true);
  358. if (!empty($result['errcode']) && '46003' != $result['errcode']) {
  359. return error(-1, "访问微信接口错误, 错误代码: {$result['errcode']}, 错误信息: {$result['errmsg']},错误详情:{$this->errorCode($result['errcode'])}");
  360. }
  361. return $result;
  362. }
  363. public function fansQueryInfo($uniid, $isOpen = true) {
  364. if ($isOpen) {
  365. $openid = $uniid;
  366. } else {
  367. exit('error');
  368. }
  369. $token = $this->getAccessToken();
  370. if (is_error($token)) {
  371. return $token;
  372. }
  373. $url = "https://api.weixin.qq.com/cgi-bin/user/info?access_token={$token}&openid={$openid}&lang=zh_CN";
  374. $response = ihttp_get($url);
  375. if (is_error($response)) {
  376. return error(-1, "访问公众平台接口失败, 错误: {$response['message']}");
  377. }
  378. preg_match('/city":"(.*)","province":"(.*)","country":"(.*)"/U', $response['content'], $reg_arr);
  379. $reg_arr[1] = empty($reg_arr[1]) ? '' : $reg_arr[1];
  380. $reg_arr[2] = empty($reg_arr[2]) ? '' : $reg_arr[2];
  381. $reg_arr[3] = empty($reg_arr[3]) ? '' : $reg_arr[3];
  382. $city = htmlentities(bin2hex($reg_arr[1]));
  383. $province = htmlentities(bin2hex($reg_arr[2]));
  384. $country = htmlentities(bin2hex($reg_arr[3]));
  385. $response['content'] = str_replace('"city":"' . $reg_arr[1] . '","province":"' . $reg_arr[2] . '","country":"' . $reg_arr[3] . '"', '"city":"' . $city . '","province":"' . $province . '","country":"' . $country . '"', $response['content']);
  386. $result = @json_decode($response['content'], true);
  387. $result['city'] = empty($result['city']) ? '' : hex2bin(html_entity_decode($result['city']));
  388. $result['province'] = empty($result['province']) ? '' : hex2bin(html_entity_decode($result['province']));
  389. $result['country'] = empty($result['country']) ? '' : hex2bin(html_entity_decode($result['country']));
  390. $result['headimgurl'] = empty($result['headimgurl']) ? '' : str_replace('http:', 'https:', $result['headimgurl']);
  391. unset($result['remark'], $result['subscribe_scene'], $result['qr_scene'], $result['qr_scene_str']);
  392. if (empty($result)) {
  393. return error(-1, "接口调用失败, 元数据: {$response['meta']}");
  394. } elseif (!empty($result['errcode'])) {
  395. return error($result['errcode'], "访问微信接口错误, 错误代码: {$result['errcode']}, 错误信息: {$result['errmsg']},错误详情:{$this->errorCode($result['errcode'])}");
  396. }
  397. return $result;
  398. }
  399. public function fansBatchQueryInfo($data) {
  400. if (empty($data)) {
  401. return error(-1, '粉丝openid错误');
  402. }
  403. foreach ($data as $da) {
  404. $post[] = array(
  405. 'openid' => trim($da),
  406. 'lang' => 'zh_CN',
  407. );
  408. }
  409. $data = array();
  410. $data['user_list'] = $post;
  411. $token = $this->getAccessToken();
  412. if (is_error($token)) {
  413. return $token;
  414. }
  415. $url = "https://api.weixin.qq.com/cgi-bin/user/info/batchget?access_token={$token}";
  416. $response = ihttp_post($url, json_encode($data));
  417. if (is_error($response)) {
  418. return error(-1, "访问公众平台接口失败, 错误: {$response['message']}");
  419. }
  420. $result = @json_decode($response['content'], true);
  421. if (empty($result)) {
  422. return error(-1, "接口调用失败, 元数据: {$response['meta']}");
  423. } elseif (!empty($result['errcode'])) {
  424. return error(-1, "访问微信接口错误, 错误代码: {$result['errcode']}, 错误信息: {$result['errmsg']},错误详情:{$this->errorCode($result['errcode'])}");
  425. }
  426. return $result['user_info_list'];
  427. }
  428. public function fansAll($startopenid = '') {
  429. global $_GPC;
  430. $token = $this->getAccessToken();
  431. if (is_error($token)) {
  432. return $token;
  433. }
  434. $url = 'https://api.weixin.qq.com/cgi-bin/user/get?access_token=' . $token;
  435. if (!empty($_GPC['next_openid'])) {
  436. $startopenid = safe_gpc_string($_GPC['next_openid']);
  437. }
  438. if (!empty($startopenid)) {
  439. $url .= '&next_openid=' . $startopenid;
  440. }
  441. $response = ihttp_get($url);
  442. if (is_error($response)) {
  443. return error(-1, "访问公众平台接口失败, 错误: {$response['message']}");
  444. }
  445. $result = @json_decode($response['content'], true);
  446. if (empty($result)) {
  447. return error(-1, "接口调用失败, 元数据: {$response['meta']}");
  448. } elseif (!empty($result['errcode'])) {
  449. return error(-1, "访问公众平台接口失败, 错误: {$result['errmsg']},错误详情:{$this->errorCode($result['errcode'])}");
  450. }
  451. $return = array();
  452. $return['total'] = $result['total'];
  453. $return['fans'] = $result['data']['openid'];
  454. $return['next'] = $result['next_openid'];
  455. return $return;
  456. }
  457. public function queryBarCodeActions() {
  458. return array('barCodeCreateDisposable', 'barCodeCreateFixed');
  459. }
  460. public function barCodeCreateDisposable($barcode) {
  461. $barcode['expire_seconds'] = empty($barcode['expire_seconds']) ? 2592000 : $barcode['expire_seconds'];
  462. if (empty($barcode['action_info']['scene']['scene_id']) && empty($barcode['action_info']['scene']['scene_str']) || empty($barcode['action_name'])) {
  463. return error('1', 'Invalid params');
  464. }
  465. $token = $this->getAccessToken();
  466. $response = ihttp_request('https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=' . $token, json_encode($barcode));
  467. if (is_error($response)) {
  468. return $response;
  469. }
  470. $content = @json_decode($response['content'], true);
  471. if (empty($content)) {
  472. return error(-1, "接口调用失败, 元数据: {$response['meta']}");
  473. }
  474. if (!empty($content['errcode'])) {
  475. return error(-1, "访问微信接口错误, 错误代码: {$content['errcode']}, 错误信息: {$content['errmsg']},错误详情:{$this->errorCode($content['errcode'])}");
  476. }
  477. return $content;
  478. }
  479. public function barCodeCreateFixed($barcode) {
  480. if ('QR_LIMIT_SCENE' == $barcode['action_name'] && empty($barcode['action_info']['scene']['scene_id'])) {
  481. return error('1', '场景值错误');
  482. }
  483. if ('QR_LIMIT_STR_SCENE' == $barcode['action_name'] && empty($barcode['action_info']['scene']['scene_str'])) {
  484. return error('1', '场景字符串错误');
  485. }
  486. $token = $this->getAccessToken();
  487. $response = ihttp_request('https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=' . $token, json_encode($barcode));
  488. if (is_error($response)) {
  489. return $response;
  490. }
  491. $content = @json_decode($response['content'], true);
  492. if (empty($content)) {
  493. return error(-1, "接口调用失败, 元数据: {$response['meta']}");
  494. }
  495. if (!empty($content['errcode'])) {
  496. return error(-1, "访问微信接口错误, 错误代码: {$content['errcode']}, 错误信息: {$content['errmsg']},错误详情:{$this->errorCode($content['errcode'])}");
  497. }
  498. return $content;
  499. }
  500. private function encryptErrorCode($code) {
  501. $errors = array(
  502. '40001' => '签名验证错误',
  503. '40002' => 'xml解析失败',
  504. '40003' => 'sha加密生成签名失败',
  505. '40004' => 'encodingAesKey 非法',
  506. '40005' => 'appid 校验错误',
  507. '40006' => 'aes 加密失败',
  508. '40007' => 'aes 解密失败',
  509. '40008' => '解密后得到的buffer非法',
  510. '40009' => 'base64加密失败',
  511. '40010' => 'base64解密失败',
  512. '40011' => '生成xml失败',
  513. );
  514. if ($errors[$code]) {
  515. return $errors[$code];
  516. } else {
  517. return '未知错误';
  518. }
  519. }
  520. public function changeSend($send) {
  521. if (empty($send)) {
  522. return error(-1, 'Invalid params');
  523. }
  524. $token = $this->getAccessToken();
  525. if (is_error($token)) {
  526. return $token;
  527. }
  528. $sendapi = 'https://api.weixin.qq.com/pay/delivernotify?access_token=' . $token;
  529. $response = ihttp_request($sendapi, json_encode($send));
  530. $response = json_decode($response['content'], true);
  531. if (empty($response)) {
  532. return error(-1, '发货失败,请检查您的公众号权限或是公众号AppId和公众号AppSecret!');
  533. }
  534. if (!empty($response['errcode'])) {
  535. return error(-1, $response['errmsg']);
  536. }
  537. return true;
  538. }
  539. public function getAccessToken() {
  540. global $_W;
  541. $cachekey = cache_system_key('accesstoken', array('uniacid' => $this->account['uniacid']));
  542. $cache = cache_load($cachekey);
  543. if (!empty($cache) && !empty($cache['token'])) {
  544. $this->account['access_token'] = $cache;
  545. return $cache['token'];
  546. }
  547. if (!empty($this->account['link'])) {
  548. load()->library('sdk-module');
  549. $link_config = iunserializer($this->account['link_config']);
  550. try {
  551. $api = new \W7\Sdk\Module\Api($_W['setting']['site']['key'], $_W['setting']['site']['token'], $link_config['app_id'], 1, CLOUD_V3API_DOMAIN_PRE);
  552. $token = $api->app()->getAccessToken()->toArray();
  553. } catch (Exception $e) {
  554. return error('-1', $e->getMessage());
  555. }
  556. } else {
  557. if (empty($this->account['key']) || empty($this->account['secret'])) {
  558. return error('-1', '未填写公众号的 appid 或 appsecret!');
  559. }
  560. $url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={$this->account['key']}&secret={$this->account['secret']}";
  561. $content = ihttp_get($url);
  562. if (is_error($content)) {
  563. return error('-1', '获取微信公众号授权失败, 请稍后重试!错误详情: ' . $content['message']);
  564. }
  565. if (empty($content['content'])) {
  566. return error('-1', 'AccessToken获取失败,请检查appid和appsecret的值是否与微信公众平台一致!');
  567. }
  568. $token = @json_decode($content['content'], true);
  569. }
  570. if (!empty($token['errcode']) && '40164' == $token['errcode']) {
  571. return error(-1, $this->errorCode($token['errcode'], $token['errmsg']));
  572. }
  573. if (empty($token) || !is_array($token) || empty($token['access_token']) || empty($token['expires_in'])) {
  574. return error('-1', '获取微信公众号授权失败!错误代码:' . $token['errcode'] . ',错误信息:' . $this->errorCode($token['errcode']));
  575. }
  576. $record = array();
  577. $record['token'] = $token['access_token'];
  578. $record_expire = $token['expires_in'] - 200;
  579. $this->account['access_token'] = $record;
  580. cache_write($cachekey, $record, $record_expire);
  581. return $record['token'];
  582. }
  583. public function getVailableAccessToken() {
  584. $accounts = pdo_fetchall('SELECT `key`, `secret`, `acid` FROM ' . tablename('account_wechats') . ' WHERE uniacid = :uniacid ORDER BY `level` DESC ', array(':uniacid' => $GLOBALS['_W']['uniacid']));
  585. if (empty($accounts)) {
  586. return error(-1, 'no permission');
  587. }
  588. foreach ($accounts as $account) {
  589. if (empty($account['key']) || empty($account['secret'])) {
  590. continue;
  591. }
  592. $acid = $account['acid'];
  593. break;
  594. }
  595. $account = WeAccount::create($acid);
  596. return $account->getAccessToken();
  597. }
  598. public function fetch_token() {
  599. return $this->getAccessToken();
  600. }
  601. public function fetch_available_token() {
  602. return $this->getVailableAccessToken();
  603. }
  604. public function clearAccessToken() {
  605. $access_token = $this->getAccessToken();
  606. if (is_error($access_token)) {
  607. return $access_token;
  608. }
  609. $url = 'https://api.weixin.qq.com/cgi-bin/getcallbackip?access_token=' . $access_token;
  610. $response = $this->requestApi($url);
  611. if (is_error($response) && '40001' == $response['errno']) {
  612. cache_delete(cache_system_key('accesstoken', array('uniacid' => $this->account['uniacid'])));
  613. }
  614. return true;
  615. }
  616. public function getJsApiTicket() {
  617. $cachekey = cache_system_key('jsticket', array('uniacid' => $this->account['uniacid']));
  618. $cache = cache_load($cachekey);
  619. if (!empty($cache) && !empty($cache['ticket'])) {
  620. return $cache['ticket'];
  621. }
  622. $access_token = $this->getAccessToken();
  623. if (is_error($access_token)) {
  624. return $access_token;
  625. }
  626. $url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token={$access_token}&type=jsapi";
  627. $content = ihttp_get($url);
  628. if (is_error($content)) {
  629. return error(-1, '调用接口获取微信公众号 jsapi_ticket 失败, 错误信息: ' . $this->errorCode($content['message']));
  630. }
  631. $result = @json_decode($content['content'], true);
  632. if (empty($result) || 0 != intval(($result['errcode'])) || 'ok' != $result['errmsg']) {
  633. return error(-1, '获取微信公众号 jsapi_ticket 结果错误, 错误信息: ' . $this->errorCode($result['errcode'], $result['errmsg']));
  634. }
  635. $record = array();
  636. $record['ticket'] = $result['ticket'];
  637. $record_expire = $result['expires_in'] - 200;
  638. $this->account['jsapi_ticket'] = $record;
  639. cache_write($cachekey, $record, $record_expire);
  640. return $record['ticket'];
  641. }
  642. public function getJssdkConfig($url = '') {
  643. global $_W, $urls;
  644. $jsapiTicket = $this->getJsApiTicket();
  645. if (is_error($jsapiTicket)) {
  646. $jsapiTicket = $jsapiTicket['message'];
  647. }
  648. $nonceStr = random(16);
  649. $timestamp = TIMESTAMP;
  650. $url = empty($url) ? ($urls['scheme'] . '://' . $urls['host'] . $_SERVER['REQUEST_URI']) : $url;
  651. $string1 = "jsapi_ticket={$jsapiTicket}&noncestr={$nonceStr}&timestamp={$timestamp}&url={$url}";
  652. $signature = sha1($string1);
  653. $config = array(
  654. 'appId' => $this->account['key'],
  655. 'nonceStr' => $nonceStr,
  656. 'timestamp' => "$timestamp",
  657. 'signature' => $signature,
  658. );
  659. if (DEVELOPMENT) {
  660. $config['url'] = $url;
  661. $config['string1'] = $string1;
  662. $config['name'] = $this->account['name'];
  663. }
  664. return $config;
  665. }
  666. public function long2short($longurl) {
  667. $token = $this->getAccessToken();
  668. if (is_error($token)) {
  669. return $token;
  670. }
  671. $url = "https://api.weixin.qq.com/cgi-bin/shorturl?access_token={$token}";
  672. $send = array();
  673. $send['action'] = 'long2short';
  674. $send['long_url'] = $longurl;
  675. $response = ihttp_request($url, json_encode($send));
  676. if (is_error($response)) {
  677. return error(-1, "访问公众平台接口失败, 错误: {$this->errorCode($response['message'])}");
  678. }
  679. $result = @json_decode($response['content'], true);
  680. if (empty($result)) {
  681. return error(-1, "接口调用失败, 元数据: {$response['meta']}");
  682. } elseif (!empty($result['errcode'])) {
  683. return error(-1, "访问微信接口错误, 错误代码: {$result['errcode']}, 错误信息: {$result['errmsg']},错误详情:{$this->errorCode($result['errcode'])}");
  684. }
  685. return $result;
  686. }
  687. public function fetchChatLog($params = array()) {
  688. if (empty($params['starttime']) || empty($params['endtime'])) {
  689. return error(-1, '没有要查询的时间段');
  690. }
  691. $starttmp = date('Y-m-d', $params['starttime']);
  692. $endtmp = date('Y-m-d', $params['endtime']);
  693. if ($starttmp != $endtmp) {
  694. return error(-1, '时间范围有误,微信公众平台不支持跨日查询');
  695. }
  696. if (empty($params['openid'])) {
  697. return error(-1, '没有要查询的openid');
  698. }
  699. if (empty($params['pagesize'])) {
  700. $params['pagesize'] = 50;
  701. }
  702. if (empty($params['pageindex'])) {
  703. $params['pageindex'] = 1;
  704. }
  705. $token = $this->getAccessToken();
  706. if (is_error($token)) {
  707. return $token;
  708. }
  709. $url = "https://api.weixin.qq.com/customservice/msgrecord/getrecord?access_token={$token}";
  710. $response = ihttp_request($url, json_encode($params));
  711. if (is_error($response)) {
  712. return error(-1, "访问公众平台接口失败, 错误: {$response['message']}");
  713. }
  714. $result = @json_decode($response['content'], true);
  715. if (empty($result)) {
  716. return error(-1, "接口调用失败, 元数据: {$response['meta']}");
  717. } elseif (!empty($result['errcode'])) {
  718. return error(-1, "访问微信接口错误, 错误代码: {$result['errcode']}, 错误信息: {$result['errmsg']},错误详情:{$this->errorCode($result['errcode'])}");
  719. }
  720. return $result;
  721. }
  722. public function isTagSupported() {
  723. return (!empty($this->account['key']) &&
  724. !empty($this->account['secret']) || ACCOUNT_OAUTH_LOGIN == $this->account['type']) &&
  725. (intval($this->account['level']) > ACCOUNT_SERVICE);
  726. }
  727. public function fansTagAdd($tagname) {
  728. if (empty($tagname)) {
  729. return error(-1, '请填写标签名称');
  730. }
  731. $token = $this->getAccessToken();
  732. if (is_error($token)) {
  733. return $token;
  734. }
  735. $url = "https://api.weixin.qq.com/cgi-bin/tags/create?access_token={$token}";
  736. $data = stripslashes(ijson_encode(array('tag' => array('name' => $tagname)), JSON_UNESCAPED_UNICODE));
  737. cache_delete(cache_system_key('account_tags', array('uniacid' => $this->account['uniacid'])));
  738. return $this->requestApi($url, $data);
  739. }
  740. public function fansTagFetchAll() {
  741. $cachekey = cache_system_key('account_tags', array('uniacid' => $this->account['uniacid']));
  742. $cache = cache_load($cachekey);
  743. if (!empty($cache['tags']) && $cache['expire'] > TIMESTAMP) {
  744. return $cache['tags'];
  745. }
  746. $token = $this->getAccessToken();
  747. if (is_error($token)) {
  748. return $token;
  749. }
  750. $url = "https://api.weixin.qq.com/cgi-bin/tags/get?access_token={$token}";
  751. $tags = $this->requestApi($url);
  752. if (!is_error($tags)) {
  753. cache_write($cachekey, array('tags' => $tags, 'expire' => TIMESTAMP + 3600), 3400);
  754. }
  755. return $tags;
  756. }
  757. public function fansTagEdit($tagid, $tagname) {
  758. if (empty($tagid) || empty($tagname)) {
  759. return error(-1, '标签信息错误');
  760. }
  761. if (in_array($tagid, array(1, 2))) {
  762. return error(-1, '微信平台默认标签,不能修改');
  763. }
  764. $token = $this->getAccessToken();
  765. if (is_error($token)) {
  766. return $token;
  767. }
  768. $url = "https://api.weixin.qq.com/cgi-bin/tags/update?access_token={$token}";
  769. $data = stripslashes(ijson_encode(array('tag' => array('id' => $tagid, 'name' => $tagname)), JSON_UNESCAPED_UNICODE));
  770. $result = $this->requestApi($url, $data);
  771. if (is_error($result)) {
  772. return $result;
  773. }
  774. cache_delete(cache_system_key('account_tags', array('uniacid' => $this->account['uniacid'])));
  775. return true;
  776. }
  777. public function fansTagDelete($tagid) {
  778. $tagid = intval($tagid);
  779. if (empty($tagid)) {
  780. return error(-1, '标签id错误');
  781. }
  782. $token = $this->getAccessToken();
  783. if (is_error($token)) {
  784. return $token;
  785. }
  786. $url = "https://api.weixin.qq.com/cgi-bin/tags/delete?access_token={$token}";
  787. $data = json_encode(array('tag' => array('id' => $tagid)));
  788. $result = $this->requestApi($url, $data);
  789. if (is_error($result)) {
  790. return $result;
  791. }
  792. cache_delete(cache_system_key('account_tags', array('uniacid' => $this->account['uniacid'])));
  793. return true;
  794. }
  795. public function fansTagGetUserlist($tagid, $next_openid = '') {
  796. $tagid = intval($tagid);
  797. $next_openid = (string) $next_openid;
  798. if (empty($tagid)) {
  799. return error(-1, '标签id错误');
  800. }
  801. $token = $this->getAccessToken();
  802. if (is_error($token)) {
  803. return $token;
  804. }
  805. $url = 'https://api.weixin.qq.com/cgi-bin/user/tag/get?access_token=' . $token;
  806. $data = array(
  807. 'tagid' => $tagid,
  808. );
  809. if (!empty($next_openid)) {
  810. $data['next_openid'] = $next_openid;
  811. }
  812. $data = json_encode($data);
  813. return $this->requestApi($url, $data);
  814. }
  815. public function fansTagTagging($openid, $tagids) {
  816. $openid = (string) $openid;
  817. $tagids = (array) $tagids;
  818. if (empty($openid)) {
  819. return error(-1, '没有填写用户openid');
  820. }
  821. if (empty($tagids)) {
  822. return error(-1, '没有填写标签');
  823. }
  824. if (count($tagids) > 20) {
  825. return error(-1, '最多20个标签');
  826. }
  827. $token = $this->getAccessToken();
  828. if (is_error($token)) {
  829. return $token;
  830. }
  831. $fetch_result = $this->fansTagFetchOwnTags($openid);
  832. if (is_error($fetch_result)) {
  833. return $fetch_result;
  834. }
  835. foreach ($fetch_result['tagid_list'] as $del_tagid) {
  836. $this->fansTagBatchUntagging($openid, $del_tagid);
  837. }
  838. $url = "https://api.weixin.qq.com/cgi-bin/tags/members/batchtagging?access_token={$token}";
  839. foreach ($tagids as $tagid) {
  840. $data = array(
  841. 'openid_list' => $openid,
  842. 'tagid' => $tagid,
  843. );
  844. $data = json_encode($data);
  845. $result = $this->requestApi($url, $data);
  846. if (is_error($result)) {
  847. return $result;
  848. }
  849. }
  850. return true;
  851. }
  852. public function fansTagBatchTagging($openid_list, $tagid) {
  853. $openid_list = (array) $openid_list;
  854. $tagid = (int) $tagid;
  855. if (empty($openid_list)) {
  856. return error(-1, '没有填写用户openid列表');
  857. }
  858. if (empty($tagid)) {
  859. return error(-1, '没有填写tagid');
  860. }
  861. $token = $this->getAccessToken();
  862. if (is_error($token)) {
  863. return $token;
  864. }
  865. $url = "https://api.weixin.qq.com/cgi-bin/tags/members/batchtagging?access_token={$token}";
  866. $data = array(
  867. 'openid_list' => $openid_list,
  868. 'tagid' => $tagid,
  869. );
  870. $data = json_encode($data);
  871. $result = $this->requestApi($url, $data);
  872. if (is_error($result)) {
  873. return $result;
  874. }
  875. return true;
  876. }
  877. public function fansTagBatchUntagging($openid_list, $tagid) {
  878. $openid_list = (array) $openid_list;
  879. $tagid = (int) $tagid;
  880. if (empty($openid_list)) {
  881. return error(-1, '没有填写用户openid列表');
  882. }
  883. if (empty($tagid)) {
  884. return error(-1, '没有填写tagid');
  885. }
  886. $token = $this->getAccessToken();
  887. if (is_error($token)) {
  888. return $token;
  889. }
  890. $url = "https://api.weixin.qq.com/cgi-bin/tags/members/batchuntagging?access_token={$token}";
  891. $data = array(
  892. 'openid_list' => $openid_list,
  893. 'tagid' => $tagid,
  894. );
  895. $data = json_encode($data);
  896. $result = $this->requestApi($url, $data);
  897. if (is_error($result)) {
  898. return $result;
  899. }
  900. return true;
  901. }
  902. public function fansTagFetchOwnTags($openid) {
  903. $openid = (string) $openid;
  904. if (empty($openid)) {
  905. return error(-1, '没有填写用户openid');
  906. }
  907. $token = $this->getAccessToken();
  908. if (is_error($token)) {
  909. return $token;
  910. }
  911. $url = "https://api.weixin.qq.com/cgi-bin/tags/getidlist?access_token={$token}";
  912. $data = json_encode(array('openid' => $openid));
  913. return $this->requestApi($url, $data);
  914. }
  915. public function fansSendAll($group, $msgtype, $media_id) {
  916. $types = array('text' => 'text', 'basic' => 'text', 'image' => 'image', 'news' => 'mpnews', 'voice' => 'voice', 'video' => 'mpvideo', 'wxcard' => 'wxcard');
  917. if (empty($types[$msgtype])) {
  918. return error(-1, '消息类型不合法');
  919. }
  920. $is_to_all = false;
  921. if ($group == -1) {
  922. $is_to_all = true;
  923. }
  924. $send_conent = ('text' == $types[$msgtype]) ? array('content' => $media_id) : array('media_id' => $media_id);
  925. $data = array(
  926. 'filter' => array(
  927. 'is_to_all' => $is_to_all,
  928. 'tag_id' => $group,
  929. ),
  930. 'msgtype' => $types[$msgtype],
  931. $types[$msgtype] => $send_conent,
  932. );
  933. if ('wxcard' == $types[$msgtype]) {
  934. unset($data['wxcard']['media_id']);
  935. $data['wxcard']['card_id'] = $media_id;
  936. }
  937. $token = $this->getAccessToken();
  938. if (is_error($token)) {
  939. return $token;
  940. }
  941. $url = "https://api.weixin.qq.com/cgi-bin/message/mass/sendall?access_token={$token}";
  942. $data = urldecode(json_encode($data, JSON_UNESCAPED_UNICODE));
  943. $response = ihttp_request($url, $data);
  944. if (is_error($response)) {
  945. return error(-1, "访问公众平台接口失败, 错误: {$response['message']}");
  946. }
  947. $result = @json_decode($response['content'], true);
  948. if (empty($result)) {
  949. return error(-1, "接口调用失败, 元数据: {$response['meta']}");
  950. } elseif (!empty($result['errcode'])) {
  951. return error(-1, "访问微信接口错误, 错误代码: {$result['errcode']}, 错误信息: {$result['errmsg']},错误详情:{$this->errorCode($result['errcode'])}");
  952. }
  953. return $result;
  954. }
  955. public function fansSendPreview($wxname, $content, $msgtype) {
  956. $types = array('text' => 'text', 'image' => 'image', 'news' => 'mpnews', 'voice' => 'voice', 'video' => 'mpvideo', 'wxcard' => 'wxcard');
  957. if (empty($types[$msgtype])) {
  958. return error(-1, '群发类型不合法');
  959. }
  960. $msgtype = $types[$msgtype];
  961. $token = $this->getAccessToken();
  962. if (is_error($token)) {
  963. return $token;
  964. }
  965. $url = 'https://api.weixin.qq.com/cgi-bin/message/mass/preview?access_token=' . $token;
  966. $send = array(
  967. 'towxname' => $wxname,
  968. 'msgtype' => $msgtype,
  969. );
  970. if ('text' == $msgtype) {
  971. $send[$msgtype] = array(
  972. 'content' => $content,
  973. );
  974. } elseif ('wxcard' == $msgtype) {
  975. $send[$msgtype] = array(
  976. 'card_id' => $content,
  977. );
  978. } else {
  979. $send[$msgtype] = array(
  980. 'media_id' => $content,
  981. );
  982. }
  983. $response = ihttp_request($url, json_encode($send, JSON_UNESCAPED_UNICODE));
  984. if (is_error($response)) {
  985. return error(-1, "访问公众平台接口失败, 错误: {$response['message']}");
  986. }
  987. $result = @json_decode($response['content'], true);
  988. if (empty($result)) {
  989. } elseif (!empty($result['errcode'])) {
  990. return error(-1, "访问公众平台接口失败, 错误: {$result['errmsg']},错误详情:{$this->errorCode($result['errcode'])}");
  991. }
  992. return $result;
  993. }
  994. public function sendCustomNotice($data) {
  995. if (empty($data)) {
  996. return error(-1, '参数错误');
  997. }
  998. $token = $this->getAccessToken();
  999. if (is_error($token)) {
  1000. return $token;
  1001. }
  1002. $url = "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token={$token}";
  1003. $response = ihttp_request($url, urldecode(json_encode($data)));
  1004. if (is_error($response)) {
  1005. return error(-1, "访问公众平台接口失败, 错误: {$response['message']}");
  1006. }
  1007. $result = @json_decode($response['content'], true);
  1008. if (empty($result)) {
  1009. return error(-1, "接口调用失败, 元数据: {$response['meta']}");
  1010. } elseif (!empty($result['errcode'])) {
  1011. return error(-1, "访问微信接口错误, 错误代码: {$result['errcode']}, 错误信息: {$result['errmsg']},错误详情:{$this->errorCode($result['errcode'])}");
  1012. }
  1013. return true;
  1014. }
  1015. public function sendTplNotice($touser, $template_id, $postdata, $url = '', $topcolor = '#FF683F', $miniprogram = array('appid' => '', 'pagepath' => '')) {
  1016. if (empty($this->account['key']) || ACCOUNT_SERVICE_VERIFY != $this->account['level']) {
  1017. return error(-1, '你的公众号没有发送模板消息的权限');
  1018. }
  1019. if (empty($touser)) {
  1020. return error(-1, '参数错误,粉丝openid不能为空');
  1021. }
  1022. if (empty($template_id)) {
  1023. return error(-1, '参数错误,模板标示不能为空');
  1024. }
  1025. if (empty($postdata) || !is_array($postdata)) {
  1026. return error(-1, '参数错误,请根据模板规则完善消息内容');
  1027. }
  1028. $token = $this->getAccessToken();
  1029. if (is_error($token)) {
  1030. return $token;
  1031. }
  1032. $data = array();
  1033. if (!empty($miniprogram['appid']) && !empty($miniprogram['pagepath'])) {
  1034. $data['miniprogram'] = $miniprogram;
  1035. }
  1036. $data['touser'] = $touser;
  1037. $data['template_id'] = trim($template_id);
  1038. $data['url'] = trim($url);
  1039. $data['topcolor'] = trim($topcolor);
  1040. $data['data'] = $postdata;
  1041. $data = json_encode($data);
  1042. $post_url = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token={$token}";
  1043. $response = ihttp_request($post_url, $data);
  1044. if (is_error($response)) {
  1045. return error(-1, "访问公众平台接口失败, 错误: {$response['message']}");
  1046. }
  1047. $result = @json_decode($response['content'], true);
  1048. if (empty($result)) {
  1049. return error(-1, "接口调用失败, 元数据: {$response['meta']}");
  1050. } elseif (!empty($result['errcode'])) {
  1051. return error(-1, "访问微信接口错误, 错误代码: {$result['errcode']}, 错误信息: {$result['errmsg']},信息详情:{$this->errorCode($result['errcode'])}");
  1052. }
  1053. return true;
  1054. }
  1055. public function uploadMedia($path, $type = 'image') {
  1056. if (empty($path)) {
  1057. return error(-1, '参数错误');
  1058. }
  1059. if (in_array(substr(ltrim($path, '/'), 0, 6), array('images', 'videos', 'audios', 'thumb'))) {
  1060. $path = ATTACHMENT_ROOT . ltrim($path, '/');
  1061. }
  1062. if (!file_exists($path)) {
  1063. return error(1, '文件不存在');
  1064. }
  1065. $token = $this->getAccessToken();
  1066. if (is_error($token)) {
  1067. return $token;
  1068. }
  1069. $url = "https://api.weixin.qq.com/cgi-bin/media/upload?access_token={$token}&type={$type}";
  1070. $data = array(
  1071. 'media' => '@' . $path,
  1072. );
  1073. return $this->requestApi($url, $data);
  1074. }
  1075. public function uploadMediaFixed($path, $type = 'images') {
  1076. global $_W;
  1077. if (empty($path)) {
  1078. return error(-1, '参数错误');
  1079. }
  1080. if (in_array(substr(ltrim($path, '/'), 0, 6), array('images', 'videos', 'audios', 'thumb', 'voices'))) {
  1081. $path = ATTACHMENT_ROOT . ltrim($path, '/');
  1082. }
  1083. if (!file_exists($path)) {
  1084. return error(1, '文件不存在');
  1085. }
  1086. $token = $this->getAccessToken();
  1087. if (is_error($token)) {
  1088. return $token;
  1089. }
  1090. $url = "https://api.weixin.qq.com/cgi-bin/material/add_material?access_token={$token}&type={$type}";
  1091. $data = array(
  1092. 'media' => '@' . $path,
  1093. );
  1094. if ('videos' == $type) {
  1095. $video_filename = ltrim($path, ATTACHMENT_ROOT);
  1096. $material = $material = pdo_get('core_attachment', array('uniacid' => $_W['uniacid'], 'attachment' => $video_filename));
  1097. }
  1098. $filename = pathinfo($path, PATHINFO_FILENAME);
  1099. $description = array(
  1100. 'title' => 'videos' == $type ? $material['filename'] : $filename,
  1101. 'introduction' => $filename,
  1102. );
  1103. $data['description'] = urldecode(json_encode($description));
  1104. return $this->requestApi($url, $data);
  1105. }
  1106. public function editMaterialNews($data) {
  1107. $token = $this->getAccessToken();
  1108. if (is_error($token)) {
  1109. return $token;
  1110. }
  1111. $url = "https://api.weixin.qq.com/cgi-bin/draft/update?access_token={$token}";
  1112. $response = $this->requestApi($url, stripslashes(ijson_encode($data, JSON_UNESCAPED_UNICODE)));
  1113. if (is_error($response)) {
  1114. return $response;
  1115. }
  1116. return true;
  1117. }
  1118. public function uploadNewsThumb($thumb) {
  1119. $token = $this->getAccessToken();
  1120. if (is_error($token)) {
  1121. return $token;
  1122. }
  1123. if (!file_exists($thumb)) {
  1124. return error(1, '文件不存在');
  1125. }
  1126. $data = array(
  1127. 'media' => '@' . $thumb,
  1128. );
  1129. $url = "https://api.weixin.qq.com/cgi-bin/media/uploadimg?access_token={$token}";
  1130. $response = $this->requestApi($url, $data);
  1131. if (is_error($response)) {
  1132. return $response;
  1133. } else {
  1134. return $response['url'];
  1135. }
  1136. }
  1137. public function uploadVideoFixed($title, $description, $path) {
  1138. if (empty($path) || empty($title) || empty($description)) {
  1139. return error(-1, '参数错误');
  1140. }
  1141. if (in_array(substr(ltrim($path, '/'), 0, 6), array('images', 'videos', 'audios'))) {
  1142. $path = ATTACHMENT_ROOT . ltrim($path, '/');
  1143. }
  1144. if (!file_exists($path)) {
  1145. return error(1, '文件不存在');
  1146. }
  1147. $token = $this->getAccessToken();
  1148. if (is_error($token)) {
  1149. return $token;
  1150. }
  1151. $url = "https://api.weixin.qq.com/cgi-bin/material/add_material?access_token={$token}&type=videos";
  1152. $data = array(
  1153. 'media' => '@' . $path,
  1154. 'description' => stripslashes(ijson_encode(array('title' => $title, 'introduction' => $description), JSON_UNESCAPED_UNICODE)),
  1155. );
  1156. return $this->requestApi($url, $data);
  1157. }
  1158. public function uploadVideo($data) {
  1159. if (empty($data)) {
  1160. return error(-1, '参数错误');
  1161. }
  1162. $token = $this->getAccessToken();
  1163. if (is_error($token)) {
  1164. return $token;
  1165. }
  1166. $url = "https://file.api.weixin.qq.com/cgi-bin/media/uploadvideo?access_token={$token}";
  1167. $response = ihttp_request($url, urldecode(json_encode($data)));
  1168. if (is_error($response)) {
  1169. return error(-1, "访问公众平台接口失败, 错误: {$response['message']}");
  1170. }
  1171. $result = @json_decode($response['content'], true);
  1172. if (empty($result)) {
  1173. return error(-1, "接口调用失败, 元数据: {$response['meta']}");
  1174. } elseif (!empty($result['errcode'])) {
  1175. return error(-1, "访问微信接口错误, 错误代码: {$result['errcode']}, 错误信息: {$result['errmsg']}, 错误详情:{$this->errorCode($result['errcode'])}");
  1176. }
  1177. return $result;
  1178. }
  1179. public function uploadNews($data) {
  1180. if (empty($data)) {
  1181. return error(-1, '参数错误');
  1182. }
  1183. $token = $this->getAccessToken();
  1184. if (is_error($token)) {
  1185. return $token;
  1186. }
  1187. $url = "https://api.weixin.qq.com/cgi-bin/media/uploadnews?access_token={$token}";
  1188. $response = ihttp_request($url, urldecode(json_encode($data)));
  1189. if (is_error($response)) {
  1190. return error(-1, "访问公众平台接口失败, 错误: {$response['message']}");
  1191. }
  1192. $result = @json_decode($response['content'], true);
  1193. if (empty($result)) {
  1194. return error(-1, "接口调用失败, 元数据: {$response['meta']}");
  1195. } elseif (!empty($result['errcode'])) {
  1196. return error(-1, "访问微信接口错误, 错误代码: {$result['errcode']}, 错误信息: {$result['errmsg']},错误详情:{$this->errorCode($result['errcode'])}");
  1197. }
  1198. return $result;
  1199. }
  1200. public function addMatrialNews($data) {
  1201. $token = $this->getAccessToken();
  1202. if (is_error($token)) {
  1203. return $token;
  1204. }
  1205. $url = "https://api.weixin.qq.com/cgi-bin/draft/add?access_token={$token}";
  1206. $data = stripslashes(urldecode(ijson_encode($data, JSON_UNESCAPED_UNICODE)));
  1207. $response = $this->requestApi($url, $data);
  1208. if (is_error($response)) {
  1209. return $response;
  1210. }
  1211. return $response['media_id'];
  1212. }
  1213. public function batchGetMaterial($type = 'news', $offset = 0, $count = 20) {
  1214. global $_W;
  1215. $token = $this->getAccessToken();
  1216. if (is_error($token)) {
  1217. return $token;
  1218. }
  1219. $url = 'https://api.weixin.qq.com/cgi-bin/material/batchget_material?access_token=' . $token;
  1220. $data = array(
  1221. 'type' => $type,
  1222. 'offset' => intval($offset),
  1223. 'count' => $count,
  1224. );
  1225. return $this->requestApi($url, json_encode($data));
  1226. }
  1227. public function getMaterial($media_id, $savefile = true) {
  1228. $token = $this->getAccessToken();
  1229. if (is_error($token)) {
  1230. return $token;
  1231. }
  1232. $url = 'https://api.weixin.qq.com/cgi-bin/material/get_material?access_token=' . $token;
  1233. $data = array(
  1234. 'media_id' => trim($media_id),
  1235. );
  1236. $response = ihttp_request($url, json_encode($data));
  1237. if (is_error($response)) {
  1238. return error(-1, "访问公平台接口失败, 错误: {$response['message']}");
  1239. }
  1240. $result = @json_decode($response['content'], true);
  1241. if (!empty($result['errcode'])) {
  1242. return error(-1, "访问公众平台接口失败, 错误: {$result['errmsg']},错误详情:{$this->errorCode($result['errcode'])}");
  1243. }
  1244. if (empty($response['headers']['Content-disposition'])) {
  1245. $response = json_decode($response['content'], true);
  1246. if (!empty($response['down_url'])) {
  1247. if (empty($savefile)) {
  1248. return $response;
  1249. }
  1250. $response = ihttp_get($response['down_url']);
  1251. $response['headers']['Content-disposition'] = $response['headers']['Content-Disposition'];
  1252. } elseif (!empty($response['news_item'])) {
  1253. return $response;
  1254. }
  1255. }
  1256. if ($savefile && !empty($response['headers']['Content-disposition']) && strexists($response['headers']['Content-disposition'], 'filename=')) {
  1257. global $_W;
  1258. preg_match('/filename=\"?([^"]*)/', $response['headers']['Content-disposition'], $match);
  1259. $pathinfo = pathinfo($match[1]);
  1260. $filename = $_W['uniacid'] . '/' . date('Y/m/');
  1261. if (in_array(strtolower($pathinfo['extension']), array('mp4'))) {
  1262. $filename = 'videos/' . $filename;
  1263. } elseif (in_array(strtolower($pathinfo['extension']), array('amr', 'mp3', 'wma', 'wmv'))) {
  1264. $filename = 'audios/' . $filename;
  1265. } else {
  1266. $filename = 'images/' . $filename;
  1267. }
  1268. $filename .= file_random_name($filename, $pathinfo['extension']);
  1269. load()->func('file');
  1270. file_write($filename, $response['content']);
  1271. file_remote_upload($filename);
  1272. return $filename;
  1273. } else {
  1274. return $response['content'];
  1275. }
  1276. return $result;
  1277. }
  1278. public function downloadMedia($media_id, $savefile = true) {
  1279. $mediatypes = array('image', 'voice', 'thumb');
  1280. $media_id = is_array($media_id) ? $media_id['media_id'] : $media_id;
  1281. if (empty($media_id)) {
  1282. return error(-1, '微信下载媒体资源参数错误');
  1283. }
  1284. $token = $this->getAccessToken();
  1285. if (is_error($token)) {
  1286. return $token;
  1287. }
  1288. $url = "https://api.weixin.qq.com/cgi-bin/media/get?access_token={$token}&media_id={$media_id}";
  1289. $response = ihttp_get($url);
  1290. if (empty($response['headers']['Content-disposition'])) {
  1291. $response = json_decode($response['content'], true);
  1292. if (!empty($response['video_url'])) {
  1293. $response = ihttp_get($response['video_url']);
  1294. $response['headers']['Content-disposition'] = $response['headers']['Content-Disposition'];
  1295. }
  1296. }
  1297. if ($savefile && !empty($response['headers']['Content-disposition']) && strexists($response['headers']['Content-disposition'], 'filename=')) {
  1298. global $_W;
  1299. preg_match('/filename=\"?([^"]*)/', $response['headers']['Content-disposition'], $match);
  1300. $filename = $_W['uniacid'] . '/' . date('Y/m/') . $match[1];
  1301. $pathinfo = pathinfo($filename);
  1302. if (in_array(strtolower($pathinfo['extension']), array('mp4'))) {
  1303. $filename = 'videos/' . $filename;
  1304. } elseif (in_array(strtolower($pathinfo['extension']), array('amr', 'mp3', 'wma', 'wmv'))) {
  1305. $filename = 'audios/' . $filename;
  1306. } else {
  1307. $filename = 'images/' . $filename;
  1308. }
  1309. load()->func('file');
  1310. file_write($filename, $response['content']);
  1311. file_remote_upload($filename);
  1312. return $filename;
  1313. } else {
  1314. return $response['content'];
  1315. }
  1316. }
  1317. public function getMaterialCount() {
  1318. $token = $this->getAccessToken();
  1319. if (is_error($token)) {
  1320. return $token;
  1321. }
  1322. $url = 'https://api.weixin.qq.com/cgi-bin/material/get_materialcount?access_token=' . $token;
  1323. return $this->requestApi($url);
  1324. }
  1325. public function delMaterial($media_id) {
  1326. $media_id = trim($media_id);
  1327. if (empty($media_id)) {
  1328. return error(-1, '素材media_id错误');
  1329. }
  1330. $token = $this->getAccessToken();
  1331. if (is_error($token)) {
  1332. return $token;
  1333. }
  1334. $url = 'https://api.weixin.qq.com/cgi-bin/material/del_material?access_token=' . $token;
  1335. $data = array(
  1336. 'media_id' => trim($media_id),
  1337. );
  1338. $response = $this->requestApi($url, json_encode($data));
  1339. if (is_error($response)) {
  1340. return $response;
  1341. }
  1342. return true;
  1343. }
  1344. public function changeOrderStatus($send) {
  1345. if (empty($send)) {
  1346. return error(-1, '参数错误');
  1347. }
  1348. $token = $this->getAccessToken();
  1349. if (is_error($token)) {
  1350. return $token;
  1351. }
  1352. $sendapi = 'https://api.weixin.qq.com/pay/delivernotify?access_token=' . $token;
  1353. $response = ihttp_request($sendapi, json_encode($send));
  1354. $response = json_decode($response['content'], true);
  1355. if (empty($response)) {
  1356. return error(-1, '发货失败,请检查您的公众号权限或是公众号AppId和公众号AppSecret!');
  1357. }
  1358. if (!empty($response['errcode'])) {
  1359. return error(-1, $response['errmsg']);
  1360. }
  1361. return $response;
  1362. }
  1363. public function getOauthUserInfo($accesstoken, $openid) {
  1364. $apiurl = "https://api.weixin.qq.com/sns/userinfo?access_token={$accesstoken}&openid={$openid}&lang=zh_CN";
  1365. $response = $this->requestApi($apiurl);
  1366. unset($response['remark'], $response['subscribe_scene'], $response['qr_scene'], $response['qr_scene_str']);
  1367. return $response;
  1368. }
  1369. public function getOauthInfo($code = '') {
  1370. global $_W, $_GPC;
  1371. if (!empty($_GPC['code'])) {
  1372. $code = $_GPC['code'];
  1373. }
  1374. if (empty($code)) {
  1375. $oauth_url = uni_account_oauth_host();
  1376. $url = $oauth_url . "app/index.php?{$_SERVER['QUERY_STRING']}";
  1377. $forward = $this->getOauthCodeUrl(urlencode($url));
  1378. header('Location: ' . $forward);
  1379. exit;
  1380. }
  1381. $url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid={$this->account['key']}&secret={$this->account['secret']}&code={$code}&grant_type=authorization_code";
  1382. return $this->requestApi($url);
  1383. }
  1384. public function getOauthAccessToken() {
  1385. $cachekey = cache_system_key('oauthaccesstoken', array('acid' => $this->account['acid']));
  1386. $cache = cache_load($cachekey);
  1387. if (!empty($cache) && !empty($cache['token'])) {
  1388. return $cache['token'];
  1389. }
  1390. $token = $this->getOauthInfo();
  1391. if (is_error($token)) {
  1392. return error(1);
  1393. }
  1394. $record = array();
  1395. $record['token'] = $token['access_token'];
  1396. $record_expire = $token['expires_in'] - 200;
  1397. cache_write($cachekey, $record, $record_expire);
  1398. return $token['access_token'];
  1399. }
  1400. public function getShareAddressConfig() {
  1401. global $_W;
  1402. static $current_url;
  1403. if (empty($current_url)) {
  1404. $current_url = $_W['siteurl'];
  1405. }
  1406. $token = $this->getOauthAccessToken();
  1407. if (is_error($token)) {
  1408. return false;
  1409. }
  1410. $package = array(
  1411. 'appid' => $this->account['key'],
  1412. 'url' => $current_url,
  1413. 'timestamp' => strval(TIMESTAMP),
  1414. 'noncestr' => strval(random(8, true)),
  1415. 'accesstoken' => $token,
  1416. );
  1417. ksort($package, SORT_STRING);
  1418. $signstring = array();
  1419. foreach ($package as $k => $v) {
  1420. $signstring[] = "{$k}={$v}";
  1421. }
  1422. $signstring = strtolower(sha1(trim(implode('&', $signstring))));
  1423. $shareaddress_config = array(
  1424. 'appId' => $this->account['key'],
  1425. 'scope' => 'jsapi_address',
  1426. 'signType' => 'sha1',
  1427. 'addrSign' => $signstring,
  1428. 'timeStamp' => $package['timestamp'],
  1429. 'nonceStr' => $package['noncestr'],
  1430. );
  1431. return $shareaddress_config;
  1432. }
  1433. public function getOauthCodeUrl($callback, $state = '') {
  1434. return "https://open.weixin.qq.com/connect/oauth2/authorize?appid={$this->account['key']}&redirect_uri={$callback}&response_type=code&scope=snsapi_base&state={$state}#wechat_redirect";
  1435. }
  1436. public function getOauthUserInfoUrl($callback, $state = '', $extra = array()) {
  1437. $url_param = '';
  1438. if (!empty($extra['forcePopup'])) {
  1439. $url_param .= '&forcePopup=true';
  1440. }
  1441. if (!empty($extra['forceSnapShot'])) {
  1442. $url_param .= '&forceSnapShot=true';
  1443. }
  1444. return "https://open.weixin.qq.com/connect/oauth2/authorize?appid={$this->account['key']}&redirect_uri={$callback}&response_type=code&scope=snsapi_userinfo&state={$state}{$url_param}#wechat_redirect";
  1445. }
  1446. public function getFansStat() {
  1447. $token = $this->getAccessToken();
  1448. if (is_error($token)) {
  1449. return $token;
  1450. }
  1451. $url = "https://api.weixin.qq.com/datacube/getusersummary?access_token={$token}";
  1452. $data = array(
  1453. 'begin_date' => date('Y-m-d', strtotime('-7 days')),
  1454. 'end_date' => date('Y-m-d', strtotime('-1 days')),
  1455. );
  1456. $summary_response = $this->requestApi($url, json_encode($data));
  1457. if (is_error($summary_response)) {
  1458. return $summary_response;
  1459. }
  1460. $url = "https://api.weixin.qq.com/datacube/getusercumulate?access_token={$token}";
  1461. $cumulate_response = $this->requestApi($url, json_encode($data));
  1462. if (is_error($cumulate_response)) {
  1463. return $cumulate_response;
  1464. }
  1465. $result = array();
  1466. if (!empty($summary_response['list'])) {
  1467. foreach ($summary_response['list'] as $row) {
  1468. $key = str_replace('-', '', $row['ref_date']);
  1469. $result[$key]['new'] = intval($result[$key]['new']) + $row['new_user'];
  1470. $result[$key]['cancel'] = intval($result[$key]['cancel']) + $row['cancel_user'];
  1471. }
  1472. }
  1473. if (!empty($cumulate_response['list'])) {
  1474. foreach ($cumulate_response['list'] as $row) {
  1475. $key = str_replace('-', '', $row['ref_date']);
  1476. $result[$key]['cumulate'] = $row['cumulate_user'];
  1477. }
  1478. }
  1479. return $result;
  1480. }
  1481. public function getComment($msg_data_id, $index, $type = 0, $begin = 0, $count = 50) {
  1482. $token = $this->getAccessToken();
  1483. if (is_error($token)) {
  1484. return $token;
  1485. }
  1486. $url = "https://api.weixin.qq.com/cgi-bin/comment/list?access_token={$token}";
  1487. $data = array(
  1488. 'msg_data_id' => $msg_data_id,
  1489. 'index' => $index,
  1490. 'begin' => $begin,
  1491. 'count' => $count,
  1492. 'type' => $type,
  1493. );
  1494. return $this->requestApi($url, json_encode($data));
  1495. }
  1496. public function commentReply($msg_data_id, $user_comment_id, $content, $index = 0) {
  1497. $token = $this->getAccessToken();
  1498. if (is_error($token)) {
  1499. return $token;
  1500. }
  1501. $url = "https://api.weixin.qq.com/cgi-bin/comment/reply/add?access_token={$token}";
  1502. $data = array(
  1503. 'msg_data_id' => $msg_data_id,
  1504. 'user_comment_id' => $user_comment_id,
  1505. 'content' => $content,
  1506. 'index' => $index,
  1507. );
  1508. return $this->requestApi($url, stripslashes(ijson_encode($data, JSON_UNESCAPED_UNICODE)));
  1509. }
  1510. public function commentMark($msg_data_id, $user_comment_id, $comment_type, $index = 0) {
  1511. $token = $this->getAccessToken();
  1512. if (is_error($token)) {
  1513. return $token;
  1514. }
  1515. if (1 != $comment_type) {
  1516. $url = "https://api.weixin.qq.com/cgi-bin/comment/markelect?access_token={$token}";
  1517. } else {
  1518. $url = "https://api.weixin.qq.com/cgi-bin/comment/unmarkelect?access_token={$token}";
  1519. }
  1520. $data = array(
  1521. 'msg_data_id' => $msg_data_id,
  1522. 'user_comment_id' => $user_comment_id,
  1523. 'index' => $index,
  1524. );
  1525. return $this->requestApi($url, json_encode($data));
  1526. }
  1527. public function commentDelete($msg_data_id, $user_comment_id, $index = 0) {
  1528. $token = $this->getAccessToken();
  1529. if (is_error($token)) {
  1530. return $token;
  1531. }
  1532. $url = "https://api.weixin.qq.com/cgi-bin/comment/delete?access_token={$token}";
  1533. $data = array(
  1534. 'msg_data_id' => $msg_data_id,
  1535. 'user_comment_id' => $user_comment_id,
  1536. 'index' => $index,
  1537. );
  1538. return $this->requestApi($url, json_encode($data));
  1539. }
  1540. public function commentReplyDelete($msg_data_id, $user_comment_id, $index = 0) {
  1541. $token = $this->getAccessToken();
  1542. if (is_error($token)) {
  1543. return $token;
  1544. }
  1545. $url = "https://api.weixin.qq.com/cgi-bin/comment/reply/delete?access_token={$token}";
  1546. $data = array(
  1547. 'msg_data_id' => $msg_data_id,
  1548. 'user_comment_id' => $user_comment_id,
  1549. 'index' => $index,
  1550. );
  1551. return $this->requestApi($url, json_encode($data));
  1552. }
  1553. public function commentSwitch($msg_data_id, $need_open_comment, $index = 0) {
  1554. $token = $this->getAccessToken();
  1555. if (is_error($token)) {
  1556. return $token;
  1557. }
  1558. if (1 == $need_open_comment) {
  1559. $url = "https://api.weixin.qq.com/cgi-bin/comment/close?access_token={$token}";
  1560. } else {
  1561. $url = "https://api.weixin.qq.com/cgi-bin/comment/open?access_token={$token}";
  1562. }
  1563. $data = array(
  1564. 'msg_data_id' => $msg_data_id,
  1565. 'index' => $index,
  1566. );
  1567. return $this->requestApi($url, json_encode($data));
  1568. }
  1569. protected function requestApi($url, $post = '') {
  1570. $response = ihttp_request($url, $post);
  1571. $result = @json_decode($response['content'], true);
  1572. if (is_error($response)) {
  1573. if (empty($result)) {
  1574. return error(-1, "接口调用失败, 元数据: {$response['message']}");
  1575. }
  1576. return error($result['errcode'], "访问公众平台接口失败, 错误详情: {$this->errorCode($result['errcode'])}");
  1577. }
  1578. if (empty($result)) {
  1579. return error(-1, "接口调用失败, 元数据: {$response['meta']}");
  1580. } elseif (!empty($result['errcode'])) {
  1581. if ($result['errcode'] == '40001') {
  1582. return error('40001', '由于应用单独调用微信接口获取accesstoken造成无法正常访问微信接口,请开发者按照系统标准接入。您可以临时联系管理员通过重置appsecret来解决!');
  1583. }
  1584. return error($result['errcode'], "访问公众平台接口失败, 错误: {$result['errmsg']},错误码:{$result['errcode']},错误详情:{$this->errorCode($result['errcode'])}");
  1585. }
  1586. return $result;
  1587. }
  1588. public function getMaterialSupport() {
  1589. return array(
  1590. 'mass' => array('basic' => false, 'news' => false, 'image' => false, 'voice' => false, 'video' => false),
  1591. 'chats' => array('basic' => false, 'news' => false, 'image' => false, 'music' => false, 'voice' => false, 'video' => false),
  1592. );
  1593. }
  1594. public function batchGetDraft($offset = 0, $count = 20, $no_content = 0) {
  1595. $token = $this->getAccessToken();
  1596. if (is_error($token)) {
  1597. return $token;
  1598. }
  1599. $url = 'https://api.weixin.qq.com/cgi-bin/draft/batchget?access_token=' . $token;
  1600. $data = array(
  1601. 'offset' => intval($offset),
  1602. 'count' => $count,
  1603. 'no_content' => intval($no_content)
  1604. );
  1605. return $this->requestApi($url, json_encode($data));
  1606. }
  1607. public function getMaterialDraft($media_id, $savefile = true) {
  1608. $token = $this->getAccessToken();
  1609. if (is_error($token)) {
  1610. return $token;
  1611. }
  1612. $url = 'https://api.weixin.qq.com/cgi-bin/draft/get?access_token=' . $token;
  1613. $data = array(
  1614. 'media_id' => trim($media_id),
  1615. );
  1616. $response = ihttp_request($url, json_encode($data));
  1617. if (is_error($response)) {
  1618. return error(-1, "访问公平台接口失败, 错误: {$response['message']}");
  1619. }
  1620. $result = @json_decode($response['content'], true);
  1621. if (!empty($result['errcode'])) {
  1622. return error(-1, "访问公众平台接口失败, 错误: {$result['errmsg']},错误详情:{$this->errorCode($result['errcode'])}");
  1623. }
  1624. if (empty($response['headers']['Content-disposition'])) {
  1625. $response = json_decode($response['content'], true);
  1626. if (!empty($response['down_url'])) {
  1627. if (empty($savefile)) {
  1628. return $response;
  1629. }
  1630. $response = ihttp_get($response['down_url']);
  1631. $response['headers']['Content-disposition'] = $response['headers']['Content-Disposition'];
  1632. } elseif (!empty($response['news_item'])) {
  1633. return $response;
  1634. }
  1635. }
  1636. if ($savefile && !empty($response['headers']['Content-disposition']) && strexists($response['headers']['Content-disposition'], 'filename=')) {
  1637. global $_W;
  1638. preg_match('/filename=\"?([^"]*)/', $response['headers']['Content-disposition'], $match);
  1639. $pathinfo = pathinfo($match[1]);
  1640. $filename = $_W['uniacid'] . '/' . date('Y/m/');
  1641. if (in_array(strtolower($pathinfo['extension']), array('mp4'))) {
  1642. $filename = 'videos/' . $filename;
  1643. } elseif (in_array(strtolower($pathinfo['extension']), array('amr', 'mp3', 'wma', 'wmv'))) {
  1644. $filename = 'audios/' . $filename;
  1645. } else {
  1646. $filename = 'images/' . $filename;
  1647. }
  1648. $filename .= file_random_name($filename, $pathinfo['extension']);
  1649. load()->func('file');
  1650. file_write($filename, $response['content']);
  1651. file_remote_upload($filename);
  1652. return $filename;
  1653. } else {
  1654. return $response['content'];
  1655. }
  1656. return $result;
  1657. }
  1658. public function delMaterialDraft($media_id) {
  1659. $media_id = trim($media_id);
  1660. if (empty($media_id)) {
  1661. return error(-1, '素材media_id错误');
  1662. }
  1663. $token = $this->getAccessToken();
  1664. if (is_error($token)) {
  1665. return $token;
  1666. }
  1667. $url = 'https://api.weixin.qq.com/cgi-bin/draft/delete?access_token=' . $token;
  1668. $data = array(
  1669. 'media_id' => trim($media_id),
  1670. );
  1671. $response = $this->requestApi($url, json_encode($data));
  1672. if (is_error($response)) {
  1673. return $response;
  1674. }
  1675. return true;
  1676. }
  1677. public function publishDraft($media_id) {
  1678. $media_id = trim($media_id);
  1679. if (empty($media_id)) {
  1680. return error(-1, '素材media_id错误');
  1681. }
  1682. $token = $this->getAccessToken();
  1683. if (is_error($token)) {
  1684. return $token;
  1685. }
  1686. $url = 'https://api.weixin.qq.com/cgi-bin/freepublish/submit?access_token=' . $token;
  1687. $data = array(
  1688. 'media_id' => $media_id,
  1689. );
  1690. return $this->requestApi($url, json_encode($data));
  1691. }
  1692. public function deletePublishDraft($article_id, $index = 0) {
  1693. $article_id = trim($article_id);
  1694. if (empty($article_id)) {
  1695. return error(-1, '素材media_id错误');
  1696. }
  1697. $token = $this->getAccessToken();
  1698. if (is_error($token)) {
  1699. return $token;
  1700. }
  1701. $url = 'https://api.weixin.qq.com/cgi-bin/freepublish/delete?access_token=' . $token;
  1702. $data = array(
  1703. 'article_id' => $article_id,
  1704. 'index' => $index
  1705. );
  1706. return $this->requestApi($url, json_encode($data));
  1707. }
  1708. public function batchGetPublishDraft($offset = 0, $count = 20, $no_content = 0) {
  1709. $token = $this->getAccessToken();
  1710. if (is_error($token)) {
  1711. return $token;
  1712. }
  1713. $url = 'https://api.weixin.qq.com/cgi-bin/freepublish/batchget?access_token=' . $token;
  1714. $data = array(
  1715. 'offset' => intval($offset),
  1716. 'count' => $count,
  1717. 'no_content' => intval($no_content)
  1718. );
  1719. return $this->requestApi($url, json_encode($data));
  1720. }
  1721. }