eaglephp使用微信api接口开发微信框架


Posted in PHP onJanuary 09, 2014

适用平台:window/Linux
依赖项目:EaglePHP框架

包含微信5.0 API基础接口、自定义菜单、高级接口,具体如下:
1、接收用户消息。
2、向用户回复消息。
3、接受事件推送。
4、会话界面自定义菜单。
5、语音识别。
6、客服接口。
7、OAuth2.0网页授权。
8、生成带参数二维码。
9、获取用户地理位置。
10、获取用户基本信息。
11、获取关注者列表。
12、用户分组。

<?php
/**
 * 微信公众平台API
 */
class WeixinChat
{ private $token;
 private $appid;
 private $appsecret;
 private $access_token;
 // 接收的数据
 private $_receive = array();
 private $_reply = '';
 // 接口错误码
 private $errCode = '';
 // 接口错误信息
 private $errMsg = '';
 // 微信oauth登陆获取code
 const CONNECT_OAUTH_AUTHORIZE_URL = 'https://open.weixin.qq.com/connect/oauth2/authorize?';
 // 微信oauth登陆通过code换取网页授权access_token
 const SNS_OAUTH_ACCESS_TOKEN_URL = 'https://api.weixin.qq.com/sns/oauth2/access_token?';
 // 微信oauth登陆刷新access_token(如果需要)
 const SNS_OAUTH_REFRESH_TOKEN_URL = 'https://api.weixin.qq.com/sns/oauth2/refresh_token?';
 // 通过ticket换取二维码
 const SHOW_QRCODE_URL = 'https://mp.weixin.qq.com/cgi-bin/showqrcode?';
 // 微信oauth登陆拉取用户信息(需scope为 snsapi_userinfo)
 const SNS_USERINFO_URL = 'https://api.weixin.qq.com/sns/userinfo?';
 // 请求api前缀
 const API_URL_PREFIX = 'https://api.weixin.qq.com/cgi-bin';
 // 自定义菜单创建
 const MENU_CREATE_URL = '/menu/create?';
 // 自定义菜单查询
 const MENU_GET_URL = '/menu/get?';
 // 自定义菜单删除
 const MENU_DELETE_URL = '/menu/delete?';
 // 获取 access_token
 const AUTH_URL = '/token?grant_type=client_credential&';

 // 获取用户基本信息
 const USER_INFO_URL = '/user/info?';
 // 获取关注者列表
 const USER_GET_URL = '/user/get?';
 // 查询分组
 const GROUPS_GET_URL = '/groups/get?'; 
 // 创建分组
 const GROUPS_CREATE_URL = '/groups/create?';
 // 修改分组名
 const GROUPS_UPDATE_URL = '/groups/update?';
 // 移动用户分组
 const GROUPS_MEMBERS_UPDATE_URL = '/groups/members/update?';
 // 发送客服消息
 const MESSAGE_CUSTOM_SEND_URL = '/message/custom/send?';
 // 创建二维码ticket
 const QRCODE_CREATE_URL = '/qrcode/create?';
 
 /**
  * 初始化配置数据
  * @param array $options
  */
 public function __construct($options)
 {
  $this->token = isset($options['token']) ? $options['token'] : '';
  $this->appid = isset($options['appid']) ? $options['appid'] : '';
  $this->appsecret = isset($options['appsecret']) ? $options['appsecret'] : '';
 }
 
 /**
  * 获取发来的消息
  * 当普通微信用户向公众账号发消息时,微信服务器将POST消息的XML数据包到开发者填写的URL上。
  */
 public function getRev()
 {
  $postStr = file_get_contents('php://input');
  if($postStr)
  {
   $this->_receive = (array)simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
   //Log::info(var_export($this->_receive, true));
  }
  return $this;
 }
 
 /**
  * 获取微信服务器发来的消息
  */
 public function getRevData()
 {
  return $this->_receive;
 }
 
 /**
  * 获取接收者
  */
 public function getRevTo()
 {
  return isset($this->_receive['ToUserName']) ? $this->_receive['ToUserName'] : false;
 }
 
 /**
  * 获取消息发送者(一个OpenID)
  */
 public function getRevFrom()
 {
  return isset($this->_receive['FromUserName']) ? $this->_receive['FromUserName'] : false;
 }
 
 /**
  * 获取接收消息创建时间 (整型)
  */
 public function getRevCTime()
 {
  return isset($this->_receive['CreateTime']) ? $this->_receive['CreateTime'] : false;
 }
 
 /**
  * 获取接收消息类型(text、image、voice、video、location、link、event)
  */
 public function getRevType()
 {
  return isset($this->_receive['MsgType']) ? $this->_receive['MsgType'] : false;
 }
 
 /**
  * 获取接收消息编号
  */
 public function getRevId()
 {
  return isset($this->_receive['MsgId']) ? $this->_receive['MsgId'] : false;
 }
 
 /**
  * 获取接收消息文本
  * 通过语音识别接口,用户发送的语音,将会同时给出语音识别出的文本内容。(需申请服务号的高级接口权限)
  */
 public function getRevText()
 {
  if(isset($this->_receive['Content'])) return trim($this->_receive['Content']);
  elseif(isset($this->_receive['Recognition'])) return trim($this->_receive['Recognition']);
  else return false;
 }
 
 /**
  * 获取接收图片消息
  */
 public function getRevImage()
 {
  if(isset($this->_receive['PicUrl'])){
   return array(
        'picUrl' => $this->_receive['PicUrl'],  //图片链接
     'mediaId' => $this->_receive['MediaId'] //图片消息媒体id,可以调用多媒体文件下载接口拉取数据。
       );
  }
  return false;
 }
 
 /**
  * 获取接收语音消息
  */
 public function getRevVoice()
 {
  if(isset($this->_receive['MediaId'])){
   return array(
        'mediaId' => $this->_receive['MediaId'],  //语音消息媒体id,可以调用多媒体文件下载接口拉取数据。
     'format' => $this->_receive['Format'] //语音格式,如amr,speex等
       );
  }
  return false;
 }
 
 /**
  * 获取接收视频消息
  */
 public function getRevVideo()
 {
  if(isset($this->_receive['MediaId'])){
   return array(
        'mediaId' => $this->_receive['MediaId'],       //视频消息媒体id,可以调用多媒体文件下载接口拉取数据。
     'thumbMediaId' => $this->_receive['ThumbMediaId']  //视频消息缩略图的媒体id,可以调用多媒体文件下载接口拉取数据。
       );
  }
  return false;
 } 
 
 /**
  * 获取用户地理位置
  */
 public function getRevLocation()
 {
  if(isset($this->_receive['Location_X'])){
   return array(
        'locationX' => $this->_receive['Location_X'],  //地理位置维度
     'locationY' => $this->_receive['Location_Y'],  //地理位置经度
     'scale' => $this->_receive['Scale'], //地图缩放大小
     'label' => $this->_receive['Label'] //地理位置信息
       );
  }
  //开通了上报地理位置接口的公众号,用户在关注后进入公众号会话时,会弹框让用户确认是否允许公众号使用其地理位置。
  //弹框只在关注后出现一次,用户以后可以在公众号详情页面进行操作。
  elseif(isset($this->_receive['Latitude'])) 
  {
   return array(
        'latitude' => $this->_receive['Latitude'],  //地理位置纬度
     'longitude' => $this->_receive['Longitude'], //地理位置经度
      'precision' => $this->_receive['Precision'] // 地理位置精度
       );
  }
  return false;
 }
 
 /**
  * 获取接收链接消息
  */
 public function getRevLink()
 {
  if(isset($this->_receive['Title'])){
   return array(
        'title' => $this->_receive['Title'],  //消息标题
     'description' => $this->_receive['Description'],  //消息描述
     'url' => $this->_receive['Url'] //消息链接
       );
  }
  return false;
 }
 
 /**
  * 获取接收事件类型
  * 事件类型如:subscribe(订阅)、unsubscribe(取消订阅)、click
  */
 public function getRevEvent()
 {
  if(isset($this->_receive['Event']))
  {
   return array(
     'event' => strtolower($this->_receive['Event']), 
     'key'=> isset($this->_receive['EventKey']) ? $this->_receive['EventKey'] : ''
       );
  }
  return false;
 }
 
 /**
  * 设置回复文本消息
  * @param string $content
  * @param string $openid
  */
 public function text($content='')
 {
  $textTpl = "<xml>
      <ToUserName><![CDATA[%s]]></ToUserName>
      <FromUserName><![CDATA[%s]]></FromUserName>
      <CreateTime>%s</CreateTime>
      <MsgType><![CDATA[%s]]></MsgType>
      <Content><![CDATA[%s]]></Content>
     </xml>";
  $this->_reply = sprintf($textTpl, 
         $this->getRevFrom(),
         $this->getRevTo(), 
         Date::getTimeStamp(), 
         'text', 
         $content
        );
  return $this;
 }
 
 /**
  * 设置回复音乐信息
  * @param string $title
  * @param string $desc
  * @param string $musicurl
  * @param string $hgmusicurl
  */
 public function music($title, $desc, $musicurl, $hgmusicurl='')
 {
  $textTpl = '<xml>
      <ToUserName><![CDATA[%s]]></ToUserName>
      <FromUserName><![CDATA[%s]]></FromUserName>
      <CreateTime>%s</CreateTime>
      <MsgType><![CDATA[%s]]></MsgType>
      <Music>
       <Title><![CDATA[%s]]></Title>
       <Description><![CDATA[%s]]></Description>
       <MusicUrl><![CDATA[%s]]></MusicUrl>
       <HQMusicUrl><![CDATA[%s]]></HQMusicUrl>
      </Music>
     </xml>';
  //<ThumbMediaId><![CDATA[%s]]></ThumbMediaId>
  $this->_reply = sprintf($textTpl, 
         $this->getRevFrom(),
         $this->getRevTo(), 
         Date::getTimeStamp(), 
         'music', 
         $title,
         $desc,
         $musicurl,
         $hgmusicurl
        );
  return $this;
 }
 
 /**
  * 回复图文消息
  * @param array
  */
 public function news($data)
 {
  $count = count($data);
  $subText = '';
  if($count > 0)
  {
   foreach($data as $v)
   {
    $tmpText = '<item>
      <Title><![CDATA[%s]]></Title> 
      <Description><![CDATA[%s]]></Description>
      <PicUrl><![CDATA[%s]]></PicUrl>
      <Url><![CDATA[%s]]></Url>
      </item>';
    $subText .= sprintf(
        $tmpText, $v['title'], 
        isset($v['description']) ? $v['description'] : '', 
        isset($v['picUrl']) ? $v['picUrl'] : '', 
        isset($v['url']) ? $v['url'] : ''
       );
   }
  }
  $textTpl = '<xml>
      <ToUserName><![CDATA[%s]]></ToUserName>
      <FromUserName><![CDATA[%s]]></FromUserName>
      <CreateTime><![CDATA[%s]]></CreateTime>
      <MsgType><![CDATA[news]]></MsgType>
      <ArticleCount><![CDATA[%d]]></ArticleCount>
      <Articles>%s</Articles>
     </xml>';
  $this->_reply = sprintf(
       $textTpl, 
       $this->getRevFrom(), 
       $this->getRevTo(), 
       Date::getTimeStamp(), 
       $count, 
       $subText
      );
  return $this;
 }
 
 /**
  * 回复消息
  * @param array $msg
  * @param bool $return
  */
 public function reply()
 {
  header('Content-Type:text/xml');
  echo $this->_reply;
  exit;
 }
 
 /**
  * 自定义菜单创建
  * @param array 菜单数据
  */
 public function createMenu($data)
 {
  if(!$this->access_token && !$this->checkAuth()) return false;
  $result = curlRequest(self::API_URL_PREFIX.self::MENU_CREATE_URL.'access_token='.$this->access_token, $this->jsonEncode($data), 'post');
  if($result)
  {
   $jsonArr = json_decode($result, true);
   if(!$jsonArr || (isset($jsonArr['errcode']) && $jsonArr['errcode'] > 0)) $this->error($jsonArr);
   else return true;
  }
  return false;
 }
 
 /**
  * 自定义菜单查询
  */
 public function getMenu()
 {
  if(!$this->access_token && !$this->checkAuth()) return false;
  $result = curlRequest(self::API_URL_PREFIX.self::MENU_GET_URL.'access_token='.$this->access_token);
  if($result)
  {
   $jsonArr = json_decode($result, true);
   if(!$jsonArr || (isset($jsonArr['errcode']) && $jsonArr['errcode'] > 0)) $this->error($jsonArr);
   else return $jsonArr;
  }
  return false;
 }
 
 /**
  * 自定义菜单删除
  */
 public function deleteMenu()
 {
  if(!$this->access_token && !$this->checkAuth()) return false;
  $result = curlRequest(self::API_URL_PREFIX.self::MENU_DELETE_URL.'access_token='.$this->access_token);
  if($result)
  {
   $jsonArr = json_decode($result, true);
   if(!$jsonArr || (isset($jsonArr['errcode']) && $jsonArr['errcode'] > 0)) $this->error($jsonArr);
   else return true;
  }
  return false;
 }
 
 /**
  * 获取用户基本信息
  * @param string $openid 普通用户的标识,对当前公众号唯一
  */
 public function getUserInfo($openid)
 {
  if(!$this->access_token && !$this->checkAuth()) return false;
  $result = curlRequest(self::API_URL_PREFIX.self::USER_INFO_URL.'access_token='.$this->access_token.'&openid='.$openid);
  if($result)
  {
   $jsonArr = json_decode($result, true);
   if(!$jsonArr || (isset($jsonArr['errcode']) && $jsonArr['errcode'] > 0)) $this->error($jsonArr);
   else return $jsonArr;
  }
  return false;
 }
 
 /**
  * 获取关注者列表
  * @param string $next_openid 第一个拉取的OPENID,不填默认从头开始拉取
  */
 public function getUserList($next_openid='')
 {
  if(!$this->access_token && !$this->checkAuth()) return false;
  $result = curlRequest(self::API_URL_PREFIX.self::USER_GET_URL.'access_token='.$this->access_token.'&next_openid='.$next_openid);
  if($result)
  {
   $jsonArr = json_decode($result, true);
   if(!$jsonArr || (isset($jsonArr['errcode']) && $jsonArr['errcode'] > 0)) $this->error($jsonArr);
   else return $jsonArr;
  }
  return false;
 }
 
 /**
  * 查询分组
  */
 public function getGroup()
 {
  if(!$this->access_token && !$this->checkAuth()) return false;
  $result = curlRequest(self::API_URL_PREFIX.self::GROUPS_GET_URL.'access_token='.$this->access_token);
  if($result)
  {
   $jsonArr = json_decode($result, true);
   if(!$jsonArr || (isset($jsonArr['errcode']) && $jsonArr['errcode'] > 0)) $this->error($jsonArr);
   else return $jsonArr;
  }
  return false;
 }
 
 /**
  * 创建分组
  * @param string $name 分组名字(30个字符以内)
  */
 public function createGroup($name)
 {
  if(!$this->access_token && !$this->checkAuth()) return false;
  $data = array('group' => array('name' => $name));
  $result = curlRequest(self::API_URL_PREFIX.self::GROUPS_CREATE_URL.'access_token='.$this->access_token, $this->jsonEncode($data), 'post');
  if($result)
  {
   $jsonArr = json_decode($result, true);
   if(!$jsonArr || (isset($jsonArr['errcode']) && $jsonArr['errcode'] > 0)) $this->error($jsonArr);
   else return true;
  }
  return false;
 }
 
 /**
  * 修改分组名
  * @param int $id 分组id,由微信分配
  * @param string $name 分组名字(30个字符以内)
  */
 public function updateGroup($id, $name)
 {
  if(!$this->access_token && !$this->checkAuth()) return false;
  $data = array('group' => array('id' => $id, 'name' => $name));
  $result = curlRequest(self::API_URL_PREFIX.self::GROUPS_UPDATE_URL.'access_token='.$this->access_token, $this->jsonEncode($data), 'post');
  if($result)
  {
   $jsonArr = json_decode($result, true);
   if(!$jsonArr || (isset($jsonArr['errcode']) && $jsonArr['errcode'] > 0)) $this->error($jsonArr);
   else return true;
  }
  return false;
 }
 
 /**
  * 移动用户分组
  * 
  * @param string $openid 用户唯一标识符
  * @param int $to_groupid 分组id
  */
 public function updateGroupMembers($openid, $to_groupid)
 {
  if(!$this->access_token && !$this->checkAuth()) return false;
  $data = array('openid' => $openid, 'to_groupid' => $to_groupid);
  $result = curlRequest(self::API_URL_PREFIX.self::GROUPS_MEMBERS_UPDATE_URL.'access_token='.$this->access_token, $this->jsonEncode($data), 'post');
  if($result)
  {
   $jsonArr = json_decode($result, true);
   if(!$jsonArr || (isset($jsonArr['errcode']) && $jsonArr['errcode'] > 0)) $this->error($jsonArr);
   else return true;
  }
  return false;
 }
 
 /**
  * 发送客服消息
  * 当用户主动发消息给公众号的时候(包括发送信息、点击自定义菜单clike事件、订阅事件、扫描二维码事件、支付成功事件、用户维权),
  * 微信将会把消息数据推送给开发者,开发者在一段时间内(目前为24小时)可以调用客服消息接口,通过POST一个JSON数据包来发送消息给普通用户,在24小时内不限制发送次数。
  * 此接口主要用于客服等有人工消息处理环节的功能,方便开发者为用户提供更加优质的服务。
  * 
  * @param string $touser 普通用户openid
  */
 public function sendCustomMessage($touser, $data, $msgType = 'text')
 {
  $arr = array();
  $arr['touser'] = $touser;
  $arr['msgtype'] = $msgType;
  switch ($msgType)
  {
   case 'text': // 发送文本消息
    $arr['text']['content'] = $data; 
    break;
   case 'image': // 发送图片消息
    $arr['image']['media_id'] = $data;
    break;
   case 'voice': // 发送语音消息
    $arr['voice']['media_id'] = $data;
    break;
   case 'video': // 发送视频消息
    $arr['video']['media_id'] = $data['media_id']; // 发送的视频的媒体ID
    $arr['video']['thumb_media_id'] = $data['thumb_media_id']; // 视频缩略图的媒体ID
    break;
   case 'music': // 发送音乐消息
    $arr['music']['title'] = $data['title'];// 音乐标题
    $arr['music']['description'] = $data['description'];// 音乐描述
    $arr['music']['musicurl'] = $data['musicurl'];// 音乐链接
    $arr['music']['hqmusicurl'] = $data['hqmusicurl'];// 高品质音乐链接,wifi环境优先使用该链接播放音乐
    $arr['music']['thumb_media_id'] = $data['title'];// 缩略图的媒体ID
    break;
   case 'news': // 发送图文消息
    $arr['news']['articles'] = $data; // title、description、url、picurl
    break;
  } 
  if(!$this->access_token && !$this->checkAuth()) return false;
  $result = curlRequest(self::API_URL_PREFIX.self::MESSAGE_CUSTOM_SEND_URL.'access_token='.$this->access_token, $this->jsonEncode($arr), 'post');
  if($result)
  {
   $jsonArr = json_decode($result, true);
   if(!$jsonArr || (isset($jsonArr['errcode']) && $jsonArr['errcode'] > 0)) $this->error($jsonArr);
   else return true;
  }
  return false;
 }
 
 /**
  * 获取access_token
  */
 public function checkAuth()
 {
  // 从缓存中获取access_token
  $cache_flag = 'weixin_access_token';
  $access_token = cache($cache_flag);
  if($access_token) 
  {
   $this->access_token = $access_token;
   return true;
  }
  // 请求微信服务器获取access_token 
  $result = curlRequest(self::API_URL_PREFIX.self::AUTH_URL.'appid='.$this->appid.'&secret='.$this->appsecret);
  if($result)
  {
   $jsonArr = json_decode($result, true);
   if(!$jsonArr || (isset($jsonArr['errcode']) && $jsonArr['errcode'] > 0))
   {
    $this->error($jsonArr);
   }
   else
   {
    $this->access_token = $jsonArr['access_token'];
    $expire = isset($jsonArr['expires_in']) ? intval($jsonArr['expires_in'])-100 : 3600;
    // 将access_token保存到缓存中
    cache($cache_flag, $this->access_token, $expire, Cache::FILE); 
    return true;
   }
  }
  return false;
 }
 
 /**
  * 微信oauth登陆->第一步:用户同意授权,获取code
  * 应用授权作用域,snsapi_base (不弹出授权页面,直接跳转,只能获取用户openid),
  * snsapi_userinfo (弹出授权页面,可通过openid拿到昵称、性别、所在地。并且,即使在未关注的情况下,只要用户授权,也能获取其信息)
  * 直接在微信打开链接,可以不填此参数。做页面302重定向时候,必须带此参数
  * 
  * @param string $redirect_uri 授权后重定向的回调链接地址
  * @param string $scope 应用授权作用域 0为snsapi_base,1为snsapi_userinfo
  * @param string $state 重定向后会带上state参数,开发者可以填写任意参数值
  */
 public function redirectGetOauthCode($redirect_uri, $scope=0, $state='')
 {
  $scope = ($scope == 0) ? 'snsapi_base' : 'snsapi_userinfo';
  $url = self::CONNECT_OAUTH_AUTHORIZE_URL.'appid='.$this->appid.'&redirect_uri='.urlencode($redirect_uri).'&response_type=code&scope='.$scope.'&state='.$state.'#wechat_redirect';
  redirect($url);
 }
 
 /**
  * 微信oauth登陆->第二步:通过code换取网页授权access_token
  * 
  * @param string $code
  */
 public function getSnsAccessToken($code)
 {
  $result = curlRequest(self::SNS_OAUTH_ACCESS_TOKEN_URL.'appid='.$this->appid.'&secret='.$this->appsecret.'&code='.$code.'&grant_type=authorization_code');
  if($result)
  {
   $jsonArr = json_decode($result, true);
   if(!$jsonArr || (isset($jsonArr['errcode']) && $jsonArr['errcode'] > 0)) $this->error($jsonArr);
   else return $jsonArr;
  }
  return false;
 }
 
 /**
  * 微信oauth登陆->第三步:刷新access_token(如果需要)
  * 由于access_token拥有较短的有效期,当access_token超时后,可以使用refresh_token进行刷新,
  * refresh_token拥有较长的有效期(7天、30天、60天、90天),当refresh_token失效的后,需要用户重新授权。
  * 
  * @param string $refresh_token 填写通过access_token获取到的refresh_token参数
  */
 public function refershToken($refresh_token)
 {
  $result = curlRequest(self::SNS_OAUTH_REFRESH_TOKEN_URL.'appid='.$this->appid.'&grant_type=refresh_token&refresh_token='.$refresh_token);
  if($result)
  {
   $jsonArr = json_decode($result, true);
   if(!$jsonArr || (isset($jsonArr['errcode']) && $jsonArr['errcode'] > 0)) $this->error($jsonArr);
   else return $jsonArr;
  }
  return false;
 }
 
 /**
  * 微信oauth登陆->第四步:拉取用户信息(需scope为 snsapi_userinfo)
  * 如果网页授权作用域为snsapi_userinfo,则此时开发者可以通过access_token和openid拉取用户信息了。
  * 
  * @param string $access_token 网页授权接口调用凭证,注意:此access_token与基础支持的access_token不同
  * @param string $openid 用户的唯一标识
  */
 public function getSnsUserInfo($access_token, $openid)
 {
  $result = curlRequest(self::SNS_USERINFO_URL.'access_token='.$access_token.'&openid='.$openid);
  if($result)
  {
   $jsonArr = json_decode($result, true);
   if(!$jsonArr || (isset($jsonArr['errcode']) && $jsonArr['errcode'] > 0)) $this->error($jsonArr);
   else return $jsonArr;
  }
  return false;
 }
 
 /**
  * 创建二维码ticket
  * 每次创建二维码ticket需要提供一个开发者自行设定的参数(scene_id),分别介绍临时二维码和永久二维码的创建二维码ticket过程。
  * 
  * @param int $scene_id 场景值ID,临时二维码时为32位整型,永久二维码时最大值为1000
  * @param int $type 二维码类型,0为临时,1为永久
  * @param int $expire 该二维码有效时间,以秒为单位。 最大不超过1800。
  */
 public function createQrcode($scene_id, $type=0, $expire=1800)
 {
  if(!$this->access_token && !$this->checkAuth()) return false;
  $data = array();
  $data['action_info'] = array('scene' => array('scene_id' => $scene_id));
  $data['action_name'] = ($type == 0 ? 'QR_SCENE' : 'QR_LIMIT_SCENE');
  if($type == 0) $data['expire_seconds'] = $expire;
  $result = curlRequest(self::API_URL_PREFIX.self::QRCODE_CREATE_URL.'access_token='.$this->access_token, $this->jsonEncode($data), 'post');
  if($result)
  {
   $jsonArr = json_decode($result, true);
   if(!$jsonArr || (isset($jsonArr['errcode']) && $jsonArr['errcode'] > 0)) $this->error($jsonArr);
   else return $jsonArr;
  }
  return false;
 }
 
 /**
  * 通过ticket换取二维码
  * 获取二维码ticket后,开发者可用ticket换取二维码图片。请注意,本接口无须登录态即可调用。
  * 提醒:TICKET记得进行UrlEncode
  * ticket正确情况下,http 返回码是200,是一张图片,可以直接展示或者下载。
  * 错误情况下(如ticket非法)返回HTTP错误码404。
  * 
  * @param string $ticket
  */
 public function getQrcodeUrl($ticket)
 {
  return self::SHOW_QRCODE_URL.'ticket='.urlencode($ticket);
 }
 
 /**
  * 记录接口产生的错误日志
  */
 public function error($data)
 {
  $this->errCode = $data['errcode'];
  $this->errMsg = $data['errmsg'];
  Log::info('WEIXIN API errcode:['.$this->errCode.'] errmsg:['.$this->errMsg.']');
 }
 
 /**
  * 将数组中的中文转换成json数据
  * @param array $arr
  */
 public function jsonEncode($arr) {
     $parts = array ();
        $is_list = false;
        //Find out if the given array is a numerical array
        $keys = array_keys ( $arr );
        $max_length = count ( $arr ) - 1;
        if (($keys [0] === 0) && ($keys [$max_length] === $max_length )) { //See if the first key is 0 and last key is length - 1
            $is_list = true;
            for($i = 0; $i < count ( $keys ); $i ++) { //See if each key correspondes to its position
               if ($i != $keys [$i]) { //A key fails at position check.
                  $is_list = false; //It is an associative array.
                  break;
               }
            }
        }
                foreach ( $arr as $key => $value ) {
                        if (is_array ( $value )) { //Custom handling for arrays
                                if ($is_list)
                                        $parts [] = $this->jsonEncode ( $value ); /* :RECURSION: */
                                else
                                        $parts [] = '"' . $key . '":' . $this->jsonEncode ( $value ); /* :RECURSION: */
                        } else {
                                $str = '';
                                if (! $is_list)
                                        $str = '"' . $key . '":';
                                //Custom handling for multiple data types
                                if (is_numeric ( $value ) && $value<2000000000)
                                        $str .= $value; //Numbers
                                elseif ($value === false)
                                $str .= 'false'; //The booleans
                                elseif ($value === true)
                                $str .= 'true';
                                else
                                        $str .= '"' . addslashes ( $value ) . '"'; //All other things
                                // :TODO: Is there any more datatype we should be in the lookout for? (Object?)
                                $parts [] = $str;
                        }
                }
                $json = implode ( ',', $parts );
                if ($is_list)
                        return '[' . $json . ']'; //Return numerical JSON
                return '{' . $json . '}'; //Return associative JSON
        }
        
 /**
  * 检验签名
  */
 public function checkSignature()
 {
        $signature = HttpRequest::getGet('signature');
        $timestamp = HttpRequest::getGet('timestamp');
        $nonce = HttpRequest::getGet('nonce');
  $token = $this->token;
  $tmpArr = array($token, $timestamp, $nonce);
  sort($tmpArr);
  $tmpStr = implode($tmpArr);
  $tmpStr = sha1($tmpStr);
  return ($tmpStr == $signature ? true : false);
 }
 
 /**
  * 验证token是否有效
  */
 public function valid()
 {
  if($this->checkSignature()) exit(HttpRequest::getGet('echostr'));
 }
}
PHP 相关文章推荐
使用PHPMyAdmin修复论坛数据库的图文方法
Jan 09 PHP
PHP常用的排序和查找算法
Aug 06 PHP
基于PHP实现等比压缩图片大小
Mar 04 PHP
深入讲解PHP的Yii框架中的属性(Property)
Mar 18 PHP
php简单统计在线人数的方法
May 10 PHP
yii的入口文件index.php中为什么会有这两句
Aug 04 PHP
PHP页面间传递值和保持值的方法
Aug 24 PHP
php使用CURL模拟GET与POST向微信接口提交及获取数据的方法
Sep 23 PHP
thinkPHP5.0框架应用请求生命周期分析
Mar 25 PHP
PHP实现上传多图即时显示与即时删除的方法
May 09 PHP
php表单处理操作
Nov 16 PHP
yii2 开发api接口时优雅的处理全局异常的方法
May 14 PHP
百度站点地图(百度sitemap)生成方法分享
Jan 09 #PHP
利用phpexcel把excel导入数据库和数据库导出excel实现
Jan 09 #PHP
php将mysql数据库整库导出生成sql文件的具体实现
Jan 08 #PHP
PHP修改session_id示例代码
Jan 08 #PHP
让PHP显示Facebook的粉丝数量方法
Jan 08 #PHP
利用浏览器的Javascript控制台调试PHP程序
Jan 08 #PHP
php获取从百度搜索进入网站的关键词的详细代码
Jan 08 #PHP
You might like
PHP利用hash冲突漏洞进行DDoS攻击的方法分析
2015/03/26 PHP
PHP+MySQL统计该库中每个表的记录数并按递减顺序排列的方法
2016/02/15 PHP
ThinkPHP5 验证器的具体使用
2018/05/31 PHP
ThinkPHP5框架实现简单的批量查询功能示例
2018/06/07 PHP
Javascript注入技巧
2007/06/22 Javascript
利用WebBrowser彻底解决Web打印问题(包括后台打印)
2009/06/22 Javascript
JQuery 风格的HTML文本转义
2009/07/01 Javascript
几个有趣的Javascript Hack
2010/07/24 Javascript
JS遮罩层效果 兼容ie firefox jQuery遮罩层
2010/07/26 Javascript
JS操作图片(增,删,改) 例子
2013/04/17 Javascript
JQuery操作单选按钮以及复选按钮示例
2013/09/23 Javascript
jquery.post用法之type设置问题
2014/02/24 Javascript
JavaScript实现在数组中查找不同顺序排列的字符串
2014/09/26 Javascript
JS动态添加选项案例分析
2016/10/17 Javascript
React-Native中props具体使用详解
2017/09/04 Javascript
vue router学习之动态路由和嵌套路由详解
2017/09/21 Javascript
vue实现todolist功能、todolist组件拆分及todolist的删除功能
2019/04/11 Javascript
详解vue路由
2020/08/05 Javascript
如何构建一个Vue插件并生成npm包
2020/10/26 Javascript
Vue 3自定义指令开发的相关总结
2021/01/29 Vue.js
[02:14]2016国际邀请赛中国区预选赛Ehome晋级之路
2016/07/01 DOTA
Python和Java进行DES加密和解密的实例
2018/01/09 Python
python xlsxwriter创建excel图表的方法
2018/06/11 Python
python打包生成的exe文件运行时提示缺少模块的解决方法
2018/10/31 Python
python怎么判断模块安装完成
2020/06/19 Python
HTML5到底会有什么发展?HTML5的前景展望
2015/07/07 HTML / CSS
Get The Label中文官网:英国运动时尚购物平台
2017/04/19 全球购物
请解释virtual关键字的含义
2015/06/17 面试题
主办会计岗位职责
2014/03/13 职场文书
《地震中的父与子》教学反思
2014/04/10 职场文书
建筑质检员岗位职责
2015/04/08 职场文书
周一问候语大全
2015/11/10 职场文书
MySQL利用UNION连接2个查询排序失效详解
2021/11/20 MySQL
sql server 累计求和实现代码
2022/02/28 SQL Server
mysql使用instr达到in(字符串)的效果
2022/04/03 MySQL
Java 多线程并发FutureTask
2022/06/28 Java/Android