WeiXin.php 55 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394
  1. <?php
  2. /**
  3. * Created by ChenTAO.
  4. * User: Administrator
  5. * Date: 15-10-8
  6. * Time: 上午9:20
  7. * Desc: 微信基类
  8. */
  9. namespace app\components\WeiXin;
  10. use Yii;
  11. class WeiXin extends \yii\base\Component{
  12. private $appId;//应用ID
  13. private $appSecret;//加密秘钥
  14. private $token;//用于验证签名
  15. private $jsDomain;//js接口安全域名
  16. private $accessToken;//接口通信凭据
  17. private $acessTokenFile;//文件存储$accessToken
  18. private $jsApiTicketFile;//文件存储js api 凭据
  19. private $getAccessTokenUrl;//获取$accessToken的接口地址
  20. private $getIpListUrl;//获取微信服务器IP接口地址
  21. private $getUserInfoUrl;//根据open_id获取用户信息接口地址
  22. private $getJsApiTicketUrl;//获取js ticket的接口地址
  23. private $addMaterialUrl;//新增永久素材接口地址(媒体文件类型,分别有图片(image)、语音(voice)、视频(video)和缩略图(thumb))
  24. private $addNewsUrl;//新增永久图文素材接口
  25. private $uploadImgUrl;//图文素材中的图片上传接口
  26. private $getMediaUrl;//永久素材获取接口
  27. private $updateNewsUrl;//修改永久图文素材接口
  28. private $delMediaUrl;//删除永久素材接口
  29. private $getMaterialCountUrl;//获取素材数量
  30. private $batcheGetMaterialUrl;//批量获取素材
  31. private $uploadNewsVideoUrl;//群发消息视频素材上传接口
  32. private $msgSendAllUrl;//消息群发接口
  33. private $msgSendUrl;//消息群发接口
  34. private $msgPreviewUrl;//群发消息预览接口
  35. private $delMsgUrl;//删除群发接口
  36. private $getMsgStatusUrl;//查询群发状态
  37. private $createGroupUrl;//创建分组接口
  38. private $getGroupsUrl;//查询所有分组信息
  39. private $getGroupIdByOpenIdUrl;//查询用户所在分组
  40. private $updateGroupNameUrl;//修改用户分组名称
  41. private $changeUserGroupUrl;//改变用户所在分组
  42. private $batchChangeUserGroupUrl;//批量改变用户所在分组
  43. private $delGroupUrl;//删除用户分组
  44. private $updateRemarkUrl;//修改用户备注
  45. private $batchGetUserInfoUrl;//批量获取用户信息
  46. private $getUserListUrl;//获取关注者列表
  47. private $getWebAuthCodeUrl;//获取网页授权CODE URL
  48. private $webAuthAccessToken;//网页授权token
  49. private $getWebAuthAccessTokenUrl;//获取网页授权token url
  50. private $currentOpenId;//当前用户
  51. private $getWebAuthUserInfoUrl;//获取授权用户信息
  52. private $createMenuUrl;//创建自定义菜单
  53. private $getMenuListUrl;//查询自定义菜单
  54. private $deleteMenuUrl;//删除自定义菜单
  55. private $createQrcodeUrl;//创建二维码
  56. private $getQrcodeUrl;//获取二维码地址
  57. private $getShortUrl;//长链接转短链接
  58. private $tplMsgUrl;//模板消息接口地址
  59. private $customerMsgUrl;//客服消息接口
  60. private $wxIpList;//微信服务器IP
  61. public $parameters;
  62. //以下与微信支付相关
  63. public $basePath;
  64. public $partnerKey;
  65. public $mchId;//商户号 1348501701
  66. public $addOrderUrl;//微信下单接口
  67. public $qryOrderUrl;//订单查询接口
  68. public $redPackUrl;//红包发送接口
  69. public $signType = 'MD5';
  70. public $timestamp;
  71. //构造
  72. public function __construct($args)
  73. {
  74. extract($args);
  75. if(empty($appId)||empty($appSecret)||empty($token))$this->showErrorMessage('缺少appid,或appsecret,或token!');
  76. $this->appId = $appId;
  77. $this->appSecret = $appSecret;
  78. $this->token = $token;
  79. $this->timestamp = time();
  80. !empty($jsDomain)&&$this->jsDomain = $jsDomain;
  81. $this->basePath = Yii::$app->params['wxPath'];
  82. dir_create($this->basePath);
  83. $this->acessTokenFile = $this->basePath.$this->appId.'_access_token.json';//文件存储$accessToken
  84. $this->jsApiTicketFile = $this->basePath.$this->appId.'_jsapi_ticket.json';//文件存储js api 凭据
  85. }
  86. //初始化
  87. public function init()
  88. {
  89. $this->getAccessTokenUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=".$this->appId."&secret=".$this->appSecret;
  90. $this->getIpListUrl = "https://api.weixin.qq.com/cgi-bin/getcallbackip?access_token=%s";
  91. $this->getUserInfoUrl= "https://api.weixin.qq.com/cgi-bin/user/info?access_token=%s&openid=%s&lang=zh_CN";
  92. $this->getJsApiTicketUrl = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=%s&type=jsapi";
  93. $this->addMaterialUrl= "https://api.weixin.qq.com/cgi-bin/material/add_material?access_token=%s";
  94. $this->addNewsUrl = "https://api.weixin.qq.com/cgi-bin/material/add_news?access_token=%s";
  95. $this->uploadImgUrl = "https://api.weixin.qq.com/cgi-bin/media/uploadimg?access_token=%s";
  96. $this->getMediaUrl = "https://api.weixin.qq.com/cgi-bin/material/get_material?access_token=%s";
  97. $this->updateNewsUrl = "https://api.weixin.qq.com/cgi-bin/material/update_news?access_token=%s";
  98. $this->delMediaUrl = "https://api.weixin.qq.com/cgi-bin/material/del_material?access_token=%s";
  99. $this->getMaterialCountUrl = "https://api.weixin.qq.com/cgi-bin/material/get_materialcount?access_token=%s";
  100. $this->batcheGetMaterialUrl = "https://api.weixin.qq.com/cgi-bin/material/batchget_material?access_token=%s";
  101. $this->uploadNewsVideoUrl = "https://file.api.weixin.qq.com/cgi-bin/media/uploadvideo?access_token=%s";
  102. $this->msgSendAllUrl = "https://api.weixin.qq.com/cgi-bin/message/mass/sendall?access_token=%s";
  103. $this->msgSendUrl = "https://api.weixin.qq.com/cgi-bin/message/mass/send?access_token=%s";
  104. $this->msgPreviewUrl = "https://api.weixin.qq.com/cgi-bin/message/mass/preview?access_token=%s";
  105. $this->delMsgUrl = "https://api.weixin.qq.com/cgi-bin/message/mass/delete?access_token=%s";
  106. $this->getMsgStatusUrl = "https://api.weixin.qq.com/cgi-bin/message/mass/get?access_token=%s";
  107. $this->createGroupUrl = "https://api.weixin.qq.com/cgi-bin/groups/create?access_token=%s";
  108. $this->getGroupsUrl = "https://api.weixin.qq.com/cgi-bin/groups/get?access_token=%s";
  109. $this->getGroupIdByOpenIdUrl = "https://api.weixin.qq.com/cgi-bin/groups/getid?access_token=%s";
  110. $this->updateGroupNameUrl = "https://api.weixin.qq.com/cgi-bin/groups/update?access_token=%s";
  111. $this->changeUserGroupUrl = "https://api.weixin.qq.com/cgi-bin/groups/members/update?access_token=%s";
  112. $this->batchChangeUserGroupUrl = "https://api.weixin.qq.com/cgi-bin/groups/members/batchupdate?access_token=%s";
  113. $this->delGroupUrl = "https://api.weixin.qq.com/cgi-bin/groups/delete?access_token=%s";
  114. $this->updateRemarkUrl = "https://api.weixin.qq.com/cgi-bin/user/info/updateremark?access_token=%s";
  115. $this->batchGetUserInfoUrl = "https://api.weixin.qq.com/cgi-bin/user/info/batchget?access_token=%s";
  116. $this->getUserListUrl = "https://api.weixin.qq.com/cgi-bin/user/get?access_token=%s&next_openid=%s";
  117. $this->getWebAuthCodeUrl = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=%s&state=%s#wechat_redirect";
  118. $this->getWebAuthAccessTokenUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code";
  119. $this->getWebAuthUserInfoUrl = "https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s&lang=zh_CN";
  120. $this->createMenuUrl = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=%s";
  121. $this->getMenuListUrl = "https://api.weixin.qq.com/cgi-bin/menu/get?access_token=%s";
  122. $this->deleteMenuUrl = "https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=%s";
  123. $this->createQrcodeUrl = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=%s";
  124. $this->getQrcodeUrl = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=%s";
  125. $this->getShortUrl = "https://api.weixin.qq.com/cgi-bin/shorturl?access_token=%s";
  126. $this->addOrderUrl = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
  127. $this->qryOrderUrl = 'https://api.mch.weixin.qq.com/pay/orderquery';
  128. $this->redPackUrl = 'https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack';
  129. $this->tplMsgUrl = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=%s";
  130. $this->customerMsgUrl = "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=%s";
  131. return $this;
  132. }
  133. //获取短链接
  134. public function createShortUrl($longUrl)
  135. {
  136. $this->getAccessToken();
  137. $this->getShortUrl = sprintf($this->getShortUrl,$this->accessToken);
  138. $postdata = json_encode(array('action'=>'long2short','long_url'=>$longUrl),JSON_UNESCAPED_UNICODE);
  139. $result = $this->httpsRequest($this->getShortUrl, $postdata);
  140. $result = json_decode($result,true);
  141. return $result;
  142. }
  143. //创建二维码 $type 1:永久,2:临时
  144. public function createQrcode($sceneId,$type=1,$expireSeconds=604800)
  145. {
  146. $this->getAccessToken();
  147. $this->createQrcodeUrl = sprintf($this->createQrcodeUrl,$this->accessToken);
  148. if($type==1)
  149. {
  150. $postdata = '{"action_name": "QR_LIMIT_SCENE", "action_info": {"scene": {"scene_id": '.$sceneId.'}}}';
  151. }
  152. if($type==2)
  153. {
  154. $postdata = '{"expire_seconds": '.$expireSeconds.', "action_name": "QR_SCENE", "action_info": {"scene": {"scene_id": '.$sceneId.'}}}';
  155. }
  156. if($type==3)
  157. {
  158. $postdata = '{"expire_seconds": '.$expireSeconds.', "action_name": "QR_STR_SCENE", "action_info": {"scene": {"scene_str": "'.$sceneId.'"}}}';
  159. }
  160. $result = $this->httpsRequest($this->createQrcodeUrl, $postdata);
  161. $result = json_decode($result,true);
  162. $result['codeUrl'] = sprintf($this->getQrcodeUrl,urlencode($result['ticket']));
  163. return $result;
  164. }
  165. //删除自定义菜单
  166. public function deleteMenu()
  167. {
  168. $this->getAccessToken();
  169. $this->deleteMenuUrl = sprintf($this->deleteMenuUrl,$this->accessToken);
  170. $result = json_decode($this->httpGet($this->deleteMenuUrl),true);
  171. return $result;
  172. }
  173. //创建自定义菜单
  174. public function createMenu($buttons)
  175. {
  176. $this->getAccessToken();
  177. $this->createMenuUrl = sprintf($this->createMenuUrl,$this->accessToken);
  178. $array['button'] = $buttons;
  179. $result = $this->httpsRequest($this->createMenuUrl, json_encode($array,JSON_UNESCAPED_UNICODE));
  180. $result = json_decode($result,true);
  181. return $result;
  182. }
  183. //查询自定义菜单
  184. public function getMenuList()
  185. {
  186. $this->getAccessToken();
  187. $this->getMenuListUrl = sprintf($this->getMenuListUrl,$this->accessToken);
  188. $result = json_decode($this->httpGet($this->getMenuListUrl),true);
  189. return $result;
  190. }
  191. /* 第一步:用户同意授权,获取code
  192. * 获取网页授权地址$scope:nsapi_base (不弹出授权页面,直接跳转,只能获取用户openid),
  193. snsapi_userinfo (弹出授权页面,可通过openid拿到昵称、性别、所在地。并且,即使在未关注的情况下,只要用户授权,也能获取其信息)
  194. */
  195. public function getWebAuthUrl($redirectUrl,$scope='snsapi_userinfo',$state='MR8888')
  196. {
  197. $this->getWebAuthCodeUrl = sprintf($this->getWebAuthCodeUrl,$this->appId,$redirectUrl,$scope,$state);
  198. return $this->getWebAuthCodeUrl;
  199. }
  200. //第二步:通过code换取网页授权access_token
  201. public function getWebAuthAccessToken()
  202. {
  203. try
  204. {
  205. $this->getWebAuthAccessTokenUrl = sprintf($this->getWebAuthAccessTokenUrl,$this->appId,$this->appSecret,$_GET['code']);
  206. $data = json_decode($this->httpGet($this->getWebAuthAccessTokenUrl),true);
  207. $this->webAuthAccessToken = $data['access_token'];
  208. $this->currentOpenId = $data['openid'];
  209. }
  210. catch(\Exception $e)
  211. {
  212. $this->showError($e->getMessage());
  213. }
  214. }
  215. // 第二步:通过code换取网页授权access_token
  216. public function getOauthAccessToken($code)
  217. {
  218. $url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=".$this->appId."&secret=".$this->appSecret."&code=$code&grant_type=authorization_code";
  219. return json_decode($this->httpGet($url),true);
  220. }
  221. //第三步:拉取用户信息(需scope为 snsapi_userinfo)
  222. public function getWebAuthUserInfo()
  223. {
  224. /*$result = $this->getOauthAccessToken($_GET['code']);
  225. $this->webAuthAccessToken = $result['access_token'];
  226. $this->currentOpenId = $result['openid'];*/
  227. $this->getWebAuthAccessToken();
  228. $this->getWebAuthUserInfoUrl = sprintf($this->getWebAuthUserInfoUrl,$this->webAuthAccessToken,$this->currentOpenId);
  229. $result = json_decode($this->httpGet($this->getWebAuthUserInfoUrl),true);
  230. $result['nick_name'] = $result['nickname'];
  231. $result['avatar'] = $result['headimgurl'];
  232. return $result;
  233. }
  234. //获取用户列表
  235. public function getUserList($nextOpenId='')
  236. {
  237. try
  238. {
  239. $this->getAccessToken();
  240. $this->getUserListUrl = sprintf($this->getUserListUrl,$this->accessToken,$nextOpenId);
  241. $result = json_decode($this->httpGet($this->getUserListUrl),true);
  242. return $result;
  243. }
  244. catch(\Exception $e)
  245. {
  246. $this->showError($e->getMessage());
  247. }
  248. }
  249. //批量获取用户基本信息
  250. public function batchGetUserInfo($userList)
  251. {
  252. try
  253. {
  254. $this->getAccessToken();
  255. $this->batchGetUserInfoUrl = sprintf($this->batchGetUserInfoUrl,$this->accessToken);
  256. if(is_array($userList))foreach($userList as $openId)
  257. {
  258. $array['user_list'][] = array('openid'=>$openId,'lang'=>'zh-CN');
  259. }
  260. $result = $this->httpsRequest($this->batchGetUserInfoUrl, json_encode($array,JSON_UNESCAPED_UNICODE));
  261. $result = json_decode($result,true);
  262. return $result;
  263. }
  264. catch(\Exception $e)
  265. {
  266. $this->showError($e->getMessage());
  267. }
  268. }
  269. //修改用户备注
  270. public function updateRemark($openId,$remark)
  271. {
  272. try
  273. {
  274. $this->getAccessToken();
  275. $this->updateRemarkUrl = sprintf($this->updateRemarkUrl,$this->accessToken);
  276. $array = array('openid'=>$openId,'remark'=>$remark);
  277. $result = $this->httpsRequest($this->updateRemarkUrl, json_encode($array,JSON_UNESCAPED_UNICODE));
  278. $result = json_decode($result,true);
  279. return $result;
  280. }
  281. catch(\Exception $e)
  282. {
  283. $this->showError($e->getMessage());
  284. }
  285. }
  286. //创建分组
  287. public function createGroup($groupName)
  288. {
  289. try
  290. {
  291. $this->getAccessToken();
  292. $this->createGroupUrl = sprintf($this->createGroupUrl,$this->accessToken);
  293. $array['group'] = array('name'=>$groupName);
  294. $result = $this->httpsRequest($this->createGroupUrl, json_encode($array,JSON_UNESCAPED_UNICODE));
  295. $result = json_decode($result,true);
  296. return $result;
  297. }
  298. catch(\Exception $e)
  299. {
  300. $this->showError($e->getMessage());
  301. }
  302. }
  303. //查询所有分组信息
  304. public function getGroups()
  305. {
  306. try
  307. {
  308. $this->getAccessToken();
  309. $this->getGroupsUrl = sprintf($this->getGroupsUrl,$this->accessToken);
  310. $result = $this->httpGet($this->getGroupsUrl);
  311. $result = json_decode($result,true);
  312. return $result;
  313. }
  314. catch(\Exception $e)
  315. {
  316. $this->showError($e->getMessage());
  317. }
  318. }
  319. //查询用户所在分组
  320. public function getGroupId($openId)
  321. {
  322. try
  323. {
  324. $this->getAccessToken();
  325. $this->getGroupIdByOpenIdUrl = sprintf($this->getGroupIdByOpenIdUrl,$this->accessToken);
  326. $array['openid'] = $openId;
  327. $result = $this->httpsRequest($this->getGroupIdByOpenIdUrl, json_encode($array,JSON_UNESCAPED_UNICODE));
  328. $result = json_decode($result,true);
  329. return $result;
  330. }
  331. catch(\Exception $e)
  332. {
  333. $this->showError($e->getMessage());
  334. }
  335. }
  336. //修改用户分组名称
  337. public function updateGroupName($groupId,$groupName)
  338. {
  339. try
  340. {
  341. $this->getAccessToken();
  342. $this->updateGroupNameUrl = sprintf($this->updateGroupNameUrl,$this->accessToken);
  343. $array['group'] = array('id'=>$groupId,'name'=>$groupName);
  344. $result = $this->httpsRequest($this->updateGroupNameUrl, json_encode($array,JSON_UNESCAPED_UNICODE));
  345. $result = json_decode($result,true);
  346. return $result;
  347. }
  348. catch(\Exception $e)
  349. {
  350. $this->showError($e->getMessage());
  351. }
  352. }
  353. //修改用户所在分组,支持批量转移
  354. public function changUserGroup($openId,$toGroupId)
  355. {
  356. try
  357. {
  358. $this->getAccessToken();
  359. if(is_array($openId))
  360. {
  361. $requestUrl = sprintf($this->batchChangeUserGroupUrl,$this->accessToken);
  362. $array= array('openid_list'=>$openId,'to_groupid'=>$toGroupId);
  363. }
  364. else
  365. {
  366. $requestUrl = sprintf($this->changeUserGroupUrl,$this->accessToken);
  367. $array= array('openid'=>$openId,'to_groupid'=>$toGroupId);
  368. }
  369. $result = $this->httpsRequest($requestUrl, json_encode($array,JSON_UNESCAPED_UNICODE));
  370. $result = json_decode($result,true);
  371. return $result;
  372. }
  373. catch(\Exception $e)
  374. {
  375. $this->showError($e->getMessage());
  376. }
  377. }
  378. //删除分组
  379. public function deleteGroup($groupId)
  380. {
  381. try
  382. {
  383. $this->getAccessToken();
  384. $this->delGroupUrl = sprintf($this->delGroupUrl,$this->accessToken);
  385. $array['group'] = array('id'=>$groupId);
  386. $result = $this->httpsRequest($this->delGroupUrl, json_encode($array,JSON_UNESCAPED_UNICODE));
  387. $result = json_decode($result,true);
  388. return $result;
  389. }
  390. catch(Exception $e)
  391. {
  392. $this->showError($e->getMessage());
  393. }
  394. }
  395. //根据openid 获取用户基本信息
  396. public function getUserInfo($open_id)
  397. {
  398. try
  399. {
  400. $this->getAccessToken();
  401. $this->getUserInfoUrl = sprintf($this->getUserInfoUrl,$this->accessToken,$open_id);
  402. $result = json_decode($this->httpGet($this->getUserInfoUrl),TRUE);
  403. return $result;
  404. }
  405. catch(\Exception $e)
  406. {
  407. $this->showError($e->getMessage());
  408. }
  409. }
  410. //群发消息
  411. public function msgSend($contentInfo)
  412. {
  413. try
  414. {
  415. $this->getAccessToken();
  416. $msg =array();
  417. $sendUrl = sprintf($this->msgSendAllUrl,$this->accessToken);
  418. extract($contentInfo);
  419. if(is_numeric($groupId))
  420. {
  421. $msg['filter'] = array('is_to_all'=>false,'group_id'=>$groupId);
  422. }
  423. if(!empty($openIds)&&is_array($openIds))
  424. {
  425. $msg['touser'] = $openIds;
  426. $sendUrl = sprintf($this->msgSendUrl,$this->accessToken);
  427. }
  428. $msg['msgtype'] = $msgtype;
  429. if($msgtype=='mpnews')//群发图文
  430. {
  431. $msg['mpnews'] = array('media_id'=>$media_id);
  432. }
  433. if($msgtype=='text')//群发文本
  434. {
  435. $msg['text'] = array('content'=>$content);
  436. }
  437. if($msgtype=='voice')//群发语音
  438. {
  439. $msg['voice'] = array('media_id'=>$media_id);
  440. }
  441. if($msgtype=='image')//群发图片
  442. {
  443. $msg['image'] = array('media_id'=>$media_id);
  444. }
  445. if($msgtype=='mpvideo')//群发视频
  446. {
  447. $msg['mpvideo'] = array('media_id'=>$media_id);
  448. }
  449. if($msgtype=='wxcard')//卡券消息
  450. {
  451. $msg['wxcard'] = array('card_id'=>$card_id);
  452. }
  453. $result = $this->httpsRequest($sendUrl, json_encode($msg,JSON_UNESCAPED_UNICODE));
  454. $result = json_decode($result,true);
  455. return $result;
  456. }
  457. catch(\Exception $e)
  458. {
  459. $this->showError($e->getMessage());
  460. }
  461. }
  462. //消息预览 $contentInfo:
  463. public function msgPreview($contentInfo)
  464. {
  465. try
  466. {
  467. $this->getAccessToken();
  468. $msg =array();
  469. $this->msgPreviewUrl = sprintf($this->msgPreviewUrl,$this->accessToken);
  470. extract($contentInfo);
  471. if(!empty($towxname)) $msg['towxname'] = $towxname;
  472. if(!empty($touser)) $msg['touser'] = $touser;
  473. $msg['msgtype'] = $msgtype;
  474. if($msgtype=='mpnews')//群发图文
  475. {
  476. $msg['mpnews'] = array('media_id'=>$media_id);
  477. }
  478. if($msgtype=='text')//群发文本
  479. {
  480. $msg['text'] = array('content'=>$content);
  481. }
  482. if($msgtype=='voice')//群发语音
  483. {
  484. $msg['voice'] = array('media_id'=>$media_id);
  485. }
  486. if($msgtype=='image')//群发图片
  487. {
  488. $msg['image'] = array('media_id'=>$media_id);
  489. }
  490. if($msgtype=='mpvideo')//群发视频
  491. {
  492. $msg['mpvideo'] = array('media_id'=>$media_id);
  493. }
  494. if($msgtype=='wxcard')//卡券消息
  495. {
  496. $msg['wxcard'] = array('card_id'=>$card_id,'card_ext'=>$card_ext);
  497. }
  498. $result = $this->httpsRequest($this->msgPreviewUrl, json_encode($msg,JSON_UNESCAPED_UNICODE));
  499. $result = json_decode($result,true);
  500. return $result;
  501. }
  502. catch(\Exception $e)
  503. {
  504. $this->showError($e->getMessage());
  505. }
  506. }
  507. //删除群发消息
  508. public function delMsg($msgId)
  509. {
  510. $this->getAccessToken();
  511. $this->delMsgUrl = sprintf($this->delMsgUrl,$this->accessToken);
  512. $array = array('msg_id'=>$msgId);
  513. $result = $this->httpsRequest($this->delMsgUrl, json_encode($array,JSON_UNESCAPED_UNICODE));
  514. $result = json_decode($result,true);
  515. return $result;
  516. }
  517. //获取群发消息状态
  518. public function msgStatus($msgId)
  519. {
  520. $this->getAccessToken();
  521. $this->getMsgStatusUrl = sprintf($this->getMsgStatusUrl,$this->accessToken);
  522. $array = array('msg_id'=>$msgId);
  523. $result = $this->httpsRequest($this->getMsgStatusUrl, json_encode($array,JSON_UNESCAPED_UNICODE));
  524. $result = json_decode($result,true);
  525. return $result;
  526. }
  527. //客服消息
  528. public function sendCustomermsg($type,$openid,$data)
  529. {
  530. $this->getAccessToken();
  531. $this->customerMsgUrl = sprintf($this->customerMsgUrl,$this->accessToken);
  532. if($type=='text')
  533. {
  534. $msgcontent = '{ "touser" : "'.$openid.'",
  535. "msgtype" : "text",
  536. "text" : {
  537. "content" : "'.$data['content'].'"
  538. }
  539. }';
  540. }
  541. if($type=='image'||$type=='voice'||$type=='mpnews')
  542. {
  543. $msgcontent = '{ "touser" : "'.$openid.'",
  544. "msgtype" : "'.$type.'",
  545. "'.$type.'" : {
  546. "media_id" : "'.$data['media_id'].'"
  547. }
  548. }';
  549. }
  550. if($type=='news')
  551. {
  552. $msgcontent = '{"touser":"'.$openid.'",
  553. "msgtype":"news",
  554. "news":{
  555. "articles": [
  556. {
  557. "title":"'.$data['title'].'",
  558. "description":"'.$data['description'].'",
  559. "url":"'.$data['url'].'",
  560. "picurl":"'.getFileUrl($data['picurl']).'"
  561. }
  562. ]
  563. }
  564. }';
  565. }
  566. if($type=='video')
  567. {
  568. $msgcontent = '{
  569. "touser":"'.$openid.'",
  570. "msgtype":"video",
  571. "video":
  572. {
  573. "media_id":"'.$data['media_id'].'",
  574. "thumb_media_id":"'.$data['thumb_media_id'].'",
  575. "title":"'.$data['title'].'",
  576. "description":"'.$data['description'].'",
  577. }
  578. }';
  579. }
  580. $result = $this->httpsRequest($this->customerMsgUrl, $msgcontent);
  581. $result = json_decode($result,true);
  582. return $result;
  583. }
  584. //自动回复消息
  585. public function responseMsg($array,$articles=array())
  586. {
  587. try
  588. {
  589. $receive = $this->receiveMsg();
  590. if (!empty($receive)){
  591. $fromUsername = $receive['fromUsername'];
  592. $toUsername = $receive['toUsername'];
  593. $time = TIMESTAMP;
  594. extract($array);
  595. if($type=='text')
  596. {
  597. $tpl = "<xml>
  598. <ToUserName><![CDATA[%s]]></ToUserName>
  599. <FromUserName><![CDATA[%s]]></FromUserName>
  600. <CreateTime>%s</CreateTime>
  601. <MsgType><![CDATA[%s]]></MsgType>
  602. <Content><![CDATA[%s]]></Content>
  603. <FuncFlag>0</FuncFlag>
  604. </xml>";
  605. $resultStr = sprintf($tpl, $fromUsername, $toUsername, $time, $type, $content);
  606. }
  607. if($type=='image')
  608. {
  609. $tpl="<xml>
  610. <ToUserName><![CDATA[%s]]></ToUserName>
  611. <FromUserName><![CDATA[%s]]></FromUserName>
  612. <CreateTime>%s</CreateTime>
  613. <MsgType><![CDATA[%s]]></MsgType>
  614. <Image>
  615. <MediaId><![CDATA[%s]]></MediaId>
  616. </Image>
  617. </xml>";
  618. $resultStr = sprintf($tpl, $fromUsername, $toUsername, $time, $type, $media_id);
  619. }
  620. if($type=='voice')
  621. {
  622. $tpl = "<xml>
  623. <ToUserName><![CDATA[%s]]></ToUserName>
  624. <FromUserName><![CDATA[%s]]></FromUserName>
  625. <CreateTime>%s</CreateTime>
  626. <MsgType><![CDATA[%s]]></MsgType>
  627. <Voice>
  628. <MediaId><![CDATA[%s]]></MediaId>
  629. </Voice>
  630. </xml>";
  631. $resultStr = sprintf($tpl, $fromUsername, $toUsername, $time, $type, $media_id);
  632. }
  633. if($type=='video')
  634. {
  635. $tpl="<xml>
  636. <ToUserName><![CDATA[%s]]></ToUserName>
  637. <FromUserName><![CDATA[%s]]></FromUserName>
  638. <CreateTime>%s</CreateTime>
  639. <MsgType><![CDATA[%s]]></MsgType>
  640. <Video>
  641. <MediaId><![CDATA[%s]]></MediaId>
  642. <Title><![CDATA[%s]]></Title>
  643. <Description><![CDATA[%s]]></Description>
  644. </Video>
  645. </xml>";
  646. $resultStr = sprintf($tpl, $fromUsername, $toUsername, $time, $type, $media_id,$title,$description);
  647. }
  648. if($type=='news')
  649. {
  650. $tpl="<xml>
  651. <ToUserName><![CDATA[%s]]></ToUserName>
  652. <FromUserName><![CDATA[%s]]></FromUserName>
  653. <CreateTime>%s</CreateTime>
  654. <MsgType><![CDATA[%s]]></MsgType>
  655. <ArticleCount>%s</ArticleCount>";
  656. $tpl.="<Articles>";
  657. if(!empty($articles))foreach($articles as $article){
  658. $tpl.="<item>
  659. <Title><![CDATA[".$article['title']."]]></Title>
  660. <Description><![CDATA[".$article['description']."]]></Description>
  661. <PicUrl><![CDATA[".$article['picurl']."]]></PicUrl>
  662. <Url><![CDATA[".$article['url']."]]></Url>
  663. </item>";
  664. }
  665. $tpl.="</Articles>";
  666. $tpl.="</xml>";
  667. $resultStr = sprintf($tpl, $fromUsername, $toUsername, $time, $type, $count);
  668. }
  669. echo $resultStr;
  670. }else {
  671. echo "";
  672. exit;
  673. }
  674. }
  675. catch(\Exception $e)
  676. {
  677. $this->showError($e->getMessage());
  678. }
  679. }
  680. //解析接收到的用户信息
  681. public function receiveMsg()
  682. {
  683. try
  684. {
  685. //$postStr = $GLOBALS["HTTP_RAW_POST_DATA"];
  686. $postStr = file_get_contents("php://input");//支持PHP7
  687. file_put_contents(BASE_PATH.'components/WeiXin/test.txt',$postStr);
  688. if (!empty($postStr)){
  689. $msg = array();
  690. /* libxml_disable_entity_loader is to prevent XML eXternal Entity Injection,
  691. the best way is to check the validity of xml by yourself */
  692. libxml_disable_entity_loader(true);
  693. $postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
  694. //file_put_contents(BASE_PATH.'components/WeiXin/test.txt',$postObj->FromUserName);
  695. $fromUsername = $postObj->FromUserName;
  696. $this->getUserInfo($fromUsername);
  697. $this->currentOpenId = $fromUsername;
  698. $toUsername = $postObj->ToUserName;
  699. $msgType = $postObj->MsgType;
  700. $event = $postObj->Event;
  701. $msgID = $postObj->MsgID;
  702. $createTime = $postObj->CreateTime;
  703. if($msgType=='text')
  704. {
  705. $msg['content'] = $postObj->Content;
  706. }
  707. if($msgType=='image')
  708. {
  709. $msg['picUrl'] = $postObj->PicUrl;
  710. $msg['mediaId'] = $postObj->MediaId;
  711. }
  712. if($msgType=='voice')
  713. {
  714. $msg['format'] = $postObj->Format;
  715. $msg['mediaId'] = $postObj->MediaId;
  716. }
  717. if($msgType=='video')
  718. {
  719. $msg['thumbMediaId'] = $postObj->ThumbMediaId;
  720. $msg['mediaId'] = $postObj->MediaId;
  721. }
  722. if($msgType=='shortvideo')
  723. {
  724. $msg['thumbMediaId'] = $postObj->ThumbMediaId;
  725. $msg['mediaId'] = $postObj->MediaId;
  726. }
  727. if($msgType=='event')
  728. {
  729. if($postObj->TotalCount)//群发消息后,微信推送过来的
  730. {
  731. }
  732. if($event=='LOCATION')//上报地理位置
  733. {
  734. $msg['latitude'] = $postObj->Latitude;
  735. $msg['longitude'] = $postObj->Longitude;
  736. $msg['precision'] = $postObj->Precision;
  737. }
  738. if($event=='subscribe')//订阅
  739. {
  740. $postObj->EventKey&&$msg['eventKey'] = $postObj->EventKey;//未关注:事件KEY值,qrscene_为前缀,后面为二维码的参数值
  741. $postObj->Ticket&&$msg['ticket'] = $postObj->Ticket;//二维码的ticket,可用来换取二维码图片
  742. }
  743. if($event=='SCAN')//已关注,扫描二维码
  744. {
  745. $postObj->EventKey&&$msg['eventKey'] = $postObj->EventKey;//事件KEY值,是一个32位无符号整数,即创建二维码时的二维码scene_id
  746. $postObj->Ticket&&$msg['ticket'] = $postObj->Ticket;//二维码的ticket,可用来换取二维码图片
  747. }
  748. if($event=='unsubscribe'){}//取消订阅
  749. if($event=='click')//点击菜单
  750. {
  751. $postObj->EventKey&&$msg['eventKey'] = $postObj->EventKey;//与自定义菜单接口中KEY值对应
  752. }
  753. if($event=='VIEW')//菜单跳转
  754. {
  755. $postObj->EventKey&&$msg['eventKey'] = $postObj->EventKey;//EventKey 是一个连接地址
  756. }
  757. if($event=='scancode_push')//扫码推事件的事件推送
  758. {
  759. $msg['eventKey'] = $postObj->EventKey;//EventKey 是一个连接地址
  760. $msg['ScanType'] = $postObj->ScanCodeInfo->ScanType;
  761. $msg['ScanResult'] = $postObj->ScanCodeInfo->ScanResult;
  762. }
  763. if($event=='scancode_waitmsg')//扫码推事件且弹出“消息接收中”提示框的事件推送
  764. {
  765. $msg['eventKey'] = $postObj->EventKey;//EventKey 是一个连接地址
  766. $msg['ScanType'] = $postObj->ScanCodeInfo->ScanType;
  767. $msg['ScanResult'] = $postObj->ScanCodeInfo->ScanResult;
  768. }
  769. if($event=='pic_sysphoto')//弹出系统拍照发图的事件推送
  770. {
  771. $msg['eventKey'] = $postObj->EventKey;//EventKey 是一个连接地址
  772. $msg['Count'] = $postObj->SendPicsInfo->Count;
  773. $msg['PicList'] = $postObj->SendPicsInfo->PicList;
  774. }
  775. if($event=='pic_photo_or_album')//弹出拍照或者相册发图的事件推送
  776. {
  777. $msg['eventKey'] = $postObj->EventKey;//EventKey 是一个连接地址
  778. $msg['Count'] = $postObj->SendPicsInfo->Count;
  779. $msg['PicList'] = $postObj->SendPicsInfo->PicList;
  780. }
  781. if($event=='pic_weixin')//弹出微信相册发图器的事件推送
  782. {
  783. $msg['eventKey'] = $postObj->EventKey;//EventKey 是一个连接地址
  784. $msg['Count'] = $postObj->SendPicsInfo->Count;
  785. $msg['PicList'] = $postObj->SendPicsInfo->PicList;
  786. }
  787. if($event=='location_select')//弹出地理位置选择器的事件推送
  788. {
  789. $msg['eventKey'] = $postObj->EventKey;//EventKey 是一个连接地址
  790. $msg['Location_X'] = $postObj->SendLocationInfo->Location_X;
  791. $msg['Location_Y'] = $postObj->SendLocationInfo->Location_Y;
  792. $msg['Scale'] = $postObj->SendLocationInfo->Scale;
  793. $msg['Label'] = $postObj->SendLocationInfo->Label;
  794. $msg['Poiname'] = $postObj->SendLocationInfo->Poiname;
  795. }
  796. }
  797. if($msgType=='link')
  798. {
  799. $msg['title'] = $postObj->Title;
  800. $msg['description'] = $postObj->Description;
  801. $msg['url'] = $postObj->Url;
  802. }
  803. $msg['fromUsername']=$fromUsername;
  804. $msg['toUsername']=$toUsername;
  805. $msg['msgType']=$msgType;
  806. $msg['event']=$event;
  807. $msg['msgID']=$msgID;
  808. $msg['createTime']=$createTime;
  809. return $msg;
  810. }
  811. else
  812. {
  813. return array();
  814. }
  815. }
  816. catch(\Exception $e)
  817. {
  818. $this->showError($e->getMessage());
  819. }
  820. }
  821. //上传永久素材
  822. public function addMaterial($type,$filepath,$title='',$introduction='')
  823. {
  824. try
  825. {
  826. $this->getAccessToken();
  827. $ext = $this->fileext($filepath);
  828. $filesize = filesize($filepath);
  829. $voiceFatmat = array('mp3','wma','wav','amr');
  830. $voiceMaxSize = 5;//5mb
  831. $voiceTimeLenth = "60秒";
  832. $imageFatmat = array('bmp','png','jpeg','jpg','gif');
  833. $imageMaxSize = 2;//2MB
  834. $newsImageFatmat = array('jpg','png');
  835. $newsImageMaxSize = 1;//1MB
  836. if($type=='voice')
  837. {
  838. if(!in_array($ext,$voiceFatmat))$this->showErrorMessage('不支持该语音格式');
  839. if($filesize>$voiceMaxSize*1014*1024)$this->showErrorMessage('语音超出大小');
  840. }
  841. if($type=='image')
  842. {
  843. if(!in_array($ext,$imageFatmat))$this->showErrorMessage('不支持该图片格式');
  844. if($filesize>$imageMaxSize*1014*1024)$this->showErrorMessage('图片超出大小');
  845. }
  846. if($type=='video'||$type=='newsvideo')
  847. {
  848. $description='{"title":"'.$title.'","introduction":"'.$introduction.'"}';
  849. if(!empty($description))$data['description'] = $description;
  850. }
  851. if($type=='newsimage')//图文消息图片时候用到
  852. {
  853. if(!in_array($ext,$newsImageFatmat))$this->showErrorMessage('不支持该图片格式');
  854. if($filesize>$newsImageMaxSize*1014*1024)$this->showErrorMessage('图片超出大小');
  855. $this->addMaterialUrl = sprintf($this->uploadImgUrl,$this->accessToken);
  856. }
  857. else
  858. {
  859. $this->addMaterialUrl = sprintf($this->addMaterialUrl,$this->accessToken);
  860. }
  861. $data['media'] = new \CURLFile(realpath($filepath));
  862. $result = $this->httpsRequest($this->addMaterialUrl, $data);
  863. $result = json_decode($result,true);
  864. if($type=='newsvideo')//图文消息中的视频素材
  865. {
  866. $this->uploadNewsVideoUrl = sprintf($this->uploadNewsVideoUrl,$this->accessToken);
  867. $array = array('media_id'=>$result['media_id'],'title'=>$title,'description'=>$description);
  868. $result = $this->httpsRequest($this->uploadNewsVideoUrl, json_encode($array,JSON_UNESCAPED_UNICODE));
  869. $result = json_decode($result,true);
  870. }
  871. return $result;
  872. }
  873. catch(\Exception $e)
  874. {
  875. $this->showError($e->getMessage());
  876. }
  877. }
  878. //上传永久图文素材
  879. public function addNews($articles)
  880. {
  881. try
  882. {
  883. $this->getAccessToken();
  884. $this->addNewsUrl = sprintf($this->addNewsUrl,$this->accessToken);
  885. $result = $this->httpsRequest($this->addNewsUrl, json_encode($articles,JSON_UNESCAPED_UNICODE));
  886. $result = json_decode($result,true);
  887. return $result;
  888. }
  889. catch(\Exception $e)
  890. {
  891. $this->showError($e->getMessage());
  892. }
  893. }
  894. //修改图文素材 index:多图文时候的单篇图文索引
  895. public function updateNews($media_id,$data,$index=0)
  896. {
  897. try
  898. {
  899. $this->getAccessToken();
  900. $this->updateNewsUrl = sprintf($this->updateNewsUrl,$this->accessToken);
  901. $data['media_id'] = $media_id;
  902. $data['index'] = $index;
  903. $result = $this->httpsRequest($this->updateNewsUrl, json_encode($data,JSON_UNESCAPED_UNICODE));
  904. $result = json_decode($result,true);
  905. return $result;
  906. }
  907. catch(\Exception $e)
  908. {
  909. $this->showError($e->getMessage());
  910. }
  911. }
  912. //根据media_id 获取素材
  913. public function getMedia($media_id)
  914. {
  915. try
  916. {
  917. $this->getAccessToken();
  918. $this->getMediaUrl = sprintf($this->getMediaUrl,$this->accessToken);
  919. $result = json_decode($this->httpsRequest($this->getMediaUrl,json_encode(array('media_id'=>$media_id))),TRUE);
  920. return $result;
  921. }
  922. catch(\Exception $e)
  923. {
  924. $this->showError($e->getMessage());
  925. }
  926. }
  927. //删除素材
  928. public function delMedia($media_id)
  929. {
  930. try
  931. {
  932. $this->getAccessToken();
  933. $this->delMediaUrl = sprintf($this->delMediaUrl,$this->accessToken);
  934. $result = json_decode($this->httpsRequest($this->delMediaUrl,json_encode(array('media_id'=>$media_id))),TRUE);
  935. return $result;
  936. }
  937. catch(\Exception $e)
  938. {
  939. $this->showError($e->getMessage());
  940. }
  941. }
  942. //获取接口凭据 $type:1 文件存储 2 数据库存储
  943. public function getAccessToken($type=1)
  944. {
  945. try
  946. {
  947. if(file_exists($this->acessTokenFile))
  948. {
  949. $data = json_decode(file_get_contents($this->acessTokenFile));
  950. if($data->expire_time<TIMESTAMP)//超时
  951. {
  952. $refresh = true;
  953. }
  954. else
  955. {
  956. $this->accessToken = $data->access_token;
  957. }
  958. }
  959. else
  960. {
  961. $refresh = true;
  962. }
  963. if($refresh)
  964. {
  965. $data = json_decode($this->httpGet($this->getAccessTokenUrl));
  966. $data->expire_time = TIMESTAMP+3600;
  967. file_put_contents($this->acessTokenFile,json_encode($data));
  968. $this->accessToken = $data->access_token;
  969. }
  970. }
  971. catch(\Exception $e)
  972. {
  973. $this->showError($e->getMessage());
  974. }
  975. }
  976. //获取js api ticket type 1:文件 2:数据库
  977. public function getJsApiTicket($type=1,$url='')
  978. {
  979. try
  980. {
  981. if(file_exists($this->jsApiTicketFile))
  982. {
  983. $data = json_decode(file_get_contents($this->jsApiTicketFile));
  984. if($data->expire_time<TIMESTAMP)//超时
  985. {
  986. $refresh = true;
  987. }
  988. else
  989. {
  990. $ticket = $data->ticket;
  991. }
  992. }
  993. else
  994. {
  995. $refresh = true;
  996. }
  997. if($refresh)
  998. {
  999. $this->getAccessToken();
  1000. $this->getJsApiTicketUrl = sprintf($this->getJsApiTicketUrl,$this->accessToken);
  1001. $data = json_decode($this->httpGet($this->getJsApiTicketUrl));
  1002. $data->expire_time = TIMESTAMP+7000;
  1003. file_put_contents($this->jsApiTicketFile,json_encode($data));
  1004. $ticket = $data->ticket;
  1005. }
  1006. $timestamp = TIMESTAMP;
  1007. $noncestr = $this->createNonceStr();
  1008. if(empty($url))$url = $this->getUrl();
  1009. $string = "jsapi_ticket=".$ticket."&noncestr=".$noncestr."&timestamp=".$timestamp."&url=".$url;
  1010. $signature = sha1($string);
  1011. return array('appid'=>$this->appId,'ticket'=>$ticket,'noncestr'=>$noncestr,'timestamp'=>$timestamp,'url'=>$url,'signature'=>$signature);
  1012. }
  1013. catch(\Exception $e)
  1014. {
  1015. $this->showError($e->getMessage());
  1016. }
  1017. }
  1018. //获取微信服务器IP列表
  1019. public function getWeiXinIpList()
  1020. {
  1021. try
  1022. {
  1023. $this->getIpListUrl = sprintf($this->getIpListUrl,$this->accessToken);
  1024. $result = $this->httpGet($this->getIpListUrl);
  1025. $result = json_decode($result,TRUE);
  1026. $this->wxIpList = $result['ip_list'];
  1027. return $this->wxIpList;
  1028. }
  1029. catch(\Exception $e)
  1030. {
  1031. $this->showError($e->getMessage());
  1032. }
  1033. }
  1034. //获取素材总数
  1035. public function getMaterialCount()
  1036. {
  1037. try
  1038. {
  1039. $this->getAccessToken();
  1040. $this->getMaterialCountUrl = sprintf($this->getMaterialCountUrl,$this->accessToken);
  1041. return $result = json_decode($this->httpGet($this->getMaterialCountUrl),TRUE);
  1042. }
  1043. catch(\Exception $e)
  1044. {
  1045. $this->showError($e->getMessage());
  1046. }
  1047. }
  1048. //批量获取素材
  1049. public function batcheGetMaterial($type,$offset,$count)
  1050. {
  1051. try
  1052. {
  1053. $this->getAccessToken();
  1054. $this->batcheGetMaterialUrl = sprintf($this->batcheGetMaterialUrl,$this->accessToken);
  1055. $result = json_decode($this->httpsRequest($this->batcheGetMaterialUrl,json_encode(array('type'=>$type,'offset'=>$offset,'count'=>$count))),TRUE);
  1056. return $result;
  1057. }
  1058. catch(\Exception $e)
  1059. {
  1060. $this->showError($e->getMessage());
  1061. }
  1062. }
  1063. //发送模板消息
  1064. public function sendTemplateMsg($openid,$templateid,$data,$url=''){
  1065. /*
  1066. $data = array(
  1067. 'name'=>array('value'=>'Lucy','color'=>"#173177") ,
  1068. 'money'=>array('value'=>'1000000','color'=>"#173177") ,
  1069. 'date'=>array('value'=>date('Y-m-d H:i:s'),'color'=>"#173177") ,
  1070. )
  1071. */
  1072. try
  1073. {
  1074. $this->getAccessToken();
  1075. $this->tplMsgUrl = sprintf($this->tplMsgUrl,$this->accessToken);
  1076. $arr = array(
  1077. 'touser'=>$openid ,
  1078. 'template_id'=>$templateid,
  1079. 'url'=>$url,
  1080. 'data'=>$data
  1081. ) ;
  1082. $result = json_decode($this->httpsRequest($this->tplMsgUrl,json_encode($arr)),TRUE);
  1083. return $result;
  1084. }
  1085. catch(\Exception $e)
  1086. {
  1087. $this->showError($e->getMessage());
  1088. }
  1089. }
  1090. // 发送红包
  1091. function sendRedPack($parameter)
  1092. {
  1093. $money = max($parameter['money'], 0.01);
  1094. $money = intval($money * 100);
  1095. $mch_billno = $this->mchId.date('YmdHis',$this->timestamp).$this->num_rand(4);
  1096. $ip = $parameter['ip'];
  1097. $openid = $parameter['openid'];
  1098. if (!$openid) {
  1099. $this->echo_json('openid获取失败');
  1100. }
  1101. $this->parameters = array();
  1102. $this->setParameter('nonce_str', $this->createNonceStr());
  1103. $this->setParameter('mch_billno', $mch_billno);
  1104. $this->setParameter('mch_id', $this->mchId);
  1105. $this->setParameter('wxappid', $this->appId);
  1106. $this->setParameter('nick_name', $parameter['nick_name']);
  1107. $this->setParameter('send_name', $parameter['send_name']);
  1108. $this->setParameter('re_openid', $openid);
  1109. $this->setParameter('total_amount', $money);
  1110. $this->setParameter('min_value', $money);
  1111. $this->setParameter('max_value', $money);
  1112. $this->setParameter('total_num', 1);
  1113. $this->setParameter('wishing', $parameter['wishing']);
  1114. $this->setParameter('client_ip', $ip);
  1115. $this->setParameter('act_name', $parameter['act_name']);
  1116. $this->setParameter('remark', $parameter['remark']);
  1117. $this->setParameter('sign', $this->getSign());
  1118. $xml = $this->arrayToXml($this->parameters);
  1119. $res = $this->wxHttpsRequestPem($this->redPackUrl, $xml);
  1120. $resObj = simplexml_load_string($res, 'SimpleXMLElement', LIBXML_NOCDATA);
  1121. if ($resObj->return_code != 'SUCCESS') {
  1122. return array('code'=>-1, 'msg'=>$resObj->return_msg);
  1123. }
  1124. if ($resObj->result_code != 'SUCCESS') {
  1125. return array('code'=>-1, 'msg'=>$resObj->err_code_des);
  1126. }
  1127. return array('code'=>1, 'order_no'=>$mch_billno, 'openid'=>$openid);
  1128. }
  1129. //验证签名
  1130. public function valid()
  1131. {
  1132. $echoStr = $_GET["echostr"];
  1133. if($this->checkSignature()){
  1134. echo $echoStr;
  1135. exit;
  1136. }
  1137. }
  1138. public function checkSignature()
  1139. {
  1140. if (empty($this->token)) {
  1141. $this->showError('错误token!');
  1142. }
  1143. $signature = $_GET["signature"];
  1144. $timestamp = $_GET["timestamp"];
  1145. $nonce = $_GET["nonce"];
  1146. $tmpArr = array($this->token, $timestamp, $nonce);
  1147. // use SORT_STRING rule
  1148. sort($tmpArr, SORT_STRING);
  1149. $tmpStr = implode( $tmpArr );
  1150. $tmpStr = sha1( $tmpStr );
  1151. if( $tmpStr == $signature ){
  1152. return true;
  1153. }else{
  1154. return false;
  1155. }
  1156. }
  1157. // 设置参数
  1158. public function setParameter($parameter, $parameterValue)
  1159. {
  1160. $this->parameters[trim($parameter)] = trim($parameterValue);
  1161. }
  1162. // 获取参数
  1163. public function getParameter($parameter)
  1164. {
  1165. return $this->parameters[$parameter];
  1166. }
  1167. /**
  1168. * 获取随机数
  1169. *
  1170. * @param int $length 长度
  1171. * @return string
  1172. */
  1173. function num_rand($length) {
  1174. mt_srand((double) microtime() * 1000000);
  1175. $randVal = mt_rand(1, 9);
  1176. for ($i = 1; $i < $length; $i++) {
  1177. $randVal .= mt_rand(0, 9);
  1178. }
  1179. return $randVal;
  1180. }
  1181. function echo_json_callback($results) { //ajax输出
  1182. if ($_GET['callback']=='') $_GET['callback']='wzcallback';
  1183. if (is_string($results)) $results=array('code'=>-1,'msg'=>$results);
  1184. header("Content-type: text/html; charset=utf-8");
  1185. header("Cache-Control: no-cache");
  1186. echo $_GET['callback']."(".json_encode($results).")";
  1187. exit;
  1188. }
  1189. function echo_json($arr=array(), $code = -1){
  1190. $arr = is_array($arr)?$arr:array("msg"=>$arr, 'code'=>$code);
  1191. header('Content-type: application/json');
  1192. echo json_encode($arr);exit;
  1193. }
  1194. //抛出异常
  1195. public function showError($msg)
  1196. {
  1197. throw new \Exception($msg);
  1198. }
  1199. //显示错误
  1200. public function showErrorMessage($msg)
  1201. {
  1202. echo $msg;
  1203. exit;
  1204. }
  1205. private function httpGet($url) {
  1206. $curl = curl_init();
  1207. curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
  1208. curl_setopt($curl, CURLOPT_TIMEOUT, 500);
  1209. curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
  1210. curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
  1211. curl_setopt($curl, CURLOPT_URL, $url);
  1212. $res = curl_exec($curl);
  1213. curl_close($curl);
  1214. return $res;
  1215. }
  1216. // POST请求
  1217. public function wxHttpsRequestPem($url, $vars, $second=30,$aHeader=array()){
  1218. $ch = curl_init();
  1219. //超时时间
  1220. curl_setopt($ch,CURLOPT_TIMEOUT,$second);
  1221. curl_setopt($ch,CURLOPT_RETURNTRANSFER, 1);
  1222. //这里设置代理,如果有的话
  1223. //curl_setopt($ch,CURLOPT_PROXY, '10.206.30.98');
  1224. //curl_setopt($ch,CURLOPT_PROXYPORT, 8080);
  1225. curl_setopt($ch,CURLOPT_URL,$url);
  1226. curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,false);
  1227. curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,false);
  1228. //以下两种方式需选择一种
  1229. //第一种方法,cert 与 key 分别属于两个.pem文件
  1230. //默认格式为PEM,可以注释
  1231. curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM');
  1232. curl_setopt($ch,CURLOPT_SSLCERT,$this->basePath.'cert/apiclient_cert.pem');
  1233. //默认格式为PEM,可以注释
  1234. curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM');
  1235. curl_setopt($ch,CURLOPT_SSLKEY,$this->basePath.'cert/apiclient_key.pem');
  1236. curl_setopt($ch,CURLOPT_CAINFO,'PEM');
  1237. curl_setopt($ch,CURLOPT_CAINFO,$this->basePath.'cert/rootca.pem');
  1238. //第二种方式,两个文件合成一个.pem文件
  1239. //curl_setopt($ch,CURLOPT_SSLCERT,getcwd().'/all.pem');
  1240. if( count($aHeader) >= 1 ){
  1241. curl_setopt($ch, CURLOPT_HTTPHEADER, $aHeader);
  1242. }
  1243. curl_setopt($ch,CURLOPT_POST, 1);
  1244. curl_setopt($ch,CURLOPT_POSTFIELDS,$vars);
  1245. $data = curl_exec($ch);
  1246. if($data){
  1247. curl_close($ch);
  1248. return $data;
  1249. }
  1250. else {
  1251. $error = curl_errno($ch);
  1252. echo "call faild, errorCode:$error\n";
  1253. curl_close($ch);
  1254. return false;
  1255. }
  1256. }
  1257. private function httpsRequest($url, $data = null)
  1258. {
  1259. $curl = curl_init();
  1260. curl_setopt($curl, CURLOPT_URL, $url);
  1261. curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
  1262. curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
  1263. if (!empty($data)){
  1264. curl_setopt($curl, CURLOPT_POST, 1);
  1265. curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
  1266. }
  1267. curl_setopt($curl, CURLOPT_TIMEOUT, 3000);
  1268. curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
  1269. $output = curl_exec($curl);
  1270. curl_close($curl);
  1271. return $output;
  1272. }
  1273. private function fileext($filepath)
  1274. {
  1275. return strtolower(trim(substr(strrchr($filepath, '.'), 1, 10)));
  1276. }
  1277. /*
  1278. * 获取当前页面完整URL地址
  1279. */
  1280. private function getUrl() {
  1281. $sys_protocal = isset($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == '443' ? 'https://' : 'http://';
  1282. $php_self = $_SERVER['PHP_SELF'] ? $this->safe_replace($_SERVER['PHP_SELF']) : $this->safe_replace($_SERVER['SCRIPT_NAME']);
  1283. $path_info = isset($_SERVER['PATH_INFO']) ? $this->safe_replace($_SERVER['PATH_INFO']) : '';
  1284. $relate_url = isset($_SERVER['REQUEST_URI']) ? $this->safe_replace($_SERVER['REQUEST_URI']) : $php_self.(isset($_SERVER['QUERY_STRING']) ? '?'.$this->safe_replace($_SERVER['QUERY_STRING']) : $path_info);
  1285. return $sys_protocal.(isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : '').$relate_url;
  1286. }
  1287. /*
  1288. * 安全过滤函数
  1289. * @parame $string
  1290. * @return string
  1291. */
  1292. function safe_replace($string)
  1293. {
  1294. $string = str_replace('%20','',$string);
  1295. $string = str_replace('%27','',$string);
  1296. $string = str_replace('%2527','',$string);
  1297. $string = str_replace('*','',$string);
  1298. $string = str_replace('"','&quot;',$string);
  1299. $string = str_replace("'",'',$string);
  1300. $string = str_replace('"','',$string);
  1301. $string = str_replace(';','',$string);
  1302. $string = str_replace('>','&gt;',$string);
  1303. $string = str_replace('<','&lt;',$string);
  1304. $string = str_replace('{','',$string);
  1305. $string = str_replace('}','',$string);
  1306. $string = str_replace('\\','',$string);
  1307. return $string;
  1308. }
  1309. // 生成随机字符串
  1310. public function createNonceStr($length = 16) {
  1311. $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
  1312. $str = "";
  1313. for ($i = 0; $i < $length; $i++) {
  1314. $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
  1315. }
  1316. return $str;
  1317. }
  1318. // 数组转XML
  1319. public function arrayToXml($arr)
  1320. {
  1321. $xml = "<xml>";
  1322. foreach ($arr as $key=>$val) {
  1323. $xml.="<".$key."><![CDATA[".$val."]]></".$key.">";
  1324. }
  1325. $xml.="</xml>";
  1326. return $xml;
  1327. }
  1328. // 获取签名
  1329. public function getSign($arr)
  1330. {
  1331. $arr = $arr ? $arr : $this->parameters;
  1332. // 参数按字典排序
  1333. unset($arr['sign']);
  1334. ksort($arr);
  1335. $str = '';
  1336. foreach ($arr as $key => $val) {
  1337. if ($val != null) {
  1338. //$key = $lower ? strtolower($key) : $key;
  1339. $str .= $key . '=' . $val . '&';
  1340. }
  1341. }
  1342. // 加上partnerKey, md5加密
  1343. $str .= 'key='.$this->partnerKey;
  1344. return strtoupper(md5($str));
  1345. }
  1346. }