欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2023-12-09 13:21:33
适用平台:window/linux依赖项目:eaglephp框架 包含微信5.0 api基础接口、自定义菜单、高级接口,具体如下:1、接收用户消息。2、向用户回复消息。3...

适用平台: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'));
 }

}