浏览代码

merge update from @binsee

dodgepudding 10 年之前
父节点
当前提交
3ac6e441be
共有 10 个文件被更改,包括 533 次插入254 次删除
  1. 33 4
      README.md
  2. 1 1
      Thinkphp/Snoopy.class.php
  3. 100 90
      Thinkphp/Wechat.class.php
  4. 3 3
      Thinkphp/Wechatauth.class.php
  5. 69 67
      Thinkphp/Wechatext.class.php
  6. 1 1
      snoopy.class.php
  7. 240 72
      wechat.class.php
  8. 77 2
      wechat.js
  9. 1 2
      wechatauth.class.php
  10. 8 12
      wechatext.class.php

+ 33 - 4
README.md

@@ -21,15 +21,18 @@ https://mp.weixin.qq.com/cgi-bin/readtemplate?t=business/course2_tmpl&lang=zh_CN
 - 菜单操作(查询、创建、删除)(菜单权限)
 - 客服消息(文本、图片、语音、视频、音乐、图文)(认证权限)
 - 二维码(创建临时、永久二维码,获取二维码URL)(认证权限)
+- 长链接转短链接接口(认证权限)
 - 分组操作(查询、创建、修改、移动用户到分组)(认证权限)
 - 网页授权(基本授权,用户信息授权)(认证权限)
 - 用户信息(查询用户基本信息、获取关注者列表)(认证权限)
+- 多客服功能(认证权限)
 - 媒体文件(上传、获取)(认证权限) 
 - 调用地址组件 (支付权限) 
 - 生成订单签名数据 (支付权限) 
 - 订单成功回调 (支付权限) 
 - 发货通知 (支付权限) 
 - 支付订单查询 (支付权限) 
+- 模板消息(支付权限) 
 
 
 ### 初始化动作 
@@ -52,12 +55,20 @@ https://mp.weixin.qq.com/cgi-bin/readtemplate?t=business/course2_tmpl&lang=zh_CN
  *  createMenu($data) 创建菜单 $data菜单结构详见 http://mp.weixin.qq.com/wiki/index.php?title=%E8%87%AA%E5%AE%9A%E4%B9%89%E8%8F%9C%E5%8D%95%E5%88%9B%E5%BB%BA%E6%8E%A5%E5%8F%A3 
  *  getMenu() 获取菜单 
  *  deleteMenu() 删除菜单 
+ *  uploadMedia($data, $type) 上传多媒体文件
  *  getMedia() 获取接收到的音频、视频媒体文件 
+ *  uploadArticles($data) 上传图文消息素材
+ *  sendMassMessage($data) 高级群发消息
+ *  sendGroupMassMessage($data) 高级群发消息(分组群发)
+ *  deleteMassMessage() 删除群发图文消息
  *  getQRCode($scene_id,$type=0,$expire=1800) 获取推广二维码ticket字串 
  *  getQRUrl($ticket) 获取二维码图片地址
+ *  getShortUrl($long_url) 长链接转短链接接口
  *  getUserList($next_openid) 批量获取关注用户列表 
  *  getUserInfo($openid) 获取关注者详细信息 
+ *  updateUserRemark($openid,$remark) 设置用户备注名
  *  getGroup() 获取用户分组列表 
+ *  getUserGroup($openid) 获取用户所在分组
  *  createGroup($name) 新增自定分组 
  *  updateGroup($groupid,$name) 更改分组名称 
  *  updateGroupMembers($groupid,$openid) 移动用户分组  
@@ -66,6 +77,7 @@ https://mp.weixin.qq.com/cgi-bin/readtemplate?t=business/course2_tmpl&lang=zh_CN
  *  getOauthAccessToken() 通过回调的code获取网页授权access_token  
  *  getOauthRefreshToken($refresh_token) 通过refresh_token对access_token续期  
  *  getOauthUserinfo($access_token,$openid) 通过网页授权的access_token获取用户资料  
+ *  getOauthAuth($access_token,$openid)  检验授权凭证access_token是否有效
  *  getSignature($arrdata,'sha1') 生成签名字串  
  *  generateNonceStr($length) 获取随机字串  
  *  createPackage($out_trade_no,$body,$total_fee,$notify_url,$spbill_create_ip,$fee_type=1,$bank_type="WX",$input_charset="UTF-8",$time_start="",$time_expire="",$transport_fee="",$product_fee="",$goods_tag="",$attach="") 生成订单package字符串  
@@ -73,7 +85,12 @@ https://mp.weixin.qq.com/cgi-bin/readtemplate?t=business/course2_tmpl&lang=zh_CN
  *  checkOrderSignature($orderxml='') 回调通知签名验证  
  *  sendPayDeliverNotify($openid,$transid,$out_trade_no,$status=1,$msg='ok') 发货通知  
  *  getPayOrder($out_trade_no) 查询订单信息  
- *  getAddrSign($url, $timeStamp, $nonceStr, $user_token='') 获取收货地址JS的签名  
+ *  getAddrSign($url, $timeStamp, $nonceStr, $user_token='') 获取收货地址JS的签名
+ *  sendTemplateMessage($data) 发送模板消息
+ *  getCustomServiceMessage($data) 获取多客服会话记录
+ *  transfer_customer_service($customer_account) 转发多客服消息
+ *  getCustomServiceKFlist() 获取多客服客服基本信息
+ *  getCustomServiceOnlineKFlist() 获取多客服在线客服接待信息
  
   
 2. wechatext.class.php  
@@ -87,7 +104,7 @@ https://mp.weixin.qq.com/cgi-bin/readtemplate?t=business/course2_tmpl&lang=zh_CN
  *  getUserList($page,$pagesize,$groupid) 获取用户信息
  *  getGroupList($page,$pagesize) 获取群组信息
  *  getNewsList($page,$pagesize) 获取图文信息列表 
- *  uploadFile($filepath,$type) 上传附件,包括图片/音频/视频
+ *  uploadFile($filepath,$type) 上传附件,包括图片/音频/视频/缩略图
  *  getFileList($type,$page,$pagesize) 获取素材库文件列表
  *  sendImage($id,$fid) 发送图片消息
  *  sendAudio($id,$fid) 发送音频消息
@@ -106,15 +123,27 @@ https://mp.weixin.qq.com/cgi-bin/readtemplate?t=business/course2_tmpl&lang=zh_CN
  *  get_login_code() 获取登陆授权码, 通过授权码才能获取二维码  
  *  get_code_image($code='') 将上面获取的授权码转换为图片二维码  
  *  verify_code() 鉴定是否登陆成功,返回200为最终授权成功.  
- *  get_login_cookie() 鉴定成功后调用此方法即可获取用户基本信息  
- *  sendNews($account,$title,$summary,$content,$pic,$srcurl='') 向一个微信账户发送图文信息  
+ *  get_login_info() 鉴定成功后调用此方法即可获取用户基本信息  
  *  get_avatar($url) 获取用户头像图片数据  
  *  logout() 注销登陆  
 
 4. wechat.js
 微信内嵌网页特殊功能js调用:
  * WeixinJS.hideOptionMenu() 隐藏右上角按钮
+ * WeixinJS.showOptionMenu() 显示右上角按钮
  * WeixinJS.hideToolbar() 隐藏工具栏
+ * WeixinJS.showToolbar() 显示工具栏
+ * WeixinJS.getNetworkType() 获取网络状态
+ * WeixinJS.closeWindow() 关闭窗口
+ * WeixinJS.scanQRCode() 扫描二维码
+ * WeixinJS.openUrlByExtBrowser(url) 使用浏览器打开网址
+ * WeixinJS.jumpToBizProfile(username) 跳转到指定公众账号页面
+ * WeixinJS.sendEmail(title,content) 发送邮件
+ * WeixinJS.openProductView(latitude,longitude,name,address,scale,infoUrl) 查看地图
+ * WeixinJS.addContact(username) 添加微信账号
+ * WeixinJS.imagePreview(urls,current) 调出微信内图片预览
+ * WeixinJS.payCallback(appId,package,timeStamp,nonceStr,signType,paySign,callback) 微信JsApi支付接口
+ * WeixinJS.editAddress(appId,addrSign,timeStamp,nonceStr,callback) 微信JsApi支付接口
  * 通过定义全局变量dataForWeixin配置触发分享的内容:
  ```javascript
  var dataForWeixin={

+ 1 - 1
Thinkphp/Snoopy.class.php

@@ -1220,7 +1220,7 @@ class Snoopy
 		if (count($formvars) == 0 && count($formfiles) == 0)
 			return;
 		if (is_string($formvars)) return $formvars;
-		if(count($formvars) == 1) return $formvars[0];
+		if((count($formvars) == 1) && isset($formvars[0])) return $formvars[0];
 		switch ($this->_submit_type) {
 			case "application/x-www-form-urlencoded":
 				reset($formvars);

+ 100 - 90
Thinkphp/Wechat.class.php

@@ -9,7 +9,7 @@
  *			'token'=>'tokenaccesskey', //填写你设定的key
  *			'appid'=>'wxdk1234567890', //填写高级调用功能的app id
  *			'appsecret'=>'xxxxxxxxxxxxxxxxxxx', //填写高级调用功能的密钥
- * 			'partnerid'=>'88888888', //财付通商户身份标识
+ *			'partnerid'=>'88888888', //财付通商户身份标识
  *			'partnerkey'=>'', //财付通商户权限密钥Key
  *			'paysignkey'=>'' //商户签名密钥Key
  *		);
@@ -40,7 +40,7 @@
  *   				array('type'=>'click','name'=>'最新消息','key'=>'MENU_KEY_NEWS'),
  *   				array('type'=>'view','name'=>'我要搜索','url'=>'http://www.baidu.com'),
  *   				)
-  *  		);
+ *  		);
  *   $result = $weObj->createMenu($newmenu);
  */
 class Wechat
@@ -66,6 +66,7 @@ class Wechat
 	const QRCODE_IMG_URL='https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=';
 	const USER_GET_URL='/user/get?';
 	const USER_INFO_URL='/user/info?';
+	const USER_UPDATEREMARK_URL='/user/info/updateremark?';	
 	const GROUP_GET_URL='/groups/get?';
 	const GROUP_CREATE_URL='/groups/create?';
 	const GROUP_UPDATE_URL='/groups/update?';
@@ -89,7 +90,6 @@ class Wechat
 	const CUSTOM_SERVICE_GET_RECORD = '/customservice/getrecord?';
 	const CUSTOM_SERVICE_GET_KFLIST = '/customservice/getkflist?';
 	const CUSTOM_SERVICE_GET_ONLINEKFLIST = '/customservice/getkflist?';
-	const Templat_SEND_URL = '/message/template/send?';
 	
 	private $token;
 	private $appid;
@@ -130,9 +130,7 @@ class Wechat
         		
 		$token = $this->token;
 		$tmpArr = array($token, $timestamp, $nonce);
-
-	    sort($tmpArr, SORT_STRING);
-
+		sort($tmpArr, SORT_STRING);
 		$tmpStr = implode( $tmpArr );
 		$tmpStr = sha1( $tmpStr );
 		
@@ -337,11 +335,11 @@ class Wechat
 	 * 获取上报地理位置事件
 	 */
 	public function getRevEventGeo(){
-		if (isset($this->_receive['Latitude'])){
-			return array(
-					'x'=>$this->_receive['Latitude'],
-					'y'=>$this->_receive['Longitude'],
-					'precision'=>$this->_receive['Precision'],
+        	if (isset($this->_receive['Latitude'])){
+        		 return array(
+				'x'=>$this->_receive['Latitude'],
+				'y'=>$this->_receive['Longitude'],
+				'precision'=>$this->_receive['Precision'],
 			);
 		} else
 			return false;
@@ -352,16 +350,21 @@ class Wechat
 	 */
 	public function getRevEvent(){
 		if (isset($this->_receive['Event'])){
-			return array(
-				'event'=>$this->_receive['Event'],
-				'key'=>$this->_receive['EventKey'],
-			);
-		} else 
+			$array['event'] = $this->_receive['Event'];
+		}
+		if (isset($this->_receive['EventKey'])){
+			$array['key'] = $this->_receive['EventKey'];
+		}
+		
+		if (isset($array) && count($array) > 0) {
+			return $array;
+		} else {
 			return false;
+		} 
 	}
 	
 	/**
-	 * 获取接收语推送
+	 * 获取接收语推送
 	 */
 	public function getRevVoice(){
 		if (isset($this->_receive['MediaId'])){
@@ -371,7 +374,7 @@ class Wechat
 			);
 		} else 
 			return false;
-	}	
+	}
 	
 	/**
 	 * 获取接收视频推送
@@ -407,6 +410,27 @@ class Wechat
 		}
 	}
 	
+	/**
+	* 获取模板消息ID
+	* 经过验证,这个和普通的消息MsgId不一样
+	*/
+	public function getRevTplMsgID(){
+		if (isset($this->_receive['MsgID'])){
+			return $this->_receive['MsgID'];
+		} else 
+			return false;
+	}
+	
+	/**
+	* 获取模板消息发送状态
+	*/
+	public function getRevStatus(){
+		if (isset($this->_receive['Status'])){
+			return $this->_receive['Status'];
+		} else 
+			return false;
+	}
+	
 	public static function xmlSafeStr($str)
 	{   
 		return '<![CDATA['.preg_replace("/[\\x00-\\x08\\x0b-\\x0c\\x0e-\\x1f]/",'',$str).']]>';   
@@ -535,7 +559,7 @@ class Wechat
 	
 	/**
 	 * 
-	 * 回复微信服务器, 此函数支持炼师操作
+	 * 回复微信服务器, 此函数支持链式操作
 	 * Example: $this->text('msg tips')->reply();
 	 * @param string $msg 要发送的信息, 默认取$this->_msg
 	 * @param bool $return 是否返回信息而不抛出到浏览器 默认:否
@@ -555,7 +579,7 @@ class Wechat
 	/**
 	 * GET 请求
 	 * @param string $url
-	*/
+	 */
 	private function http_get($url){
 		$oCurl = curl_init();
 		if(stripos($url,"https://")!==FALSE){
@@ -576,10 +600,10 @@ class Wechat
 	
 	/**
 	 * POST 请求
-	 * @param string $url 
-	 * @param array $param 
+	 * @param string $url
+	 * @param array $param
 	 * @return string content
-	*/
+	 */
 	private function http_post($url,$param){
 		$oCurl = curl_init();
 		if(stripos($url,"https://")!==FALSE){
@@ -640,7 +664,7 @@ class Wechat
 		}
 		return false;
 	}
-	
+
 	/**
 	 * 删除验证数据
 	 * @param string $appid
@@ -652,7 +676,7 @@ class Wechat
 		S($authname,null);
 		return true;
 	}
-	
+
 	/**
 	 * 微信api不支持中文转义的json结构
 	 * @param array $arr
@@ -791,8 +815,10 @@ class Wechat
 
 	/**
 	 * 上传多媒体文件
-	 * @param array $data 消息结构{ "touser":[ "OPENID1", "OPENID2" ], "mpnews":{ "media_id":"123dsdajkasd231jhksad" }, "msgtype":"mpnews" }
-	 * @return raw data
+	 * 注意:数组的键值任意,但文件名前必须加@,使用单引号以避免本地路径斜杠被转义
+	 * @param array $data {"media":'@Path\filename.jpg'}
+	 * @param type 类型:图片:image 语音:voice 视频:video 缩略图:thumb
+	 * @return boolean|array
 	 */
 	public function uploadMedia($data, $type){
 		if (!$this->access_token && !$this->checkAuth()) return false;
@@ -925,9 +951,9 @@ class Wechat
 	public function getQRCode($scene_id,$type=0,$expire=1800){
 		if (!$this->access_token && !$this->checkAuth()) return false;
 		$data = array(
-				'action_name'=>$type?"QR_LIMIT_SCENE":"QR_SCENE",
-				'expire_seconds'=>$expire,
-				'action_info'=>array('scene'=>array('scene_id'=>$scene_id))
+			'action_name'=>$type?"QR_LIMIT_SCENE":"QR_SCENE",
+			'expire_seconds'=>$expire,
+			'action_info'=>array('scene'=>array('scene_id'=>$scene_id))
 		);
 		if ($type == 1) {
 			unset($data['expire_seconds']);
@@ -995,6 +1021,32 @@ class Wechat
 		}
 		return false;
 	}
+
+	/**
+	 * 设置用户备注名
+	 * @param string $openid
+	 * @param string $remark 备注名
+	 * @return boolean|array
+	 */
+	public function updateUserRemark($openid,$remark){
+	    if (!$this->access_token && !$this->checkAuth()) return false;
+	    $data = array(
+			'openid'=>$openid,
+			'remark'=>$remark
+	    );
+	    $result = $this->http_post(self::API_URL_PREFIX.self::USER_UPDATEREMARK_URL.'access_token='.$this->access_token,$data);
+	    if ($result)
+	    {
+	        $json = json_decode($result,true);
+			if (!$json || !empty($json['errcode'])) {
+				$this->errCode = $json['errcode'];
+				$this->errMsg = $json['errmsg'];
+				return false;
+			}
+			return $json;
+	    }
+	    return false;
+	}
 	
 	/**
 	 * 获取用户分组列表
@@ -1092,48 +1144,6 @@ class Wechat
 	}
 	
 	/**
-	 * 发送模板消息
-	 * @param array $data 消息结构
-	 * {
-			"touser":"OPENID",
-			"template_id":"ngqIpbwh8bUfcSsECmogfXcV14J0tQlEpBO27izEYtY",
-			"url":"http://weixin.qq.com/download",
-			"topcolor":"#FF0000",
-			"data":{
-				"参数名1": {
-					"value":"参数",
-					"color":"#173177"	 //参数颜色
-					},
-				"Date":{
-					"value":"06月07日 19时24分",
-					"color":"#173177"
-					},
-				"CardNumber":{
-					"value":"0426",
-					"color":"#173177"
-					},
-				"Type":{
-					"value":"消费",
-					"color":"#173177"
-					}
-			}
-		}
-	 * @return boolean|array
-	 */
-	public function sendTemplateMessage($data){
-		if (!$this->access_token && !$this->checkAuth()) return false;
-		$result = $this->http_post(self::API_URL_PREFIX.self::Templat_SEND_URL.'access_token='.$this->access_token,self::json_encode($data));
-		
-		if($result){
-			$json = json_decode($result,true);
-			
-			return $json;
-		}
-		return false;
-	}
-	
-	
-	/**
 	 * 发送客服消息
 	 * @param array $data 消息结构{"touser":"OPENID","msgtype":"news","news":{...}}
 	 * @return boolean|array
@@ -1163,10 +1173,10 @@ class Wechat
 		return self::OAUTH_PREFIX.self::OAUTH_AUTHORIZE_URL.'appid='.$this->appid.'&redirect_uri='.urlencode($callback).'&response_type=code&scope='.$scope.'&state='.$state.'#wechat_redirect';
 	}
 	
-	/*
+	/**
 	 * 通过code获取Access Token
-	* @return array {access_token,expires_in,refresh_token,openid,scope}
-	*/
+	 * @return array {access_token,expires_in,refresh_token,openid,scope}
+	 */
 	public function getOauthAccessToken(){
 		$code = isset($_GET['code'])?$_GET['code']:'';
 		if (!$code) return false;
@@ -1374,7 +1384,7 @@ class Wechat
 		return false;
 	}
 	
-	/*
+	/**
 	 * 查询订单信息
 	 * @param string $out_trade_no 订单号
 	 * @return boolean|array
@@ -1497,7 +1507,7 @@ class Wechat
 		}
 		return false;
 	}
-	
+
 	/**
 	 * 转发多客服消息
 	 * Examle: $obj->transfer_customer_service($customer_account)->reply();
@@ -1506,10 +1516,10 @@ class Wechat
 	public function transfer_customer_service($customer_account = '')
 	{
 		$msg = array(
-				'ToUserName' => $this->getRevFrom(),
-				'FromUserName'=>$this->getRevTo(),
-				'CreateTime'=>time(),
-				'MsgType'=>'transfer_customer_service',
+			'ToUserName' => $this->getRevFrom(),
+			'FromUserName'=>$this->getRevTo(),
+			'CreateTime'=>time(),
+			'MsgType'=>'transfer_customer_service',
 		);
 		if (!$customer_account) {
 			$msg['TransInfo'] = array('KfAccount'=>$customer_account);
@@ -1520,8 +1530,8 @@ class Wechat
 	
 	/**
 	 * 获取多客服客服基本信息
-	 * @param
-	 * @return array
+	 * 
+	 * @return boolean|array
 	 */
 	public function getCustomServiceKFlist(){
 		if (!$this->access_token && !$this->checkAuth()) return false;
@@ -1541,15 +1551,15 @@ class Wechat
 	
 	/**
 	 * 获取多客服在线客服接待信息
-	 * @param
-	 * @return array {
+	 * 
+	 * @return boolean|array {
 	 "kf_online_list": [
 	 {
-	 "kf_account": "test1@test", //客服账号@微信别名
-	 "status": 1,				//客服在线状态 1:pc在线,2:手机在线,若pc和手机同时在线则为 1+2=3
-	 "kf_id": "1001",			//客服工号
-	 "auto_accept": 0,			//客服设置的最大自动接入数
-	 "accepted_case": 1 			//客服当前正在接待的会话数
+	 "kf_account": "test1@test",	//客服账号@微信别名
+	 "status": 1,			//客服在线状态 1:pc在线,2:手机在线,若pc和手机同时在线则为 1+2=3
+	 "kf_id": "1001",		//客服工号
+	 "auto_accept": 0,		//客服设置的最大自动接入数
+	 "accepted_case": 1		//客服当前正在接待的会话数
 	 }
 	 ]
 	 }

+ 3 - 3
Thinkphp/Wechatauth.class.php

@@ -7,8 +7,7 @@
  *  get_login_code() 获取登陆授权码, 通过授权码才能获取二维码
  *  get_code_image($code='') 将上面获取的授权码转换为图片二维码
  *  verify_code() 鉴定是否登陆成功,返回200为最终授权成功.
- *  get_login_cookie() 鉴定成功后调用此方法即可获取用户基本信息
- *  sendNews($account,$title,$summary,$content,$pic,$srcurl='') 向一个微信账户发送图文信息
+ *  get_login_info() 鉴定成功后调用此方法即可获取用户基本信息
  *  get_avatar($url) 获取用户头像图片数据
  *  @author dodge <dodgepudding@gmail.com>
  *  @link https://github.com/dodgepudding/wechat-php-sdk
@@ -19,6 +18,7 @@ include "Snoopy.class.php";
 class Wechatauth
 {
 	private $cookie;
+	private $skey;
 	private $_cookiename;
 	private $_cookieexpired = 3600;
 	private $_account = 'test';
@@ -93,7 +93,7 @@ class Wechatauth
 		}
 		return $result;
 	}
-	
+
 	/**
 	 * 通过授权码获取对应的二维码图片地址
 	 * @param string $code

+ 69 - 67
Thinkphp/Wechatext.class.php

@@ -10,6 +10,7 @@
  *  sendNews($id,$msgid) 发送图文消息
  *  getNewsList($page,$pagesize) 获取图文信息列表
  *  uploadFile($filepath,$type) 上传附件,包括图片/音频/视频
+ *  addPreview($title,$author,$summary,$content,$photoid,$srcurl='')   创建新的图文信息 
  *  getFileList($type,$page,$pagesize) 获取素材库文件列表
  *  sendImage($id,$fid) 发送图片消息
  *  sendAudio($id,$fid) 发送音频消息
@@ -39,7 +40,7 @@ class Wechatext
 	private $debug;
 	private $_logcallback;
 	private $_token;
-		
+	
 	public function __construct($options)
 	{
 		$this->_account = isset($options['account'])?$options['account']:'';
@@ -67,7 +68,7 @@ class Wechatext
 		$post['ajax'] = 1;
         $send_snoopy->referer = "https://mp.weixin.qq.com/cgi-bin/singlesendpage?t=message/send&action=index&tofakeid=$id&token={$this->_token}&lang=zh_CN";
 		$send_snoopy->rawheaders['Cookie']= $this->cookie;
-		$submit = "http://mp.weixin.qq.com/cgi-bin/singlesend?t=ajax-response";
+		$submit = "https://mp.weixin.qq.com/cgi-bin/singlesend?t=ajax-response";
 		$send_snoopy->submit($submit,$post);
 		$this->log($send_snoopy->results);
 		return $send_snoopy->results;
@@ -183,7 +184,7 @@ class Wechatext
 		}
 		return false;
 	}
-		
+	
 	/**
 	 * 获取图文信息列表
 	 * @param $page 页码(从0开始)
@@ -207,7 +208,7 @@ class Wechatext
 		} 
 		return false;
 	}
-
+	
 	/**
 	 * 获取与指定用户的对话内容
 	 * @param  $fakeid
@@ -278,6 +279,55 @@ class Wechatext
 	}
 	
 	/**
+	 * 创建图文消息
+	 * @param array $title 标题
+	 * @param array $summary 摘要
+	 * @param array $content 内容
+	 * @param array $photoid 素材库里的图片id(可通过uploadFile上传后获取)
+	 * @param array $srcurl 原文链接
+	 * @return json
+	 */
+	public function addPreview($title,$author,$summary,$content,$photoid,$srcurl='') {
+		$send_snoopy = new Snoopy;
+		$send_snoopy->referer = 'https://mp.weixin.qq.com/cgi-bin/operate_appmsg?lang=zh_CN&sub=edit&t=wxm-appmsgs-edit-new&type=10&subtype=3&token='.$this->_token;
+		
+		$submit = "https://mp.weixin.qq.com/cgi-bin/operate_appmsg?lang=zh_CN&t=ajax-response&sub=create&token=".$this->_token;
+		$send_snoopy->rawheaders['Cookie']= $this->cookie;
+		
+		$send_snoopy->set_submit_normal();
+		$post = array(
+				'token'=>$this->_token,
+				'type'=>10,
+				'lang'=>'zh_CN',
+				'sub'=>'create',
+				'ajax'=>1,
+				'AppMsgId'=>'',				
+				'error'=>'false',
+		);
+		if (count($title)==count($author)&&count($title)==count($summary)&&count($title)==count($content)&&count($title)==count($photoid))
+		{
+			$i = 0;
+			foreach($title as $v) {
+				$post['title'.$i] = $title[$i];
+				$post['author'.$i] = $author[$i];
+				$post['digest'.$i] = $summary[$i];
+				$post['content'.$i] = $content[$i];
+				$post['fileid'.$i] = $photoid[$i];
+				if ($srcurl[$i]) $post['sourceurl'.$i] = $srcurl[$i];
+				
+				$i++;
+				}
+		}
+		$post['count'] = $i;
+		$post['token'] = $this->_token;
+		$send_snoopy->submit($submit,$post);
+		$tmp = $send_snoopy->results;
+		$this->log('step2:'.$tmp);
+		$json = json_decode($tmp,true);
+		return $json;
+	}
+	
+	/**
 	 * 发送媒体文件
 	 * @param $id 用户的uid(即FakeId)
 	 * @param $fid 文件id
@@ -305,7 +355,7 @@ class Wechatext
 		else
 			return false;
 	}
-
+	
 	/**
 	 * 获取素材库文件列表
 	 * @param $type 文件类型: 2:图片 3:音频 4:视频
@@ -329,7 +379,7 @@ class Wechatext
 		else
 			return false;
 	}
-		
+	
 	/**
 	 * 发送图文信息,必须从库里选取文件ID发送
 	 * @param  string $id      用户的uid(即FakeId)
@@ -361,55 +411,6 @@ class Wechatext
 	}
 	
 	/**
-	 * 创建图文消息
-	 * @param array $title 标题
-	 * @param array $summary 摘要
-	 * @param array $content 内容
-	 * @param array $photoid 素材库里的图片id(可通过uploadFile上传后获取)
-	 * @param array $srcurl 原文链接
-	 * @return json
-	 */
-	public function addPreview($title,$author,$summary,$content,$photoid,$srcurl='') {
-		$send_snoopy = new Snoopy;
-		$send_snoopy->referer = 'https://mp.weixin.qq.com/cgi-bin/operate_appmsg?lang=zh_CN&sub=edit&t=wxm-appmsgs-edit-new&type=10&subtype=3&token='.$this->_token;
-	
-		$submit = "https://mp.weixin.qq.com/cgi-bin/operate_appmsg?lang=zh_CN&t=ajax-response&sub=create&token=".$this->_token;
-		$send_snoopy->rawheaders['Cookie']= $this->cookie;
-	
-		$send_snoopy->set_submit_normal();
-		$post = array(
-				'token'=>$this->_token,
-				'type'=>10,
-				'lang'=>'zh_CN',
-				'sub'=>'create',
-				'ajax'=>1,
-				'AppMsgId'=>'',				
-				'error'=>'false',
-		);
-		if (count($title)==count($author)&&count($title)==count($summary)&&count($title)==count($content)&&count($title)==count($photoid))
-		{
-			$i = 0;
-			foreach($title as $v) {
-				$post['title'.$i] = $title[$i];
-				$post['author'.$i] = $author[$i];
-				$post['digest'.$i] = $summary[$i];
-				$post['content'.$i] = $content[$i];
-				$post['fileid'.$i] = $photoid[$i];
-				if ($srcurl[$i]) $post['sourceurl'.$i] = $srcurl[$i];
-	
-				$i++;
-			}
-		}
-		$post['count'] = $i;
-		$post['token'] = $this->_token;
-		$send_snoopy->submit($submit,$post);
-		$tmp = $send_snoopy->results;
-		$this->log('step2:'.$tmp);
-		$json = json_decode($tmp,true);
-		return $json;
-	}
-		
-	/**
 	 * 发送预览图文消息
 	 * @param string $account 账户名称(user_name)
 	 * @param string $title 标题
@@ -477,7 +478,7 @@ class Wechatext
 		$send_snoopy = new Snoopy;
 		$send_snoopy->rawheaders['Cookie']= $this->cookie;
 		$send_snoopy->referer = "https://mp.weixin.qq.com/cgi-bin/getmessage?t=wxm-message&lang=zh_CN&count=50&token=".$this->_token;
-		$url = "https://mp.weixin.qq.com/cgi-bin/getheadimg?fakeid=$fakeid&token=".$this->_token."&lang=zh_CN";
+		$url = "https://mp.weixin.qq.com/misc/getheadimg?fakeid=$fakeid&token=".$this->_token."&lang=zh_CN";
 		$send_snoopy->fetch($url);
 		$result = $send_snoopy->results;
 		$this->log('Head image:'.$fakeid.'; length:'.strlen($result));
@@ -486,7 +487,7 @@ class Wechatext
 		}
 		return $result;
 	}
-	
+
 	/**
 	 * 获取消息更新数目
 	 * @param int $lastid 最近获取的消息ID,为0时获取总消息数目
@@ -616,7 +617,7 @@ class Wechatext
 		if (!isset($result['base_resp']) || $result['base_resp']['ret'] != 0) {
 			return false;
 		}
-		
+        
 		foreach ($snoopy->headers as $key => $value) {
 			$value = trim($value);
 			if(preg_match('/^set-cookie:[\s]+([^=]+)=([^;]+)/i', $value,$match))
@@ -650,19 +651,19 @@ class Wechatext
 	public function getCookie($filename){
 		$data = S($filename);
 		if($data){
+			$login=json_decode($data,true);
 			$send_snoopy = new Snoopy; 
-			$send_snoopy->rawheaders['Cookie']= $cookie;
+			$send_snoopy->rawheaders['Cookie']= $login['cookie'];
 			$send_snoopy->maxredirs = 0;
-			$url = "https://mp.weixin.qq.com/cgi-bin/indexpage?t=wxm-index&lang=zh_CN";
+			$url = "https://mp.weixin.qq.com/cgi-bin/home?t=home/index&lang=zh_CN&token=".$login['token'];
 			$send_snoopy->fetch($url);
-			$header = implode(',',$send_snoopy->headers);
+			$header = $send_snoopy->headers;
 			$this->log('header:'.print_r($send_snoopy->headers,true));
-			preg_match("/token=(\d+)/i",$header,$matches);
-			if(empty($matches)){
+			if( strstr($header[3], 'EXPIRED')){
 				return $this->login();
 			}else{
-				$this->_token = $matches[1];
-				return $data;
+				$this->_token =$login['token'];
+				return $login['cookie'];
 			}
 		}else{
 			return $this->login();
@@ -671,13 +672,14 @@ class Wechatext
 
 	/**
 	 * 验证cookie的有效性
-	 * @return [type] [description]
+	 * @return bool
 	 */
 	public function checkValid()
 	{
+		if (!$this->cookie || !$this->_token) return false;
 		$send_snoopy = new Snoopy; 
 		$post = array('ajax'=>1,'token'=>$this->_token);
-		$submit = "http://mp.weixin.qq.com/cgi-bin/getregions?id=1017&t=ajax-getregions&lang=zh_CN";
+		$submit = "https://mp.weixin.qq.com/cgi-bin/getregions?id=1017&t=ajax-getregions&lang=zh_CN";
 		$send_snoopy->rawheaders['Cookie']= $this->cookie;
 		$send_snoopy->submit($submit,$post);
 		$result = $send_snoopy->results;

+ 1 - 1
snoopy.class.php

@@ -1221,7 +1221,7 @@ class Snoopy
 		if (count($formvars) == 0 && count($formfiles) == 0)
 			return;
 		if (is_string($formvars)) return $formvars;
-		if(count($formvars) == 1) return $formvars[0];
+		if((count($formvars) == 1) && isset($formvars[0])) return $formvars[0];
 		switch ($this->_submit_type) {
 			case "application/x-www-form-urlencoded":
 				reset($formvars);

+ 240 - 72
wechat.class.php

@@ -30,6 +30,7 @@
  *   		default:
  *   			$weObj->text("help info")->reply();
  *   }
+ *   
  *   //获取菜单操作:
  *   $menu = $weObj->getMenu();
  *   //设置菜单
@@ -39,7 +40,7 @@
  *   				array('type'=>'click','name'=>'最新消息','key'=>'MENU_KEY_NEWS'),
  *   				array('type'=>'view','name'=>'我要搜索','url'=>'http://www.baidu.com'),
  *   				)
-  *  		);
+ *  		);
  *   $result = $weObj->createMenu($newmenu);
  */
 class Wechat
@@ -63,15 +64,19 @@ class Wechat
 	const QR_SCENE = 0;
 	const QR_LIMIT_SCENE = 1;
 	const QRCODE_IMG_URL='https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=';
+	const SHORT_URL='/shorturl?';
 	const USER_GET_URL='/user/get?';
 	const USER_INFO_URL='/user/info?';
+	const USER_UPDATEREMARK_URL='/user/info/updateremark?';	
 	const GROUP_GET_URL='/groups/get?';
+	const USER_GROUP_URL='/groups/getid?';
 	const GROUP_CREATE_URL='/groups/create?';
 	const GROUP_UPDATE_URL='/groups/update?';
 	const GROUP_MEMBER_UPDATE_URL='/groups/members/update?';
 	const CUSTOM_SEND_URL='/message/custom/send?';
 	const MEDIA_UPLOADNEWS_URL = '/media/uploadnews?';
 	const MASS_SEND_URL = '/message/mass/send?';
+	const Templat_SEND_URL = '/message/template/send?';
 	const MASS_SEND_GROUP_URL = '/message/mass/sendall?';
 	const MASS_DELETE_URL = '/message/mass/delete?';
 	const UPLOAD_MEDIA_URL = 'http://file.api.weixin.qq.com/cgi-bin';
@@ -82,6 +87,7 @@ class Wechat
 	const OAUTH_TOKEN_URL = '/access_token?';
 	const OAUTH_REFRESH_URL = '/refresh_token?';
 	const OAUTH_USERINFO_URL = 'https://api.weixin.qq.com/sns/userinfo?';
+	const OAUTH_AUTH_URL = 'https://api.weixin.qq.com/sns/auth?';
 	const PAY_DELIVERNOTIFY = 'https://api.weixin.qq.com/pay/delivernotify?';
 	const PAY_ORDERQUERY = 'https://api.weixin.qq.com/pay/orderquery?';
 	const CUSTOM_SERVICE_GET_RECORD = '/customservice/getrecord?';
@@ -221,7 +227,7 @@ class Wechat
 	{
 		return $this->_receive;
 	}
-		
+	
 	/**
 	 * 获取消息发送者
 	 */
@@ -351,7 +357,7 @@ class Wechat
 	}
 	
 	/**
-	 * 获取接收语推送
+	 * 获取接收语推送
 	 */
 	public function getRevVoice(){
 		if (isset($this->_receive['MediaId'])){
@@ -380,23 +386,44 @@ class Wechat
 	 * 获取接收TICKET
 	 */
 	public function getRevTicket(){
-	if (isset($this->_receive['Ticket'])){
-		return $this->_receive['Ticket'];
-	} else
-		return false;
-    }
+		if (isset($this->_receive['Ticket'])){
+			return $this->_receive['Ticket'];
+		} else
+			return false;
+	}
+	
+	/**
+	* 获取二维码的场景值
+	*/
+	public function getRevSceneId (){
+		if (isset($this->_receive['EventKey'])){
+			return str_replace('qrscene_','',$this->_receive['EventKey']);
+		} else{
+			return false;
+		}
+	}
+	
+	/**
+	* 获取模板消息ID
+	* 经过验证,这个和普通的消息MsgId不一样
+	*/
+	public function getRevTplMsgID(){
+		if (isset($this->_receive['MsgID'])){
+			return $this->_receive['MsgID'];
+		} else 
+			return false;
+	}
+	
+	/**
+	* 获取模板消息发送状态
+	*/
+	public function getRevStatus(){
+		if (isset($this->_receive['Status'])){
+			return $this->_receive['Status'];
+		} else 
+			return false;
+	}
 	
-    /**
-     * 获取二维码的场景值
-     */
-    public function getRevSceneId (){
-    	if (isset($this->_receive['EventKey'])){
-    		return str_replace('qrscene_','',$this->_receive['EventKey']);
-    	} else{
-    		return false;
-    	}
-    }
-    
 	public static function xmlSafeStr($str)
 	{   
 		return '<![CDATA['.preg_replace("/[\\x00-\\x08\\x0b-\\x0c\\x0e-\\x1f]/",'',$str).']]>';   
@@ -526,7 +553,7 @@ class Wechat
 	/**
 	 * 
 	 * 回复微信服务器, 此函数支持链式操作
-	 * @example $this->text('msg tips')->reply();
+	 * Example: $this->text('msg tips')->reply();
 	 * @param string $msg 要发送的信息, 默认取$this->_msg
 	 * @param bool $return 是否返回信息而不抛出到浏览器 默认:否
 	 */
@@ -542,7 +569,6 @@ class Wechat
 			echo $xmldata;
 	}
 	
-
 	/**
 	 * GET 请求
 	 * @param string $url
@@ -638,7 +664,7 @@ class Wechat
 		//TODO: remove cache
 		return true;
 	}
-		
+
 	/**
 	 * 微信api不支持中文转义的json结构
 	 * @param array $arr
@@ -686,38 +712,38 @@ class Wechat
 			return '[' . $json . ']'; //Return numerical JSON
 		return '{' . $json . '}'; //Return associative JSON
 	}
-	
+
 	/**
 	 * 创建菜单
 	 * @param array $data 菜单数组数据
 	 * example:
-	 {
-	 "button":[
-	 {
-	 "type":"click",
-	 "name":"今日歌曲",
-	 "key":"MENU_KEY_MUSIC"
-	 },
-	 {
-	 "type":"view",
-	 "name":"歌手简介",
-	 "url":"http://www.qq.com/"
-	 },
-	 {
-	 "name":"菜单",
-	 "sub_button":[
-	 {
-	 "type":"click",
-	 "name":"hello word",
-	 "key":"MENU_KEY_MENU"
-	 },
-	 {
-	 "type":"click",
-	 "name":"赞一下我们",
-	 "key":"MENU_KEY_GOOD"
-	 }]
-	 }]
-	 }
+		  {
+		     "button":[
+		     {	
+		          "type":"click",
+		          "name":"今日歌曲",
+		          "key":"MENU_KEY_MUSIC"
+		      },
+		      {
+		           "type":"view",
+		           "name":"歌手简介",
+		           "url":"http://www.qq.com/"
+		      },
+		      {
+		           "name":"菜单",
+		           "sub_button":[
+		            {
+		               "type":"click",
+		               "name":"hello word",
+		               "key":"MENU_KEY_MENU"
+		            },
+		            {
+		               "type":"click",
+		               "name":"赞一下我们",
+		               "key":"MENU_KEY_GOOD"
+		            }]
+		       }]
+		 }
 	 */
 	public function createMenu($data){
 		if (!$this->access_token && !$this->checkAuth()) return false;
@@ -777,8 +803,10 @@ class Wechat
 
 	/**
 	 * 上传多媒体文件
-	 * @param array $data 消息结构{ "touser":[ "OPENID1", "OPENID2" ], "mpnews":{ "media_id":"123dsdajkasd231jhksad" }, "msgtype":"mpnews" }
-	 * @return raw data
+	 * 注意:数组的键值任意,但文件名前必须加@,使用单引号以避免本地路径斜杠被转义
+	 * @param array $data {"media":'@Path\filename.jpg'}
+	 * @param type 类型:图片:image 语音:voice 视频:video 缩略图:thumb
+	 * @return boolean|array
 	 */
 	public function uploadMedia($data, $type){
 		if (!$this->access_token && !$this->checkAuth()) return false;
@@ -906,7 +934,7 @@ class Wechat
 	 * @param int $scene_id 自定义追踪id
 	 * @param int $type 0:临时二维码;1:永久二维码(此时expire参数无效)
 	 * @param int $expire 临时二维码有效期,最大为1800秒
-	 * @return array('ticket'=>'qrcode字串','expire_seconds'=>1800)
+	 * @return array('ticket'=>'qrcode字串','expire_seconds'=>1800,'url'=>'二维码图片解析后的地址')
 	 */
 	public function getQRCode($scene_id,$type=0,$expire=1800){
 		if (!$this->access_token && !$this->checkAuth()) return false;
@@ -942,6 +970,31 @@ class Wechat
 	}
 	
 	/**
+	 * 长链接转短链接接口
+	 * @param string $long_url 传入要转换的长url
+	 * @return boolean|string url 成功则返回转换后的短url
+	 */
+	public function getShortUrl($long_url){
+	    if (!$this->access_token && !$this->checkAuth()) return false;
+	    $data = array(
+            'action'=>'long2short',
+            'long_url'=>$long_url
+	    );
+	    $result = $this->http_post(self::API_URL_PREFIX.self::SHORT_URL.'access_token='.$this->access_token,self::json_encode($data));
+	    if ($result)
+	    {
+	        $json = json_decode($result,true);
+	        if (!$json || !empty($json['errcode'])) {
+	            $this->errCode = $json['errcode'];
+	            $this->errMsg = $json['errmsg'];
+	            return false;
+	        }
+	        return $json['short_url'];
+	    }
+	    return false;
+	}
+
+	/**
 	 * 批量获取关注用户列表
 	 * @param unknown $next_openid
 	 */
@@ -981,6 +1034,32 @@ class Wechat
 		}
 		return false;
 	}
+
+	/**
+	 * 设置用户备注名
+	 * @param string $openid
+	 * @param string $remark 备注名
+	 * @return boolean|array
+	 */
+	public function updateUserRemark($openid,$remark){
+	    if (!$this->access_token && !$this->checkAuth()) return false;
+	    $data = array(
+			'openid'=>$openid,
+			'remark'=>$remark
+	    );
+	    $result = $this->http_post(self::API_URL_PREFIX.self::USER_UPDATEREMARK_URL.'access_token='.$this->access_token,$data);
+	    if ($result)
+	    {
+	        $json = json_decode($result,true);
+			if (!$json || !empty($json['errcode'])) {
+				$this->errCode = $json['errcode'];
+				$this->errMsg = $json['errmsg'];
+				return false;
+			}
+			return $json;
+	    }
+	    return false;
+	}
 	
 	/**
 	 * 获取用户分组列表
@@ -1003,6 +1082,30 @@ class Wechat
 	}
 	
 	/**
+	 * 获取用户所在分组
+	 * @param string $openid
+	 * @return boolean|int 成功则返回用户分组id
+	 */
+	public function getUserGroup($openid){
+	    if (!$this->access_token && !$this->checkAuth()) return false;
+	    $data = array(
+	            'openid'=>$openid
+	    );
+	    $result = $this->http_post(self::API_URL_PREFIX.self::USER_GROUP_URL.'access_token='.$this->access_token,self::json_encode($data));
+	    if ($result)
+	    {
+	        $json = json_decode($result,true);
+	        if (!$json || !empty($json['errcode'])) {
+	            $this->errCode = $json['errcode'];
+	            $this->errMsg = $json['errmsg'];
+	            return false;
+	        } else 
+                if (isset($json['groupid'])) return $json['groupid'];
+	    }
+	    return false;
+	}
+    
+	/**
 	 * 新增自定分组
 	 * @param string $name 分组名称
 	 * @return boolean|array
@@ -1107,7 +1210,7 @@ class Wechat
 		return self::OAUTH_PREFIX.self::OAUTH_AUTHORIZE_URL.'appid='.$this->appid.'&redirect_uri='.urlencode($callback).'&response_type=code&scope='.$scope.'&state='.$state.'#wechat_redirect';
 	}
 	
-	/*
+	/**
 	 * 通过code获取Access Token
 	 * @return array {access_token,expires_in,refresh_token,openid,scope}
 	 */
@@ -1170,7 +1273,27 @@ class Wechat
 		}
 		return false;
 	}
-	
+
+	/**
+	 * 检验授权凭证是否有效
+	 * @param string $access_token
+	 * @param string $openid
+	 * @return boolean 是否有效
+	 */
+	public function getOauthAuth($access_token,$openid){
+	    $result = $this->http_get(self::OAUTH_AUTH_URL.'access_token='.$access_token.'&openid='.$openid);
+	    if ($result)
+	    {
+	        $json = json_decode($result,true);
+	        if (!$json || !empty($json['errcode'])) {
+	            $this->errCode = $json['errcode'];
+	            $this->errMsg = $json['errmsg'];
+	            return false;
+	        } else
+	          if ($json['errcode'==0) return true;
+	    }
+	    return false;
+	}
 	
 	/**
 	 * 获取签名
@@ -1319,7 +1442,7 @@ class Wechat
 		return false;
 	}
 	
-	/*
+	/**
 	 * 查询订单信息
 	 * @param string $out_trade_no 订单号
 	 * @return boolean|array
@@ -1348,10 +1471,11 @@ class Wechat
 			return $json["order_info"];
 		}
 		return false;
-	}	
+	}
 	
 	/**
 	 * 获取收货地址JS的签名
+	 * @tutorial 参考weixin.js脚本的WeixinJS.editAddress方法调用
 	 * @param string $appId
 	 * @param string $url
 	 * @param int $timeStamp
@@ -1377,6 +1501,51 @@ class Wechat
 	}
 	
 	/**
+	 * 发送模板消息
+	 * @param array $data 消息结构
+	 * {
+			"touser":"OPENID",
+			"template_id":"ngqIpbwh8bUfcSsECmogfXcV14J0tQlEpBO27izEYtY",
+			"url":"http://weixin.qq.com/download",
+			"topcolor":"#FF0000",
+			"data":{
+				"参数名1": {
+					"value":"参数",
+					"color":"#173177"	 //参数颜色
+					},
+				"Date":{
+					"value":"06月07日 19时24分",
+					"color":"#173177"
+					},
+				"CardNumber":{
+					"value":"0426",
+					"color":"#173177"
+					},
+				"Type":{
+					"value":"消费",
+					"color":"#173177"
+					}
+			}
+		}
+	 * @return boolean|array
+	 */
+	public function sendTemplateMessage($data){
+		if (!$this->access_token && !$this->checkAuth()) return false;
+		$result = $this->http_post(self::API_URL_PREFIX.self::Templat_SEND_URL.'access_token='.$this->access_token,self::json_encode($data));
+		
+		if($result){
+			$json = json_decode($result,true);
+			if (!$json || !empty($json['errcode'])) {
+				$this->errCode = $json['errcode'];
+				$this->errMsg = $json['errmsg'];
+				return false;
+			}
+			return $json;
+		}
+		return false;
+	}
+	
+	/**
 	 * 获取多客服会话记录
 	 * @param array $data 数据结构{"starttime":123456789,"endtime":987654321,"openid":"OPENID","pagesize":10,"pageindex":1,}
 	 * @return boolean|array
@@ -1419,8 +1588,8 @@ class Wechat
 	
 	/**
 	 * 获取多客服客服基本信息
-	 * @param 
-	 * @return array
+	 * 
+	 * @return boolean|array
 	 */
 	public function getCustomServiceKFlist(){
 		if (!$this->access_token && !$this->checkAuth()) return false;
@@ -1440,18 +1609,18 @@ class Wechat
 	
 	/**
 	 * 获取多客服在线客服接待信息
-	 * @param 
-	 * @return array {
-    "kf_online_list": [
-        {
-            "kf_account": "test1@test", //客服账号@微信别名
-            "status": 1,				//客服在线状态 1:pc在线,2:手机在线,若pc和手机同时在线则为 1+2=3
-            "kf_id": "1001",			//客服工号
-            "auto_accept": 0,			//客服设置的最大自动接入数
-            "accepted_case": 1 			//客服当前正在接待的会话数
-        }
-    ]
-}
+	 * 
+	 * @return boolean|array {
+	 "kf_online_list": [
+	 {
+	 "kf_account": "test1@test",	//客服账号@微信别名
+	 "status": 1,			//客服在线状态 1:pc在线,2:手机在线,若pc和手机同时在线则为 1+2=3
+	 "kf_id": "1001",		//客服工号
+	 "auto_accept": 0,		//客服设置的最大自动接入数
+	 "accepted_case": 1		//客服当前正在接待的会话数
+	 }
+	 ]
+	 }
 	 */
 	public function getCustomServiceOnlineKFlist(){
 		if (!$this->access_token && !$this->checkAuth()) return false;
@@ -1468,5 +1637,4 @@ class Wechat
 		}
 		return false;
 	}
-
 }

+ 77 - 2
wechat.js

@@ -7,7 +7,20 @@
  * 
  * 自定义分享使用:
  * WeixinJS.hideOptionMenu() 隐藏右上角按钮
+ * WeixinJS.showOptionMenu() 显示右上角按钮
  * WeixinJS.hideToolbar() 隐藏工具栏
+ * WeixinJS.showToolbar() 显示工具栏
+ * WeixinJS.getNetworkType() 获取网络状态
+ * WeixinJS.closeWindow() 关闭窗口
+ * WeixinJS.scanQRCode() 扫描二维码
+ * WeixinJS.openUrlByExtBrowser(url) 使用浏览器打开网址
+ * WeixinJS.jumpToBizProfile(username) 跳转到指定公众账号页面
+ * WeixinJS.sendEmail(title,content) 发送邮件
+ * WeixinJS.openProductView(latitude,longitude,name,address,scale,infoUrl) 查看地图
+ * WeixinJS.addContact(username) 添加微信账号
+ * WeixinJS.imagePreview(urls,current) 调出微信内图片预览
+ * WeixinJS.payCallback(appId,package,timeStamp,nonceStr,signType,paySign,callback) 微信JsApi支付接口
+ * WeixinJS.editAddress(appId,addrSign,timeStamp,nonceStr,callback) 微信JsApi支付接口
  * 自定义分享内容数据格式:
  * var dataForWeixin={
 	   appId:"",
@@ -80,29 +93,91 @@
  */
 
 WeixinJS = typeof WeixinJS!='undefined' || {};
+//隐藏右上角按钮
 WeixinJS.hideOptionMenu = function() {
 	document.addEventListener('WeixinJSBridgeReady', function onBridgeReady() {
 		if (typeof WeixinJSBridge!='undefined')	WeixinJSBridge.call('hideOptionMenu');
 	});
 };
+//显示右上角按钮
+WeixinJS.showOptionMenu = function() {
+	document.addEventListener('WeixinJSBridgeReady', function onBridgeReady() {
+		if (typeof WeixinJSBridge!='undefined')	WeixinJSBridge.call('showOptionMenu');
+	});
+};
+//隐藏底部导航栏
 WeixinJS.hideToolbar = function() {
 	document.addEventListener('WeixinJSBridgeReady', function onBridgeReady() {
 		if (typeof WeixinJSBridge!='undefined') WeixinJSBridge.call('hideToolbar');
 	});
 };
+//显示底部导航栏
+WeixinJS.showToolbar = function() {
+	document.addEventListener('WeixinJSBridgeReady', function onBridgeReady() {
+		if (typeof WeixinJSBridge!='undefined') WeixinJSBridge.call('showToolbar');
+	});
+};
+//网页获取用户网络状态
+netType={"network_type:wifi":"wifi网络","network_type:edge":"非wifi,包含3G/2G","network_type:fail":"网络断开连接","network_type:wwan":"2g或者3g"};
 WeixinJS.getNetworkType = function(callback) {
 	document.addEventListener('WeixinJSBridgeReady', function onBridgeReady() {
 		if (typeof WeixinJSBridge!='undefined') WeixinJSBridge.invoke('getNetworkType',{},
 		function(res){
 			//result: network_type:wifi,network_type:edge,network_type:fail,network_type:wwan
+			//netType[e.err_msg]
 			callback(res.err_msg);
 	    });
 	});
 };
-
+//关闭窗口
 WeixinJS.closeWindow = function() {
 	if (typeof WeixinJSBridge!='undefined') WeixinJSBridge.invoke("closeWindow", {});
 };
+//扫描二维码
+WeixinJS.scanQRCode = function() {
+	if (typeof WeixinJSBridge!='undefined') WeixinJSBridge.invoke("scanQRCode", {});
+};
+//使用浏览器打开网址
+WeixinJS.openUrlByExtBrowser=function(url){
+	if (typeof WeixinJSBridge!='undefined') WeixinJSBridge.invoke("openUrlByExtBrowser",{"url" : url});
+};
+//跳转到指定公众账号页面
+WeixinJS.jumpToBizProfile=function(username){
+	if (typeof WeixinJSBridge!='undefined') WeixinJSBridge.invoke("jumpToBizProfile",{"tousername" : username});
+};
+//发送邮件
+WeixinJS.sendEmail=function(title,content){
+	if (typeof WeixinJSBridge!='undefined') WeixinJSBridge.invoke("sendEmail",{
+	    "title" : title,
+	    "content" : content
+	});
+};
+//查看地图
+WeixinJS.openProductView=function(latitude,longitude,name,address,scale,infoUrl){
+	if (typeof WeixinJSBridge!='undefined') WeixinJSBridge.invoke("openProductView",{
+	    "latitude" : latitude, //纬度
+	    "longitude" : longitude, //经度
+	    "name" : name, //名称
+	    "address" : address, //地址
+	    "scale" : scale, //地图缩放级别
+	    "infoUrl" : infoUrl, //查看位置界面底部的超链接            
+	});
+};
+//添加微信账号
+WeixinJS.addContact=function weixinAddContact(username){
+    if (typeof WeixinJSBridge!='undefined') WeixinJSBridge.invoke("addContact", {
+    	"webtype": "1",
+    	"username": username
+    }, function(e) {
+	    WeixinJSBridge.log(e.err_msg);
+	    //e.err_msg:add_contact:added 已经添加
+	    //e.err_msg:add_contact:cancel 取消添加
+	    //e.err_msg:add_contact:ok 添加成功
+	    if(e.err_msg == 'add_contact:added' || e.err_msg == 'add_contact:ok'){
+	            //关注成功,或者已经关注过
+	    }
+    });
+};
 
 /**
  * 调出微信内图片预览scrollview
@@ -133,7 +208,7 @@ WeixinJS.payCallback = function(appId,package,timeStamp,nonceStr,signType,paySig
     	callback(res);
     });
 };
-
+//编辑收货地址
 WeixinJS.editAddress = function(appId,addrSign,timeStamp,nonceStr,callback){
 	var postdata = {
 			"appId" : appId.toString(),

+ 1 - 2
wechatauth.class.php

@@ -7,8 +7,7 @@
  *  get_login_code() 获取登陆授权码, 通过授权码才能获取二维码
  *  get_code_image($code='') 将上面获取的授权码转换为图片二维码
  *  verify_code() 鉴定是否登陆成功,返回200为最终授权成功.
- *  get_login_cookie() 鉴定成功后调用此方法即可获取用户基本信息
- *  sendNews($account,$title,$summary,$content,$pic,$srcurl='') 向一个微信账户发送图文信息
+ *  get_login_info() 鉴定成功后调用此方法即可获取用户基本信息
  *  get_avatar($url) 获取用户头像图片数据
  *  @author dodge <dodgepudding@gmail.com>
  *  @link https://github.com/dodgepudding/wechat-php-sdk

+ 8 - 12
wechatext.class.php

@@ -5,7 +5,7 @@
  *  注: 用户id为通过getMsg()方法获取的FakeId值
  *  主要实现如下功能:
  *  send($id,$content) 向某用户id发送微信文字信息
- *  getUserList($page,$pagesize,$group) 获取用户信息
+ *  getUserList($page,$pagesize,$groupid) 获取用户信息
  *  getGroupList($page,$pagesize) 获取群组信息
  *  sendNews($id,$msgid) 发送图文消息
  *  getNewsList($page,$pagesize) 获取图文信息列表
@@ -230,7 +230,6 @@ class Wechatext
 		return false;
 	}
 	
-	
 	/**
 	 * 发送图文信息,必须从图文库里选取消息ID发送
 	 * @param  string $id      用户的uid(即FakeId)
@@ -602,10 +601,6 @@ class Wechatext
 	 * 模拟登录获取cookie
 	 * @return [type] [description]
 	 */
-	/**
-	 * 模拟登录获取cookie
-	 * @return [type] [description]
-	 */
 	public function login(){
 		$snoopy = new Snoopy; 
 		$submit = "https://mp.weixin.qq.com/cgi-bin/login?lang=zh_CN";
@@ -664,19 +659,20 @@ class Wechatext
 		} else
 			$data = '';
 		if($data){
-			$denglu=json_decode($data,true);
-			$send_snoopy = new Snoopy; 
-			$send_snoopy->rawheaders['Cookie']= $denglu[cookie];
+			$login=json_decode($data,true);
+			$send_snoopy = new Snoopy;
+			$send_snoopy->rawheaders['Cookie']= $login['cookie'];
 			$send_snoopy->maxredirs = 0;
-			$url = "https://mp.weixin.qq.com/cgi-bin/home?t=home/index&lang=zh_CN&token=".$denglu[token];
+			$url = "https://mp.weixin.qq.com/cgi-bin/home?t=home/index&lang=zh_CN&token=".$login['token'];
 			$send_snoopy->fetch($url);
 			$header = $send_snoopy->headers;
+			$this->log('header:'.print_r($send_snoopy->headers,true));
 			if( strstr($header[3], 'EXPIRED')){
 				return $this->login();
 			}else{
-				$this->_token =$denglu[token];
+				$this->_token =$login['token'];
 				$this->log('token:'.$this->_token);
-				return $denglu[cookie];
+				return $login['cookie'];
 			}
 		}else{
 			return $this->login();