showErrorMessage('缺少appid,或appsecret,或token!'); $this->appId = $appId; $this->appSecret = $appSecret; $this->token = $token; $this->timestamp = time(); !empty($jsDomain)&&$this->jsDomain = $jsDomain; $this->basePath = Yii::$app->params['wxPath']; dir_create($this->basePath); $this->acessTokenFile = $this->basePath.$this->appId.'_access_token.json';//文件存储$accessToken $this->jsApiTicketFile = $this->basePath.$this->appId.'_jsapi_ticket.json';//文件存储js api 凭据 } //初始化 public function init() { $this->getAccessTokenUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=".$this->appId."&secret=".$this->appSecret; $this->getIpListUrl = "https://api.weixin.qq.com/cgi-bin/getcallbackip?access_token=%s"; $this->getUserInfoUrl= "https://api.weixin.qq.com/cgi-bin/user/info?access_token=%s&openid=%s&lang=zh_CN"; $this->getJsApiTicketUrl = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=%s&type=jsapi"; $this->addMaterialUrl= "https://api.weixin.qq.com/cgi-bin/material/add_material?access_token=%s"; $this->addNewsUrl = "https://api.weixin.qq.com/cgi-bin/material/add_news?access_token=%s"; $this->uploadImgUrl = "https://api.weixin.qq.com/cgi-bin/media/uploadimg?access_token=%s"; $this->getMediaUrl = "https://api.weixin.qq.com/cgi-bin/material/get_material?access_token=%s"; $this->updateNewsUrl = "https://api.weixin.qq.com/cgi-bin/material/update_news?access_token=%s"; $this->delMediaUrl = "https://api.weixin.qq.com/cgi-bin/material/del_material?access_token=%s"; $this->getMaterialCountUrl = "https://api.weixin.qq.com/cgi-bin/material/get_materialcount?access_token=%s"; $this->batcheGetMaterialUrl = "https://api.weixin.qq.com/cgi-bin/material/batchget_material?access_token=%s"; $this->uploadNewsVideoUrl = "https://file.api.weixin.qq.com/cgi-bin/media/uploadvideo?access_token=%s"; $this->msgSendAllUrl = "https://api.weixin.qq.com/cgi-bin/message/mass/sendall?access_token=%s"; $this->msgSendUrl = "https://api.weixin.qq.com/cgi-bin/message/mass/send?access_token=%s"; $this->msgPreviewUrl = "https://api.weixin.qq.com/cgi-bin/message/mass/preview?access_token=%s"; $this->delMsgUrl = "https://api.weixin.qq.com/cgi-bin/message/mass/delete?access_token=%s"; $this->getMsgStatusUrl = "https://api.weixin.qq.com/cgi-bin/message/mass/get?access_token=%s"; $this->createGroupUrl = "https://api.weixin.qq.com/cgi-bin/groups/create?access_token=%s"; $this->getGroupsUrl = "https://api.weixin.qq.com/cgi-bin/groups/get?access_token=%s"; $this->getGroupIdByOpenIdUrl = "https://api.weixin.qq.com/cgi-bin/groups/getid?access_token=%s"; $this->updateGroupNameUrl = "https://api.weixin.qq.com/cgi-bin/groups/update?access_token=%s"; $this->changeUserGroupUrl = "https://api.weixin.qq.com/cgi-bin/groups/members/update?access_token=%s"; $this->batchChangeUserGroupUrl = "https://api.weixin.qq.com/cgi-bin/groups/members/batchupdate?access_token=%s"; $this->delGroupUrl = "https://api.weixin.qq.com/cgi-bin/groups/delete?access_token=%s"; $this->updateRemarkUrl = "https://api.weixin.qq.com/cgi-bin/user/info/updateremark?access_token=%s"; $this->batchGetUserInfoUrl = "https://api.weixin.qq.com/cgi-bin/user/info/batchget?access_token=%s"; $this->getUserListUrl = "https://api.weixin.qq.com/cgi-bin/user/get?access_token=%s&next_openid=%s"; $this->getWebAuthCodeUrl = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=%s&state=%s#wechat_redirect"; $this->getWebAuthAccessTokenUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code"; $this->getWebAuthUserInfoUrl = "https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s&lang=zh_CN"; $this->createMenuUrl = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=%s"; $this->getMenuListUrl = "https://api.weixin.qq.com/cgi-bin/menu/get?access_token=%s"; $this->deleteMenuUrl = "https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=%s"; $this->createQrcodeUrl = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=%s"; $this->getQrcodeUrl = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=%s"; $this->getShortUrl = "https://api.weixin.qq.com/cgi-bin/shorturl?access_token=%s"; $this->addOrderUrl = 'https://api.mch.weixin.qq.com/pay/unifiedorder'; $this->qryOrderUrl = 'https://api.mch.weixin.qq.com/pay/orderquery'; $this->redPackUrl = 'https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack'; $this->tplMsgUrl = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=%s"; $this->customerMsgUrl = "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=%s"; return $this; } //获取短链接 public function createShortUrl($longUrl) { $this->getAccessToken(); $this->getShortUrl = sprintf($this->getShortUrl,$this->accessToken); $postdata = json_encode(array('action'=>'long2short','long_url'=>$longUrl),JSON_UNESCAPED_UNICODE); $result = $this->httpsRequest($this->getShortUrl, $postdata); $result = json_decode($result,true); return $result; } //创建二维码 $type 1:永久,2:临时 public function createQrcode($sceneId,$type=1,$expireSeconds=604800) { $this->getAccessToken(); $this->createQrcodeUrl = sprintf($this->createQrcodeUrl,$this->accessToken); if($type==1) { $postdata = '{"action_name": "QR_LIMIT_SCENE", "action_info": {"scene": {"scene_id": '.$sceneId.'}}}'; } if($type==2) { $postdata = '{"expire_seconds": '.$expireSeconds.', "action_name": "QR_SCENE", "action_info": {"scene": {"scene_id": '.$sceneId.'}}}'; } if($type==3) { $postdata = '{"expire_seconds": '.$expireSeconds.', "action_name": "QR_STR_SCENE", "action_info": {"scene": {"scene_str": "'.$sceneId.'"}}}'; } $result = $this->httpsRequest($this->createQrcodeUrl, $postdata); $result = json_decode($result,true); $result['codeUrl'] = sprintf($this->getQrcodeUrl,urlencode($result['ticket'])); return $result; } //删除自定义菜单 public function deleteMenu() { $this->getAccessToken(); $this->deleteMenuUrl = sprintf($this->deleteMenuUrl,$this->accessToken); $result = json_decode($this->httpGet($this->deleteMenuUrl),true); return $result; } //创建自定义菜单 public function createMenu($buttons) { $this->getAccessToken(); $this->createMenuUrl = sprintf($this->createMenuUrl,$this->accessToken); $array['button'] = $buttons; $result = $this->httpsRequest($this->createMenuUrl, json_encode($array,JSON_UNESCAPED_UNICODE)); $result = json_decode($result,true); return $result; } //查询自定义菜单 public function getMenuList() { $this->getAccessToken(); $this->getMenuListUrl = sprintf($this->getMenuListUrl,$this->accessToken); $result = json_decode($this->httpGet($this->getMenuListUrl),true); return $result; } /* 第一步:用户同意授权,获取code * 获取网页授权地址$scope:nsapi_base (不弹出授权页面,直接跳转,只能获取用户openid), snsapi_userinfo (弹出授权页面,可通过openid拿到昵称、性别、所在地。并且,即使在未关注的情况下,只要用户授权,也能获取其信息) */ public function getWebAuthUrl($redirectUrl,$scope='snsapi_userinfo',$state='MR8888') { $this->getWebAuthCodeUrl = sprintf($this->getWebAuthCodeUrl,$this->appId,$redirectUrl,$scope,$state); return $this->getWebAuthCodeUrl; } //第二步:通过code换取网页授权access_token public function getWebAuthAccessToken() { try { $this->getWebAuthAccessTokenUrl = sprintf($this->getWebAuthAccessTokenUrl,$this->appId,$this->appSecret,$_GET['code']); $data = json_decode($this->httpGet($this->getWebAuthAccessTokenUrl),true); $this->webAuthAccessToken = $data['access_token']; $this->currentOpenId = $data['openid']; } catch(\Exception $e) { $this->showError($e->getMessage()); } } // 第二步:通过code换取网页授权access_token public function getOauthAccessToken($code) { $url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=".$this->appId."&secret=".$this->appSecret."&code=$code&grant_type=authorization_code"; return json_decode($this->httpGet($url),true); } //第三步:拉取用户信息(需scope为 snsapi_userinfo) public function getWebAuthUserInfo() { /*$result = $this->getOauthAccessToken($_GET['code']); $this->webAuthAccessToken = $result['access_token']; $this->currentOpenId = $result['openid'];*/ $this->getWebAuthAccessToken(); $this->getWebAuthUserInfoUrl = sprintf($this->getWebAuthUserInfoUrl,$this->webAuthAccessToken,$this->currentOpenId); $result = json_decode($this->httpGet($this->getWebAuthUserInfoUrl),true); $result['nick_name'] = $result['nickname']; $result['avatar'] = $result['headimgurl']; return $result; } //获取用户列表 public function getUserList($nextOpenId='') { try { $this->getAccessToken(); $this->getUserListUrl = sprintf($this->getUserListUrl,$this->accessToken,$nextOpenId); $result = json_decode($this->httpGet($this->getUserListUrl),true); return $result; } catch(\Exception $e) { $this->showError($e->getMessage()); } } //批量获取用户基本信息 public function batchGetUserInfo($userList) { try { $this->getAccessToken(); $this->batchGetUserInfoUrl = sprintf($this->batchGetUserInfoUrl,$this->accessToken); if(is_array($userList))foreach($userList as $openId) { $array['user_list'][] = array('openid'=>$openId,'lang'=>'zh-CN'); } $result = $this->httpsRequest($this->batchGetUserInfoUrl, json_encode($array,JSON_UNESCAPED_UNICODE)); $result = json_decode($result,true); return $result; } catch(\Exception $e) { $this->showError($e->getMessage()); } } //修改用户备注 public function updateRemark($openId,$remark) { try { $this->getAccessToken(); $this->updateRemarkUrl = sprintf($this->updateRemarkUrl,$this->accessToken); $array = array('openid'=>$openId,'remark'=>$remark); $result = $this->httpsRequest($this->updateRemarkUrl, json_encode($array,JSON_UNESCAPED_UNICODE)); $result = json_decode($result,true); return $result; } catch(\Exception $e) { $this->showError($e->getMessage()); } } //创建分组 public function createGroup($groupName) { try { $this->getAccessToken(); $this->createGroupUrl = sprintf($this->createGroupUrl,$this->accessToken); $array['group'] = array('name'=>$groupName); $result = $this->httpsRequest($this->createGroupUrl, json_encode($array,JSON_UNESCAPED_UNICODE)); $result = json_decode($result,true); return $result; } catch(\Exception $e) { $this->showError($e->getMessage()); } } //查询所有分组信息 public function getGroups() { try { $this->getAccessToken(); $this->getGroupsUrl = sprintf($this->getGroupsUrl,$this->accessToken); $result = $this->httpGet($this->getGroupsUrl); $result = json_decode($result,true); return $result; } catch(\Exception $e) { $this->showError($e->getMessage()); } } //查询用户所在分组 public function getGroupId($openId) { try { $this->getAccessToken(); $this->getGroupIdByOpenIdUrl = sprintf($this->getGroupIdByOpenIdUrl,$this->accessToken); $array['openid'] = $openId; $result = $this->httpsRequest($this->getGroupIdByOpenIdUrl, json_encode($array,JSON_UNESCAPED_UNICODE)); $result = json_decode($result,true); return $result; } catch(\Exception $e) { $this->showError($e->getMessage()); } } //修改用户分组名称 public function updateGroupName($groupId,$groupName) { try { $this->getAccessToken(); $this->updateGroupNameUrl = sprintf($this->updateGroupNameUrl,$this->accessToken); $array['group'] = array('id'=>$groupId,'name'=>$groupName); $result = $this->httpsRequest($this->updateGroupNameUrl, json_encode($array,JSON_UNESCAPED_UNICODE)); $result = json_decode($result,true); return $result; } catch(\Exception $e) { $this->showError($e->getMessage()); } } //修改用户所在分组,支持批量转移 public function changUserGroup($openId,$toGroupId) { try { $this->getAccessToken(); if(is_array($openId)) { $requestUrl = sprintf($this->batchChangeUserGroupUrl,$this->accessToken); $array= array('openid_list'=>$openId,'to_groupid'=>$toGroupId); } else { $requestUrl = sprintf($this->changeUserGroupUrl,$this->accessToken); $array= array('openid'=>$openId,'to_groupid'=>$toGroupId); } $result = $this->httpsRequest($requestUrl, json_encode($array,JSON_UNESCAPED_UNICODE)); $result = json_decode($result,true); return $result; } catch(\Exception $e) { $this->showError($e->getMessage()); } } //删除分组 public function deleteGroup($groupId) { try { $this->getAccessToken(); $this->delGroupUrl = sprintf($this->delGroupUrl,$this->accessToken); $array['group'] = array('id'=>$groupId); $result = $this->httpsRequest($this->delGroupUrl, json_encode($array,JSON_UNESCAPED_UNICODE)); $result = json_decode($result,true); return $result; } catch(Exception $e) { $this->showError($e->getMessage()); } } //根据openid 获取用户基本信息 public function getUserInfo($open_id) { try { $this->getAccessToken(); $this->getUserInfoUrl = sprintf($this->getUserInfoUrl,$this->accessToken,$open_id); $result = json_decode($this->httpGet($this->getUserInfoUrl),TRUE); return $result; } catch(\Exception $e) { $this->showError($e->getMessage()); } } //群发消息 public function msgSend($contentInfo) { try { $this->getAccessToken(); $msg =array(); $sendUrl = sprintf($this->msgSendAllUrl,$this->accessToken); extract($contentInfo); if(is_numeric($groupId)) { $msg['filter'] = array('is_to_all'=>false,'group_id'=>$groupId); } if(!empty($openIds)&&is_array($openIds)) { $msg['touser'] = $openIds; $sendUrl = sprintf($this->msgSendUrl,$this->accessToken); } $msg['msgtype'] = $msgtype; if($msgtype=='mpnews')//群发图文 { $msg['mpnews'] = array('media_id'=>$media_id); } if($msgtype=='text')//群发文本 { $msg['text'] = array('content'=>$content); } if($msgtype=='voice')//群发语音 { $msg['voice'] = array('media_id'=>$media_id); } if($msgtype=='image')//群发图片 { $msg['image'] = array('media_id'=>$media_id); } if($msgtype=='mpvideo')//群发视频 { $msg['mpvideo'] = array('media_id'=>$media_id); } if($msgtype=='wxcard')//卡券消息 { $msg['wxcard'] = array('card_id'=>$card_id); } $result = $this->httpsRequest($sendUrl, json_encode($msg,JSON_UNESCAPED_UNICODE)); $result = json_decode($result,true); return $result; } catch(\Exception $e) { $this->showError($e->getMessage()); } } //消息预览 $contentInfo: public function msgPreview($contentInfo) { try { $this->getAccessToken(); $msg =array(); $this->msgPreviewUrl = sprintf($this->msgPreviewUrl,$this->accessToken); extract($contentInfo); if(!empty($towxname)) $msg['towxname'] = $towxname; if(!empty($touser)) $msg['touser'] = $touser; $msg['msgtype'] = $msgtype; if($msgtype=='mpnews')//群发图文 { $msg['mpnews'] = array('media_id'=>$media_id); } if($msgtype=='text')//群发文本 { $msg['text'] = array('content'=>$content); } if($msgtype=='voice')//群发语音 { $msg['voice'] = array('media_id'=>$media_id); } if($msgtype=='image')//群发图片 { $msg['image'] = array('media_id'=>$media_id); } if($msgtype=='mpvideo')//群发视频 { $msg['mpvideo'] = array('media_id'=>$media_id); } if($msgtype=='wxcard')//卡券消息 { $msg['wxcard'] = array('card_id'=>$card_id,'card_ext'=>$card_ext); } $result = $this->httpsRequest($this->msgPreviewUrl, json_encode($msg,JSON_UNESCAPED_UNICODE)); $result = json_decode($result,true); return $result; } catch(\Exception $e) { $this->showError($e->getMessage()); } } //删除群发消息 public function delMsg($msgId) { $this->getAccessToken(); $this->delMsgUrl = sprintf($this->delMsgUrl,$this->accessToken); $array = array('msg_id'=>$msgId); $result = $this->httpsRequest($this->delMsgUrl, json_encode($array,JSON_UNESCAPED_UNICODE)); $result = json_decode($result,true); return $result; } //获取群发消息状态 public function msgStatus($msgId) { $this->getAccessToken(); $this->getMsgStatusUrl = sprintf($this->getMsgStatusUrl,$this->accessToken); $array = array('msg_id'=>$msgId); $result = $this->httpsRequest($this->getMsgStatusUrl, json_encode($array,JSON_UNESCAPED_UNICODE)); $result = json_decode($result,true); return $result; } //客服消息 public function sendCustomermsg($type,$openid,$data) { $this->getAccessToken(); $this->customerMsgUrl = sprintf($this->customerMsgUrl,$this->accessToken); if($type=='text') { $msgcontent = '{ "touser" : "'.$openid.'", "msgtype" : "text", "text" : { "content" : "'.$data['content'].'" } }'; } if($type=='image'||$type=='voice'||$type=='mpnews') { $msgcontent = '{ "touser" : "'.$openid.'", "msgtype" : "'.$type.'", "'.$type.'" : { "media_id" : "'.$data['media_id'].'" } }'; } if($type=='news') { $msgcontent = '{"touser":"'.$openid.'", "msgtype":"news", "news":{ "articles": [ { "title":"'.$data['title'].'", "description":"'.$data['description'].'", "url":"'.$data['url'].'", "picurl":"'.getFileUrl($data['picurl']).'" } ] } }'; } if($type=='video') { $msgcontent = '{ "touser":"'.$openid.'", "msgtype":"video", "video": { "media_id":"'.$data['media_id'].'", "thumb_media_id":"'.$data['thumb_media_id'].'", "title":"'.$data['title'].'", "description":"'.$data['description'].'", } }'; } $result = $this->httpsRequest($this->customerMsgUrl, $msgcontent); $result = json_decode($result,true); return $result; } //自动回复消息 public function responseMsg($array,$articles=array()) { try { $receive = $this->receiveMsg(); if (!empty($receive)){ $fromUsername = $receive['fromUsername']; $toUsername = $receive['toUsername']; $time = TIMESTAMP; extract($array); if($type=='text') { $tpl = " %s 0 "; $resultStr = sprintf($tpl, $fromUsername, $toUsername, $time, $type, $content); } if($type=='image') { $tpl=" %s "; $resultStr = sprintf($tpl, $fromUsername, $toUsername, $time, $type, $media_id); } if($type=='voice') { $tpl = " %s "; $resultStr = sprintf($tpl, $fromUsername, $toUsername, $time, $type, $media_id); } if($type=='video') { $tpl=" %s "; $resultStr = sprintf($tpl, $fromUsername, $toUsername, $time, $type, $media_id,$title,$description); } if($type=='news') { $tpl=" %s %s"; $tpl.=""; if(!empty($articles))foreach($articles as $article){ $tpl.=" <![CDATA[".$article['title']."]]> "; } $tpl.=""; $tpl.=""; $resultStr = sprintf($tpl, $fromUsername, $toUsername, $time, $type, $count); } echo $resultStr; }else { echo ""; exit; } } catch(\Exception $e) { $this->showError($e->getMessage()); } } //解析接收到的用户信息 public function receiveMsg() { try { //$postStr = $GLOBALS["HTTP_RAW_POST_DATA"]; $postStr = file_get_contents("php://input");//支持PHP7 file_put_contents(BASE_PATH.'components/WeiXin/test.txt',$postStr); if (!empty($postStr)){ $msg = array(); /* libxml_disable_entity_loader is to prevent XML eXternal Entity Injection, the best way is to check the validity of xml by yourself */ libxml_disable_entity_loader(true); $postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA); //file_put_contents(BASE_PATH.'components/WeiXin/test.txt',$postObj->FromUserName); $fromUsername = $postObj->FromUserName; $this->getUserInfo($fromUsername); $this->currentOpenId = $fromUsername; $toUsername = $postObj->ToUserName; $msgType = $postObj->MsgType; $event = $postObj->Event; $msgID = $postObj->MsgID; $createTime = $postObj->CreateTime; if($msgType=='text') { $msg['content'] = $postObj->Content; } if($msgType=='image') { $msg['picUrl'] = $postObj->PicUrl; $msg['mediaId'] = $postObj->MediaId; } if($msgType=='voice') { $msg['format'] = $postObj->Format; $msg['mediaId'] = $postObj->MediaId; } if($msgType=='video') { $msg['thumbMediaId'] = $postObj->ThumbMediaId; $msg['mediaId'] = $postObj->MediaId; } if($msgType=='shortvideo') { $msg['thumbMediaId'] = $postObj->ThumbMediaId; $msg['mediaId'] = $postObj->MediaId; } if($msgType=='event') { if($postObj->TotalCount)//群发消息后,微信推送过来的 { } if($event=='LOCATION')//上报地理位置 { $msg['latitude'] = $postObj->Latitude; $msg['longitude'] = $postObj->Longitude; $msg['precision'] = $postObj->Precision; } if($event=='subscribe')//订阅 { $postObj->EventKey&&$msg['eventKey'] = $postObj->EventKey;//未关注:事件KEY值,qrscene_为前缀,后面为二维码的参数值 $postObj->Ticket&&$msg['ticket'] = $postObj->Ticket;//二维码的ticket,可用来换取二维码图片 } if($event=='SCAN')//已关注,扫描二维码 { $postObj->EventKey&&$msg['eventKey'] = $postObj->EventKey;//事件KEY值,是一个32位无符号整数,即创建二维码时的二维码scene_id $postObj->Ticket&&$msg['ticket'] = $postObj->Ticket;//二维码的ticket,可用来换取二维码图片 } if($event=='unsubscribe'){}//取消订阅 if($event=='click')//点击菜单 { $postObj->EventKey&&$msg['eventKey'] = $postObj->EventKey;//与自定义菜单接口中KEY值对应 } if($event=='VIEW')//菜单跳转 { $postObj->EventKey&&$msg['eventKey'] = $postObj->EventKey;//EventKey 是一个连接地址 } if($event=='scancode_push')//扫码推事件的事件推送 { $msg['eventKey'] = $postObj->EventKey;//EventKey 是一个连接地址 $msg['ScanType'] = $postObj->ScanCodeInfo->ScanType; $msg['ScanResult'] = $postObj->ScanCodeInfo->ScanResult; } if($event=='scancode_waitmsg')//扫码推事件且弹出“消息接收中”提示框的事件推送 { $msg['eventKey'] = $postObj->EventKey;//EventKey 是一个连接地址 $msg['ScanType'] = $postObj->ScanCodeInfo->ScanType; $msg['ScanResult'] = $postObj->ScanCodeInfo->ScanResult; } if($event=='pic_sysphoto')//弹出系统拍照发图的事件推送 { $msg['eventKey'] = $postObj->EventKey;//EventKey 是一个连接地址 $msg['Count'] = $postObj->SendPicsInfo->Count; $msg['PicList'] = $postObj->SendPicsInfo->PicList; } if($event=='pic_photo_or_album')//弹出拍照或者相册发图的事件推送 { $msg['eventKey'] = $postObj->EventKey;//EventKey 是一个连接地址 $msg['Count'] = $postObj->SendPicsInfo->Count; $msg['PicList'] = $postObj->SendPicsInfo->PicList; } if($event=='pic_weixin')//弹出微信相册发图器的事件推送 { $msg['eventKey'] = $postObj->EventKey;//EventKey 是一个连接地址 $msg['Count'] = $postObj->SendPicsInfo->Count; $msg['PicList'] = $postObj->SendPicsInfo->PicList; } if($event=='location_select')//弹出地理位置选择器的事件推送 { $msg['eventKey'] = $postObj->EventKey;//EventKey 是一个连接地址 $msg['Location_X'] = $postObj->SendLocationInfo->Location_X; $msg['Location_Y'] = $postObj->SendLocationInfo->Location_Y; $msg['Scale'] = $postObj->SendLocationInfo->Scale; $msg['Label'] = $postObj->SendLocationInfo->Label; $msg['Poiname'] = $postObj->SendLocationInfo->Poiname; } } if($msgType=='link') { $msg['title'] = $postObj->Title; $msg['description'] = $postObj->Description; $msg['url'] = $postObj->Url; } $msg['fromUsername']=$fromUsername; $msg['toUsername']=$toUsername; $msg['msgType']=$msgType; $msg['event']=$event; $msg['msgID']=$msgID; $msg['createTime']=$createTime; return $msg; } else { return array(); } } catch(\Exception $e) { $this->showError($e->getMessage()); } } //上传永久素材 public function addMaterial($type,$filepath,$title='',$introduction='') { try { $this->getAccessToken(); $ext = $this->fileext($filepath); $filesize = filesize($filepath); $voiceFatmat = array('mp3','wma','wav','amr'); $voiceMaxSize = 5;//5mb $voiceTimeLenth = "60秒"; $imageFatmat = array('bmp','png','jpeg','jpg','gif'); $imageMaxSize = 2;//2MB $newsImageFatmat = array('jpg','png'); $newsImageMaxSize = 1;//1MB if($type=='voice') { if(!in_array($ext,$voiceFatmat))$this->showErrorMessage('不支持该语音格式'); if($filesize>$voiceMaxSize*1014*1024)$this->showErrorMessage('语音超出大小'); } if($type=='image') { if(!in_array($ext,$imageFatmat))$this->showErrorMessage('不支持该图片格式'); if($filesize>$imageMaxSize*1014*1024)$this->showErrorMessage('图片超出大小'); } if($type=='video'||$type=='newsvideo') { $description='{"title":"'.$title.'","introduction":"'.$introduction.'"}'; if(!empty($description))$data['description'] = $description; } if($type=='newsimage')//图文消息图片时候用到 { if(!in_array($ext,$newsImageFatmat))$this->showErrorMessage('不支持该图片格式'); if($filesize>$newsImageMaxSize*1014*1024)$this->showErrorMessage('图片超出大小'); $this->addMaterialUrl = sprintf($this->uploadImgUrl,$this->accessToken); } else { $this->addMaterialUrl = sprintf($this->addMaterialUrl,$this->accessToken); } $data['media'] = new \CURLFile(realpath($filepath)); $result = $this->httpsRequest($this->addMaterialUrl, $data); $result = json_decode($result,true); if($type=='newsvideo')//图文消息中的视频素材 { $this->uploadNewsVideoUrl = sprintf($this->uploadNewsVideoUrl,$this->accessToken); $array = array('media_id'=>$result['media_id'],'title'=>$title,'description'=>$description); $result = $this->httpsRequest($this->uploadNewsVideoUrl, json_encode($array,JSON_UNESCAPED_UNICODE)); $result = json_decode($result,true); } return $result; } catch(\Exception $e) { $this->showError($e->getMessage()); } } //上传永久图文素材 public function addNews($articles) { try { $this->getAccessToken(); $this->addNewsUrl = sprintf($this->addNewsUrl,$this->accessToken); $result = $this->httpsRequest($this->addNewsUrl, json_encode($articles,JSON_UNESCAPED_UNICODE)); $result = json_decode($result,true); return $result; } catch(\Exception $e) { $this->showError($e->getMessage()); } } //修改图文素材 index:多图文时候的单篇图文索引 public function updateNews($media_id,$data,$index=0) { try { $this->getAccessToken(); $this->updateNewsUrl = sprintf($this->updateNewsUrl,$this->accessToken); $data['media_id'] = $media_id; $data['index'] = $index; $result = $this->httpsRequest($this->updateNewsUrl, json_encode($data,JSON_UNESCAPED_UNICODE)); $result = json_decode($result,true); return $result; } catch(\Exception $e) { $this->showError($e->getMessage()); } } //根据media_id 获取素材 public function getMedia($media_id) { try { $this->getAccessToken(); $this->getMediaUrl = sprintf($this->getMediaUrl,$this->accessToken); $result = json_decode($this->httpsRequest($this->getMediaUrl,json_encode(array('media_id'=>$media_id))),TRUE); return $result; } catch(\Exception $e) { $this->showError($e->getMessage()); } } //删除素材 public function delMedia($media_id) { try { $this->getAccessToken(); $this->delMediaUrl = sprintf($this->delMediaUrl,$this->accessToken); $result = json_decode($this->httpsRequest($this->delMediaUrl,json_encode(array('media_id'=>$media_id))),TRUE); return $result; } catch(\Exception $e) { $this->showError($e->getMessage()); } } //获取接口凭据 $type:1 文件存储 2 数据库存储 public function getAccessToken($type=1) { try { if(file_exists($this->acessTokenFile)) { $data = json_decode(file_get_contents($this->acessTokenFile)); if($data->expire_timeaccessToken = $data->access_token; } } else { $refresh = true; } if($refresh) { $data = json_decode($this->httpGet($this->getAccessTokenUrl)); $data->expire_time = TIMESTAMP+3600; file_put_contents($this->acessTokenFile,json_encode($data)); $this->accessToken = $data->access_token; } } catch(\Exception $e) { $this->showError($e->getMessage()); } } //获取js api ticket type 1:文件 2:数据库 public function getJsApiTicket($type=1,$url='') { try { if(file_exists($this->jsApiTicketFile)) { $data = json_decode(file_get_contents($this->jsApiTicketFile)); if($data->expire_timeticket; } } else { $refresh = true; } if($refresh) { $this->getAccessToken(); $this->getJsApiTicketUrl = sprintf($this->getJsApiTicketUrl,$this->accessToken); $data = json_decode($this->httpGet($this->getJsApiTicketUrl)); $data->expire_time = TIMESTAMP+7000; file_put_contents($this->jsApiTicketFile,json_encode($data)); $ticket = $data->ticket; } $timestamp = TIMESTAMP; $noncestr = $this->createNonceStr(); if(empty($url))$url = $this->getUrl(); $string = "jsapi_ticket=".$ticket."&noncestr=".$noncestr."×tamp=".$timestamp."&url=".$url; $signature = sha1($string); return array('appid'=>$this->appId,'ticket'=>$ticket,'noncestr'=>$noncestr,'timestamp'=>$timestamp,'url'=>$url,'signature'=>$signature); } catch(\Exception $e) { $this->showError($e->getMessage()); } } //获取微信服务器IP列表 public function getWeiXinIpList() { try { $this->getIpListUrl = sprintf($this->getIpListUrl,$this->accessToken); $result = $this->httpGet($this->getIpListUrl); $result = json_decode($result,TRUE); $this->wxIpList = $result['ip_list']; return $this->wxIpList; } catch(\Exception $e) { $this->showError($e->getMessage()); } } //获取素材总数 public function getMaterialCount() { try { $this->getAccessToken(); $this->getMaterialCountUrl = sprintf($this->getMaterialCountUrl,$this->accessToken); return $result = json_decode($this->httpGet($this->getMaterialCountUrl),TRUE); } catch(\Exception $e) { $this->showError($e->getMessage()); } } //批量获取素材 public function batcheGetMaterial($type,$offset,$count) { try { $this->getAccessToken(); $this->batcheGetMaterialUrl = sprintf($this->batcheGetMaterialUrl,$this->accessToken); $result = json_decode($this->httpsRequest($this->batcheGetMaterialUrl,json_encode(array('type'=>$type,'offset'=>$offset,'count'=>$count))),TRUE); return $result; } catch(\Exception $e) { $this->showError($e->getMessage()); } } //发送模板消息 public function sendTemplateMsg($openid,$templateid,$data,$url=''){ /* $data = array( 'name'=>array('value'=>'Lucy','color'=>"#173177") , 'money'=>array('value'=>'1000000','color'=>"#173177") , 'date'=>array('value'=>date('Y-m-d H:i:s'),'color'=>"#173177") , ) */ try { $this->getAccessToken(); $this->tplMsgUrl = sprintf($this->tplMsgUrl,$this->accessToken); $arr = array( 'touser'=>$openid , 'template_id'=>$templateid, 'url'=>$url, 'data'=>$data ) ; $result = json_decode($this->httpsRequest($this->tplMsgUrl,json_encode($arr)),TRUE); return $result; } catch(\Exception $e) { $this->showError($e->getMessage()); } } // 发送红包 function sendRedPack($parameter) { $money = max($parameter['money'], 0.01); $money = intval($money * 100); $mch_billno = $this->mchId.date('YmdHis',$this->timestamp).$this->num_rand(4); $ip = $parameter['ip']; $openid = $parameter['openid']; if (!$openid) { $this->echo_json('openid获取失败'); } $this->parameters = array(); $this->setParameter('nonce_str', $this->createNonceStr()); $this->setParameter('mch_billno', $mch_billno); $this->setParameter('mch_id', $this->mchId); $this->setParameter('wxappid', $this->appId); $this->setParameter('nick_name', $parameter['nick_name']); $this->setParameter('send_name', $parameter['send_name']); $this->setParameter('re_openid', $openid); $this->setParameter('total_amount', $money); $this->setParameter('min_value', $money); $this->setParameter('max_value', $money); $this->setParameter('total_num', 1); $this->setParameter('wishing', $parameter['wishing']); $this->setParameter('client_ip', $ip); $this->setParameter('act_name', $parameter['act_name']); $this->setParameter('remark', $parameter['remark']); $this->setParameter('sign', $this->getSign()); $xml = $this->arrayToXml($this->parameters); $res = $this->wxHttpsRequestPem($this->redPackUrl, $xml); $resObj = simplexml_load_string($res, 'SimpleXMLElement', LIBXML_NOCDATA); if ($resObj->return_code != 'SUCCESS') { return array('code'=>-1, 'msg'=>$resObj->return_msg); } if ($resObj->result_code != 'SUCCESS') { return array('code'=>-1, 'msg'=>$resObj->err_code_des); } return array('code'=>1, 'order_no'=>$mch_billno, 'openid'=>$openid); } //验证签名 public function valid() { $echoStr = $_GET["echostr"]; if($this->checkSignature()){ echo $echoStr; exit; } } public function checkSignature() { if (empty($this->token)) { $this->showError('错误token!'); } $signature = $_GET["signature"]; $timestamp = $_GET["timestamp"]; $nonce = $_GET["nonce"]; $tmpArr = array($this->token, $timestamp, $nonce); // use SORT_STRING rule sort($tmpArr, SORT_STRING); $tmpStr = implode( $tmpArr ); $tmpStr = sha1( $tmpStr ); if( $tmpStr == $signature ){ return true; }else{ return false; } } // 设置参数 public function setParameter($parameter, $parameterValue) { $this->parameters[trim($parameter)] = trim($parameterValue); } // 获取参数 public function getParameter($parameter) { return $this->parameters[$parameter]; } /** * 获取随机数 * * @param int $length 长度 * @return string */ function num_rand($length) { mt_srand((double) microtime() * 1000000); $randVal = mt_rand(1, 9); for ($i = 1; $i < $length; $i++) { $randVal .= mt_rand(0, 9); } return $randVal; } function echo_json_callback($results) { //ajax输出 if ($_GET['callback']=='') $_GET['callback']='wzcallback'; if (is_string($results)) $results=array('code'=>-1,'msg'=>$results); header("Content-type: text/html; charset=utf-8"); header("Cache-Control: no-cache"); echo $_GET['callback']."(".json_encode($results).")"; exit; } function echo_json($arr=array(), $code = -1){ $arr = is_array($arr)?$arr:array("msg"=>$arr, 'code'=>$code); header('Content-type: application/json'); echo json_encode($arr);exit; } //抛出异常 public function showError($msg) { throw new \Exception($msg); } //显示错误 public function showErrorMessage($msg) { echo $msg; exit; } private function httpGet($url) { $curl = curl_init(); curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); curl_setopt($curl, CURLOPT_TIMEOUT, 500); curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false); curl_setopt($curl, CURLOPT_URL, $url); $res = curl_exec($curl); curl_close($curl); return $res; } // POST请求 public function wxHttpsRequestPem($url, $vars, $second=30,$aHeader=array()){ $ch = curl_init(); //超时时间 curl_setopt($ch,CURLOPT_TIMEOUT,$second); curl_setopt($ch,CURLOPT_RETURNTRANSFER, 1); //这里设置代理,如果有的话 //curl_setopt($ch,CURLOPT_PROXY, '10.206.30.98'); //curl_setopt($ch,CURLOPT_PROXYPORT, 8080); curl_setopt($ch,CURLOPT_URL,$url); curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,false); curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,false); //以下两种方式需选择一种 //第一种方法,cert 与 key 分别属于两个.pem文件 //默认格式为PEM,可以注释 curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM'); curl_setopt($ch,CURLOPT_SSLCERT,$this->basePath.'cert/apiclient_cert.pem'); //默认格式为PEM,可以注释 curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM'); curl_setopt($ch,CURLOPT_SSLKEY,$this->basePath.'cert/apiclient_key.pem'); curl_setopt($ch,CURLOPT_CAINFO,'PEM'); curl_setopt($ch,CURLOPT_CAINFO,$this->basePath.'cert/rootca.pem'); //第二种方式,两个文件合成一个.pem文件 //curl_setopt($ch,CURLOPT_SSLCERT,getcwd().'/all.pem'); if( count($aHeader) >= 1 ){ curl_setopt($ch, CURLOPT_HTTPHEADER, $aHeader); } curl_setopt($ch,CURLOPT_POST, 1); curl_setopt($ch,CURLOPT_POSTFIELDS,$vars); $data = curl_exec($ch); if($data){ curl_close($ch); return $data; } else { $error = curl_errno($ch); echo "call faild, errorCode:$error\n"; curl_close($ch); return false; } } private function httpsRequest($url, $data = null) { $curl = curl_init(); curl_setopt($curl, CURLOPT_URL, $url); curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE); curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE); if (!empty($data)){ curl_setopt($curl, CURLOPT_POST, 1); curl_setopt($curl, CURLOPT_POSTFIELDS, $data); } curl_setopt($curl, CURLOPT_TIMEOUT, 3000); curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); $output = curl_exec($curl); curl_close($curl); return $output; } private function fileext($filepath) { return strtolower(trim(substr(strrchr($filepath, '.'), 1, 10))); } /* * 获取当前页面完整URL地址 */ private function getUrl() { $sys_protocal = isset($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == '443' ? 'https://' : 'http://'; $php_self = $_SERVER['PHP_SELF'] ? $this->safe_replace($_SERVER['PHP_SELF']) : $this->safe_replace($_SERVER['SCRIPT_NAME']); $path_info = isset($_SERVER['PATH_INFO']) ? $this->safe_replace($_SERVER['PATH_INFO']) : ''; $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); return $sys_protocal.(isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : '').$relate_url; } /* * 安全过滤函数 * @parame $string * @return string */ function safe_replace($string) { $string = str_replace('%20','',$string); $string = str_replace('%27','',$string); $string = str_replace('%2527','',$string); $string = str_replace('*','',$string); $string = str_replace('"','"',$string); $string = str_replace("'",'',$string); $string = str_replace('"','',$string); $string = str_replace(';','',$string); $string = str_replace('>','>',$string); $string = str_replace('<','<',$string); $string = str_replace('{','',$string); $string = str_replace('}','',$string); $string = str_replace('\\','',$string); return $string; } // 生成随机字符串 public function createNonceStr($length = 16) { $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; $str = ""; for ($i = 0; $i < $length; $i++) { $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1); } return $str; } // 数组转XML public function arrayToXml($arr) { $xml = ""; foreach ($arr as $key=>$val) { $xml.="<".$key.">"; } $xml.=""; return $xml; } // 获取签名 public function getSign($arr) { $arr = $arr ? $arr : $this->parameters; // 参数按字典排序 unset($arr['sign']); ksort($arr); $str = ''; foreach ($arr as $key => $val) { if ($val != null) { //$key = $lower ? strtolower($key) : $key; $str .= $key . '=' . $val . '&'; } } // 加上partnerKey, md5加密 $str .= 'key='.$this->partnerKey; return strtoupper(md5($str)); } }