binsee преди 10 години
родител
ревизия
2ad23432f6

+ 22 - 240
Thinkphp/Wechat.class.php

@@ -9,10 +9,7 @@
  *			'token'=>'tokenaccesskey', //填写你设定的key
  *			'encodingaeskey'=>'encodingaeskey', //填写加密用的EncodingAESKey
  *			'appid'=>'wxdk1234567890', //填写高级调用功能的app id
- *			'appsecret'=>'xxxxxxxxxxxxxxxxxxx', //填写高级调用功能的密钥
- *			'partnerid'=>'88888888', //财付通商户身份标识
- *			'partnerkey'=>'', //财付通商户权限密钥Key
- *			'paysignkey'=>'' //商户签名密钥Key
+ *			'appsecret'=>'xxxxxxxxxxxxxxxxxxx' //填写高级调用功能的密钥
  *		);
  *	 $weObj = new Wechat($options);
  *   $weObj->valid();
@@ -117,8 +114,6 @@ class Wechat
 	const OAUTH_REFRESH_URL = '/sns/oauth2/refresh_token?';
 	const OAUTH_USERINFO_URL = '/sns/userinfo?';
 	const OAUTH_AUTH_URL = '/sns/auth?';
-	const PAY_DELIVERNOTIFY = '/pay/delivernotify?';
-	const PAY_ORDERQUERY = '/pay/orderquery?';
 	///多客服相关地址
 	const CUSTOM_SERVICE_GET_RECORD = '/customservice/getrecord?';
 	const CUSTOM_SERVICE_GET_KFLIST = '/customservice/getkflist?';
@@ -185,9 +180,6 @@ class Wechat
 		$this->encodingAesKey = isset($options['encodingaeskey'])?$options['encodingaeskey']:'';
 		$this->appid = isset($options['appid'])?$options['appid']:'';
 		$this->appsecret = isset($options['appsecret'])?$options['appsecret']:'';
-		$this->partnerid = isset($options['partnerid'])?$options['partnerid']:'';
-		$this->partnerkey = isset($options['partnerkey'])?$options['partnerkey']:'';
-		$this->paysignkey = isset($options['paysignkey'])?$options['paysignkey']:'';
 		$this->debug = isset($options['debug'])?$options['debug']:false;
 		$this->_logcallback = isset($options['logcallback'])?$options['logcallback']:false;
 	}
@@ -1244,6 +1236,27 @@ class Wechat
 			return '[' . $json . ']'; //Return numerical JSON
 		return '{' . $json . '}'; //Return associative JSON
 	}
+	
+	/**
+	 * 获取签名
+	 * @param array $arrdata 签名数组
+	 * @param string $method 签名方法
+	 * @return boolean|string 签名值
+	 */
+	public function getSignature($arrdata,$method="sha1") {
+		if (!function_exists($method)) return false;
+		ksort($arrdata);
+		$paramstring = "";
+		foreach($arrdata as $key => $value)
+		{
+			if(strlen($paramstring) == 0)
+				$paramstring .= $key . "=" . $value;
+			else
+				$paramstring .= "&" . $key . "=" . $value;
+		}
+		$paySign = $method($paramstring);
+		return $paySign;
+	}
 
 	/**
 	 * 获取微信服务器IP地址列表
@@ -1982,237 +1995,6 @@ class Wechat
 	}
 
 	/**
-	 * 获取签名
-	 * @param array $arrdata 签名数组
-	 * @param string $method 签名方法
-	 * @return boolean|string 签名值
-	 */
-	public function getSignature($arrdata,$method="sha1") {
-		if (!function_exists($method)) return false;
-		ksort($arrdata);
-		$paramstring = "";
-		foreach($arrdata as $key => $value)
-		{
-			if(strlen($paramstring) == 0)
-				$paramstring .= $key . "=" . $value;
-			else
-				$paramstring .= "&" . $key . "=" . $value;
-		}
-		$paySign = $method($paramstring);
-		return $paySign;
-	}
-
-	/**
-	 * 生成随机字串
-	 * @param number $length 长度,默认为16,最长为32字节
-	 * @return string
-	 */
-	public function generateNonceStr($length=16){
-		// 密码字符集,可任意添加你需要的字符
-		$chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
-		$str = "";
-		for($i = 0; $i < $length; $i++)
-		{
-			$str .= $chars[mt_rand(0, strlen($chars) - 1)];
-		}
-		return $str;
-	}
-
-	/**
-	 * 生成原生支付url
-	 * @param number $productid 商品编号,最长为32字节
-	 * @return string
-	 */
-	public function createNativeUrl($productid){
-		    $nativeObj["appid"] = $this->appid;
-		    $nativeObj["appkey"] = $this->paysignkey;
-		    $nativeObj["productid"] = urlencode($productid);
-		    $nativeObj["timestamp"] = time();
-		    $nativeObj["noncestr"] = $this->generateNonceStr();
-		    $nativeObj["sign"] = $this->getSignature($nativeObj);
-		    unset($nativeObj["appkey"]);
-		    $bizString = "";
-		    foreach($nativeObj as $key => $value)
-		    {
-			if(strlen($bizString) == 0)
-				$bizString .= $key . "=" . $value;
-			else
-				$bizString .= "&" . $key . "=" . $value;
-		    }
-		    return "weixin://wxpay/bizpayurl?".$bizString;
-		    //weixin://wxpay/bizpayurl?sign=XXXXX&appid=XXXXXX&productid=XXXXXX&timestamp=XXXXXX&noncestr=XXXXXX
-	}
-
-
-	/**
-	 * 生成订单package字符串
-	 * @param string $out_trade_no 必填,商户系统内部的订单号,32个字符内,确保在商户系统唯一
-	 * @param string $body 必填,商品描述,128 字节以下
-	 * @param int $total_fee 必填,订单总金额,单位为分
-	 * @param string $notify_url 必填,支付完成通知回调接口,255 字节以内
-	 * @param string $spbill_create_ip 必填,用户终端IP,IPV4字串,15字节内
-	 * @param int $fee_type 必填,现金支付币种,默认1:人民币
-	 * @param string $bank_type 必填,银行通道类型,默认WX
-	 * @param string $input_charset 必填,传入参数字符编码,默认UTF-8,取值有UTF-8和GBK
-	 * @param string $time_start 交易起始时间,订单生成时间,格式yyyyMMddHHmmss
-	 * @param string $time_expire 交易结束时间,也是订单失效时间
-	 * @param int $transport_fee 物流费用,单位为分
-	 * @param int $product_fee 商品费用,单位为分,必须保证 transport_fee + product_fee=total_fee
-	 * @param string $goods_tag 商品标记,优惠券时可能用到
-	 * @param string $attach 附加数据,notify接口原样返回
-	 * @return string
-	 */
-	public function 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=""){
-			$arrdata = array("bank_type" => $bank_type, "body" => $body, "partner" => $this->partnerid, "out_trade_no" => $out_trade_no, "total_fee" => $total_fee, "fee_type" => $fee_type, "notify_url" => $notify_url, "spbill_create_ip" => $spbill_create_ip, "input_charset" => $input_charset);
-			if ($time_start)  $arrdata['time_start'] = $time_start;
-			if ($time_expire)  $arrdata['time_expire'] = $time_expire;
-			if ($transport_fee)  $arrdata['transport_fee'] = $transport_fee;
-			if ($product_fee)  $arrdata['product_fee'] = $product_fee;
-			if ($goods_tag)  $arrdata['goods_tag'] = $goods_tag;
-			if ($attach)  $arrdata['attach'] = $attach;
-			ksort($arrdata);
-			$paramstring = "";
-			foreach($arrdata as $key => $value)
-			{
-			if(strlen($paramstring) == 0)
-				$paramstring .= $key . "=" . $value;
-				else
-				$paramstring .= "&" . $key . "=" . $value;
-			}
-			$stringSignTemp = $paramstring . "&key=" . $this->partnerkey;
-			$signValue = strtoupper(md5($stringSignTemp));
-			$package = http_build_query($arrdata) . "&sign=" . $signValue;
-			return $package;
-	}
-
-	/**
-	 * 支付签名(paySign)生成方法
-	 * @param string $package 订单详情字串
-	 * @param string $timeStamp 当前时间戳(需与JS输出的一致)
-	 * @param string $nonceStr 随机串(需与JS输出的一致)
-	 * @return string 返回签名字串
-	 */
-	public function getPaySign($package, $timeStamp, $nonceStr){
-		$arrdata = array("appid" => $this->appid, "timestamp" => $timeStamp, "noncestr" => $nonceStr, "package" => $package, "appkey" => $this->paysignkey);
-		$paySign = $this->getSignature($arrdata);
-		return $paySign;
-	}
-
-	/**
-	 * 回调通知签名验证
-	 * @param array $orderxml 返回的orderXml的数组表示,留空则自动从post数据获取
-	 * @return boolean
-	 */
-	public function checkOrderSignature($orderxml=''){
-		if (!$orderxml) {
-			$postStr = file_get_contents("php://input");
-			if (!empty($postStr)) {
-				$orderxml = (array)simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
-			} else return false;
-		}
-		$arrdata = array('appid'=>$orderxml['AppId'],'appkey'=>$this->paysignkey,'timestamp'=>$orderxml['TimeStamp'],'noncestr'=>$orderxml['NonceStr'],'openid'=>$orderxml['OpenId'],'issubscribe'=>$orderxml['IsSubscribe']);
-		$paySign = $this->getSignature($arrdata);
-		if ($paySign!=$orderxml['AppSignature']) return false;
-		return true;
-	}
-
-	/**
-	 * 发货通知
-	 * @param string $openid 用户open_id
-	 * @param string $transid 交易单号
-	 * @param string $out_trade_no 第三方订单号
-	 * @param int $status 0:发货失败;1:已发货
-	 * @param string $msg 失败原因
-	 * @return boolean|array
-	 */
-	public function sendPayDeliverNotify($openid,$transid,$out_trade_no,$status=1,$msg='ok'){
-		if (!$this->access_token && !$this->checkAuth()) return false;
-		$postdata = array(
-				"appid"=>$this->appid,
-				"appkey"=>$this->paysignkey,
-				"openid"=>$openid,
-				"transid"=>strval($transid),
-				"out_trade_no"=>strval($out_trade_no),
-				"deliver_timestamp"=>strval(time()),
-				"deliver_status"=>strval($status),
-				"deliver_msg"=>$msg,
-		);
-		$postdata['app_signature'] = $this->getSignature($postdata);
-		$postdata['sign_method'] = 'sha1';
-		unset($postdata['appkey']);
-		$result = $this->http_post(self::API_BASE_URL_PREFIX.self::PAY_DELIVERNOTIFY.'access_token='.$this->access_token,self::json_encode($postdata));
-		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 string $out_trade_no 订单号
-	 * @return boolean|array
-	 */
-	public function getPayOrder($out_trade_no) {
-		if (!$this->access_token && !$this->checkAuth()) return false;
-		$sign = strtoupper(md5("out_trade_no=$out_trade_no&partner={$this->partnerid}&key={$this->partnerkey}"));
-		$postdata = array(
-				"appid"=>$this->appid,
-				"appkey"=>$this->paysignkey,
-				"package"=>"out_trade_no=$out_trade_no&partner={$this->partnerid}&sign=$sign",
-				"timestamp"=>strval(time()),
-		);
-		$postdata['app_signature'] = $this->getSignature($postdata);
-		$postdata['sign_method'] = 'sha1';
-		unset($postdata['appkey']);
-		$result = $this->http_post(self::API_BASE_URL_PREFIX.self::PAY_ORDERQUERY.'access_token='.$this->access_token,self::json_encode($postdata));
-		if ($result)
-		{
-			$json = json_decode($result,true);
-			if (!$json || !empty($json['errcode'])) {
-				$this->errCode = $json['errcode'];
-				$this->errMsg = $json['errmsg'].json_encode($postdata);
-				return false;
-			}
-			return $json["order_info"];
-		}
-		return false;
-	}
-
-	/**
-	 * 获取收货地址JS的签名
-	 * @tutorial 参考weixin.js脚本的WeixinJS.editAddress方法调用
-	 * @param string $appId
-	 * @param string $url
-	 * @param int $timeStamp
-	 * @param string $nonceStr
-	 * @param string $user_token
-	 * @return Ambigous <boolean, string>
-	 */
-	public function getAddrSign($url, $timeStamp, $nonceStr, $user_token=''){
-		if (!$user_token) $user_token = $this->user_token;
-		if (!$user_token) {
-			$this->errMsg = 'no user access token found!';
-			return false;
-		}
-		$url = htmlspecialchars_decode($url);
-		$arrdata = array(
-				'appid'=>$this->appid,
-				'url'=>$url,
-				'timestamp'=>strval($timeStamp),
-				'noncestr'=>$nonceStr,
-				'accesstoken'=>$user_token
-		);
-		return $this->getSignature($arrdata);
-	}
-
-	/**
 	 * 模板消息 设置所属行业
 	 * @param int $id1  公众号模板消息所属行业编号,参看官方开发文档 行业代码
 	 * @param int $id2  同$id1。但如果只有一个行业,此参数可省略

+ 267 - 0
old_version/Thinkphp/Wechatauth.class.php

@@ -0,0 +1,267 @@
+<?php
+/**
+ *	微信公众平台PHP-SDK
+ *  Wechatauth为非官方微信登陆API
+ *  用户通过扫描网页提供的二维码实现登陆信息获取
+ *  主要实现如下功能:
+ *  get_login_code() 获取登陆授权码, 通过授权码才能获取二维码
+ *  get_code_image($code='') 将上面获取的授权码转换为图片二维码
+ *  verify_code() 鉴定是否登陆成功,返回200为最终授权成功.
+ *  get_login_info() 鉴定成功后调用此方法即可获取用户基本信息
+ *  get_avatar($url) 获取用户头像图片数据
+ *  @author dodge <dodgepudding@gmail.com>
+ *  @link https://github.com/dodgepudding/wechat-php-sdk
+ *  @version 1.1
+ *  
+ */
+include "Snoopy.class.php";
+class Wechatauth
+{
+	private $cookie;
+	private $skey;
+	private $_cookiename;
+	private $_cookieexpired = 3600;
+	private $_account = 'test';
+	private $_datapath = './data/cookie_';
+	private $debug;
+	private $_logcallback;
+	public $login_user; //当前登陆用户, 调用get_login_info后获取
+	
+	public function __construct($options)
+	{
+		$this->_account = isset($options['account'])?$options['account']:'';
+		$this->_datapath = isset($options['datapath'])?$options['datapath']:$this->_datapath;
+		$this->debug = isset($options['debug'])?$options['debug']:false;
+		$this->_logcallback = isset($options['logcallback'])?$options['logcallback']:false;
+		$this->_cookiename = $this->_datapath.$this->_account;
+		$this->getCookie($this->_cookiename);
+	}
+	/**
+	 * 把cookie写入缓存
+	 * @param  string $filename 缓存文件名
+	 * @param  string $content  文件内容
+	 * @return bool
+	 */
+	public function saveCookie($filename,$content){
+		return S($filename,$content,$this->_cookieexpired);
+	}
+
+	/**
+	 * 读取cookie缓存内容
+	 * @param  string $filename 缓存文件名
+	 * @return string cookie
+	 */
+	public function getCookie($filename){
+		$data = S($filename);
+		if ($data) $this->cookie = $data;
+		return $this->cookie;
+	}
+	
+	/*
+	 * 删除cookie
+	 */
+	public function deleteCookie($filename) {
+		$this->cookie = '';
+		S($filename,null);
+		return true;
+	}
+	
+	private function log($log){
+		if ($this->debug && function_exists($this->_logcallback)) {
+			if (is_array($log)) $log = print_r($log,true);
+			return call_user_func($this->_logcallback,$log);
+		}
+	}
+	
+	/**
+	 * 获取登陆二维码对应的授权码
+	 */	
+	public function get_login_code(){
+		if ($this->_logincode) return $this->_logincode;
+		$t = time().strval(mt_rand(100,999));
+		$codeurl = 'https://login.weixin.qq.com/jslogin?appid=wx782c26e4c19acffb&redirect_uri=https%3A%2F%2Fwx.qq.com%2Fcgi-bin%2Fmmwebwx-bin%2Fwebwxnewloginpage&fun=new&lang=zh_CN&_='.$t;
+		$send_snoopy = new Snoopy; 
+		$send_snoopy->fetch($codeurl);
+		$result = $send_snoopy->results;
+		if ($result) {
+			preg_match("/window.QRLogin.uuid\s+=\s+\"([^\"]+)\"/",$result,$matches);
+			if(count($matches)>1) {
+				$this->_logincode = $matches[1];
+				$_SESSION['login_step'] = 0;
+				return $this->_logincode;
+			}
+		}
+		return $result;
+	}
+
+	/**
+	 * 通过授权码获取对应的二维码图片地址
+	 * @param string $code
+	 * @return string image url
+	 */
+	public function get_code_image($code=''){
+		if ($code=='') $code = $this->_logincode;
+		if (!$code) return false;
+		return 'http://login.weixin.qq.com/qrcode/'.$this->_logincode.'?t=webwx';
+	}
+	
+	/**
+	 * 设置二维码对应的授权码
+	 * @param string $code
+	 * @return class $this
+	 */
+	public  function set_login_code($code) {
+		$this->_logincode = $code;
+		return $this;
+	}
+	
+	/**
+	 * 二维码登陆验证
+	 *
+	 * @return status:
+	 * >=400: invaild code; 408: not auth and wait, 400,401: not valid or expired
+	 * 201: just scaned but not confirm
+	 * 200: confirm then you can get user info
+	 */
+	public function verify_code() {
+		if (!$this->_logincode) return false;
+		$t = time().strval(mt_rand(100,999));
+
+			$url = 'https://login.weixin.qq.com/cgi-bin/mmwebwx-bin/login?uuid='.$this->_logincode.'&tip=0&_='.$t;
+			$send_snoopy = new Snoopy; 
+			$send_snoopy->referer = "https://wx.qq.com/";
+			$send_snoopy->fetch($url);
+			$result = $send_snoopy->results;
+			$this->log('step1:'.$result);
+			if ($result) {
+				preg_match("/window\.code=(\d+)/",$result,$matches);
+				if(count($matches)>1) {
+					$status = intval($matches[1]);
+					if ($status==201) $_SESSION['login_step'] = 1;
+					if ($status==200) {
+						preg_match("/ticket=([0-9a-z-_]+)&lang=zh_CN&scan=(\d+)/",$result,$matches);
+						preg_match("/window.redirect_uri=\"([^\"]+)\"/",$result,$matcheurl);
+						$this->log('step2:'.print_r($matches,true));
+						if (count($matcheurl)>1) {
+							$ticket = $matches[1];
+							$scan = $matches[2];
+							//$loginurl = 'https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxnewloginpage?ticket='.$ticket.'&lang=zh_CN&scan='.$scan.'&fun=new';
+							$loginurl = str_replace("wx.qq.com", "wx2.qq.com", $matcheurl[1]).'&fun=old';
+							$urlpart = parse_url($loginurl);
+							$send_snoopy = new Snoopy; 
+							$send_snoopy->referer = "https://{$urlpart['host']}/cgi-bin/mmwebwx-bin/webwxindex?t=chat";
+							$send_snoopy->fetch($loginurl);
+							$result = $send_snoopy->results;
+							$xml = simplexml_load_string($result);
+							if ($xml->ret=="0") $this->skey = $xml->skey;
+							foreach ($send_snoopy->headers as $key => $value) {
+								$value = trim($value);
+								if(strpos($value,'Set-Cookie: ') !== false){
+									$tmp = str_replace("Set-Cookie: ","",$value);
+									$tmparray = explode(';', $tmp);
+									$item = trim($tmparray[0]);
+									$cookie.=$item.';';
+								}
+							}
+							$cookie .="Domain=.qq.com;";
+							$this->cookie = $cookie;
+							$this->log('step3:'.$loginurl.';cookie:'.$cookie.';respond:'.$result);
+							
+							$this->saveCookie($this->_cookiename,$this->cookie);
+						}
+					}
+					return $status;
+				}
+			}
+		return false;
+	}
+	
+	/**
+	 * 获取登陆的cookie
+	 *
+	 * @param bool $is_array 是否以数值方式返回,默认否,返回字符串
+	 * @return string|array
+	 */
+	public function get_login_cookie($is_array = false){
+		if (!$is_array)	return $this->cookie;
+		$c_arr = explode(';',$this->cookie);
+		$cookie = array();
+		foreach($c_arr as $item) {
+			$kitem = explode('=',trim($item));
+			if (count($kitem)>1) {
+				$key = trim($kitem[0]);
+				$val = trim($kitem[1]);
+				if (!empty($val)) $cookie[$key] = $val;
+			}
+		}
+		return $cookie;
+	}
+	
+	/**
+	 * 	 授权登陆后获取用户登陆信息
+	 */
+	public function get_login_info(){
+		if (!$this->cookie) return false;
+		$t = time().strval(mt_rand(100,999));
+		$send_snoopy = new Snoopy; 
+		$submit = 'https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxinit?r='.$t.'&skey='.urlencode($this->skey);
+		$send_snoopy->rawheaders['Cookie']= $this->cookie;
+		$send_snoopy->referer = "https://wx2.qq.com/";
+		$citems = $this->get_login_cookie(true);
+		$post = array(
+			"BaseRequest"=>array(
+				array(
+					"Uin"=>$citems['wxuin'],
+					"Sid"=>$citems['wxsid'],
+					"Skey"=>$this->skey,
+					"DeviceID"=>''
+				)
+			)
+		);
+		$send_snoopy->submit($submit,json_encode($post));
+		$this->log('login_info:'.$send_snoopy->results);
+		$result = json_decode($send_snoopy->results,true);
+		if ($result['BaseResponse']['Ret']<0) return false;
+		$this->_login_user = $result['User'];
+		return $result;
+	}
+	
+	/**
+	 *  获取头像
+	 *  @param string $url 传入从用户信息接口获取到的头像地址
+	 */
+	public function get_avatar($url) {
+		if (!$this->cookie) return false;
+		if (strpos($url, 'http')===false) {
+			$url = 'http://wx2.qq.com'.$url;
+		}
+		$send_snoopy = new Snoopy; 
+		$send_snoopy->rawheaders['Cookie']= $this->cookie;
+		$send_snoopy->referer = "https://wx2.qq.com/";
+		$send_snoopy->fetch($url);
+		$result = $send_snoopy->results;
+		if ($result) 
+			return $result;
+		else
+			return false;
+	}
+	
+	/**
+	 * 登出当前登陆用户
+	 */
+	public function logout(){
+		if (!$this->cookie) return false;
+		preg_match("/wxuin=(\w+);/",$this->cookie,$matches);
+		if (count($matches)>1) $uid = $matches[1];
+		preg_match("/wxsid=(\w+);/",$this->cookie,$matches);
+		if (count($matches)>1) $sid = $matches[1];
+		$this->log('logout: uid='.$uid.';sid='.$sid);
+		$send_snoopy = new Snoopy; 
+		$submit = 'https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxlogout?redirect=1&type=1';
+		$send_snoopy->rawheaders['Cookie']= $this->cookie;
+		$send_snoopy->referer = "https://wx2.qq.com/";
+		$send_snoopy->submit($submit,array('uin'=>$uid,'sid'=>$sid));
+		$this->deleteCookie($this->_cookiename);
+		return true;
+	}
+}

+ 784 - 0
old_version/Thinkphp/Wechatext.class.php

@@ -0,0 +1,784 @@
+<?php
+/**
+ *	微信公众平台PHP-SDK
+ *  Wechatext为非官方微信发送API
+ *  注: 用户id为通过getMsg()方法获取的FakeId值
+ *  主要实现如下功能:
+ *  send($id,$content) 向某用户id发送微信文字信息
+ *  getUserList($page,$pagesize,$groupid) 获取用户信息
+ *  getGroupList($page,$pagesize) 获取群组信息
+ *  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) 发送音频消息
+ *  sendVideo($id,$fid) 发送视频消息
+ *  getInfo($id) 根据id获取用户资料
+ *  getNewMsgNum($lastid) 获取从$lastid算起新消息的数目
+ *  getTopMsg() 获取最新一条消息的数据, 此方法获取的消息id可以作为检测新消息的$lastid依据
+ *  getMsg($lastid,$offset=0,$perpage=50,$day=0,$today=0,$star=0) 获取最新的消息列表, 列表将返回消息id, 用户id, 消息类型, 文字消息等参数
+ *  消息返回结构:  {"id":"消息id","type":"类型号(1为文字,2为图片,3为语音)","fileId":"0","hasReply":"0","fakeId":"用户uid","nickName":"昵称","dateTime":"时间戳","content":"文字内容"} 
+ *  getMsgImage($msgid,$mode='large') 若消息type类型为2, 调用此方法获取图片数据
+ *  getMsgVoice($msgid) 若消息type类型为3, 调用此方法获取语音数据
+ *  quickSetInterface($url, $token) 快速设置接口信息
+ *  @author dodge <dodgepudding@gmail.com>
+ *  @link https://github.com/dodgepudding/wechat-php-sdk
+ *  @version 1.2
+ *  
+ */
+
+include "Snoopy.class.php";
+class Wechatext
+{
+	private $cookie;
+	private $_cookiename;
+	private $_cookieexpired = 3600;
+	private $_account;
+	private $_password;
+	private $_datapath = './data/cookie_';
+	private $debug;
+	private $_logcallback;
+	private $_token;
+	
+	public function __construct($options)
+	{
+		$this->_account = isset($options['account'])?$options['account']:'';
+		$this->_password = isset($options['password'])?$options['password']:'';
+		$this->_datapath = isset($options['datapath'])?$options['datapath']:$this->_datapath;
+		$this->debug = isset($options['debug'])?$options['debug']:false;
+		$this->_logcallback = isset($options['logcallback'])?$options['logcallback']:false;
+		$this->_cookiename = $this->_datapath.$this->_account;
+		$this->cookie = $this->getCookie($this->_cookiename);
+	}
+
+	/**
+	 * 主动发消息
+	 * @param  string $id      用户的uid(即FakeId)
+	 * @param  string $content 发送的内容
+	 */
+	public function send($id,$content)
+	{
+		$send_snoopy = new Snoopy; 
+		$post = array();
+		$post['tofakeid'] = $id;
+		$post['type'] = 1;
+		$post['token'] = $this->_token;
+		$post['content'] = $content;
+		$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 = "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;
+	}
+	
+	/**
+	 * 群发功能 纯文本
+	 * @param string $content
+	 * @return string
+	 */
+	public function mass($content) {
+		$send_snoopy = new Snoopy;
+		$post = array();
+		$post['type'] = 1;
+		$post['token'] = $this->_token;
+		$post['content'] = $content;
+		$post['ajax'] = 1;
+		$post['city']='';
+		$post['country']='';
+		$post['f']='json';
+		$post['groupid']='-1';
+		$post['imgcode']='';
+		$post['lang']='zh_CN';
+		$post['province']='';
+		$post['random']=  rand(0, 1);
+		$post['sex']=0;
+		$post['synctxnews']=0;
+		$post['synctxweibo']=0;
+		$post['t']='ajax-response';
+		$send_snoopy->referer = "https://mp.weixin.qq.com/cgi-bin/masssendpage?t=mass/send&token={$this->_token}&lang=zh_CN";
+		$send_snoopy->rawheaders['Cookie']= $this->cookie;
+		$submit = "https://mp.weixin.qq.com/cgi-bin/masssend";
+		$send_snoopy->submit($submit,$post);
+		$this->log($send_snoopy->results);
+		return $send_snoopy->results;
+	}
+	
+	/**
+	 * 群发功能 图文素材
+	 * @param int $appmsgid 图文素材ID
+	 * @return string
+	 */
+	function massNews($appmsgid){
+		$send_snoopy = new Snoopy;
+		$post = array();
+		$post['type'] = 10;
+		$post['token'] = $this->_token;
+		$post['appmsgid'] = $appmsgid;
+		$post['ajax'] = 1;
+		$post['city']='';
+		$post['country']='';
+		$post['f']='json';
+		$post['groupid']='-1';
+		$post['imgcode']='';
+		$post['lang']='zh_CN';
+		$post['province']='';
+		$post['random']=  rand(0, 1);
+		$post['sex']=0;
+		$post['synctxnews']=0;
+		$post['synctxweibo']=0;
+		$post['t']='ajax-response';
+		$send_snoopy->referer = "https://mp.weixin.qq.com/cgi-bin/masssendpage?t=mass/send&token={$this->_token}&lang=zh_CN";
+		$send_snoopy->rawheaders['Cookie']= $this->cookie;
+		$submit = "https://mp.weixin.qq.com/cgi-bin/masssend";
+		$send_snoopy->submit($submit,$post);
+		$this->log($send_snoopy->results);
+		return $send_snoopy->results;
+	}
+	
+	/**
+	 * 获取用户列表列表
+	 * @param $page 页码(从0开始)
+	 * @param $pagesize 每页大小
+	 * @param $groupid 分组id
+	 * @return array ({contacts:[{id:12345667,nick_name:"昵称",remark_name:"备注名",group_id:0},{}....]})
+	 */
+	function getUserList($page=0,$pagesize=10,$groupid=0){
+		$send_snoopy = new Snoopy;
+		$t = time().strval(mt_rand(100,999));
+		$send_snoopy->referer = "https://mp.weixin.qq.com/cgi-bin/contactmanage?t=user/index&pagesize=".$pagesize."&pageidx=".$page."&type=0&groupid=0&lang=zh_CN&token=".$this->_token;
+		$send_snoopy->rawheaders['Cookie']= $this->cookie;
+		$submit = "https://mp.weixin.qq.com/cgi-bin/contactmanage?t=user/index&pagesize=".$pagesize."&pageidx=".$page."&type=0&groupid=$groupid&lang=zh_CN&f=json&token=".$this->_token;
+		$send_snoopy->fetch($submit);
+		$result = $send_snoopy->results;
+		$this->log('userlist:'.$result);
+		$json = json_decode($result,true);
+		if (isset($json['contact_list'])) {
+			$json = json_decode($json['contact_list'],true);
+			if (isset($json['contacts']))
+				return $json['contacts'];
+		}
+		return false;
+	}
+	
+	/**
+	 * 获取分组列表
+	 * 
+	 */
+	function getGroupList(){
+		$send_snoopy = new Snoopy;
+		$t = time().strval(mt_rand(100,999));
+		$send_snoopy->referer = "https://mp.weixin.qq.com/cgi-bin/contactmanage?t=user/index&pagesize=10&pageidx=0&type=0&groupid=0&lang=zh_CN&token=".$this->_token;
+		$send_snoopy->rawheaders['Cookie']= $this->cookie;
+		$submit = "https://mp.weixin.qq.com/cgi-bin/contactmanage?t=user/index&pagesize=10&pageidx=0&type=0&groupid=0&lang=zh_CN&f=json&token=".$this->_token;
+		$send_snoopy->fetch($submit);
+		$result = $send_snoopy->results;
+		$this->log('userlist:'.$result);
+		$json = json_decode($result,true);
+		if (isset($json['group_list'])){
+			$json = json_decode($json['group_list'],true);
+			if (isset($json['groups']))
+				return $json['groups'];
+		}
+		return false;
+	}
+	
+	/**
+	 * 获取图文信息列表
+	 * @param $page 页码(从0开始)
+	 * @param $pagesize 每页大小
+	 * @return array
+	 */
+	public function getNewsList($page,$pagesize=10) {
+		$send_snoopy = new Snoopy;
+		$t = time().strval(mt_rand(100,999));
+		$type=10;
+		$begin = $page*$pagesize;
+		$send_snoopy->referer = "https://mp.weixin.qq.com/cgi-bin/masssendpage?t=mass/send&token=".$this->_token."&lang=zh_CN";
+		$send_snoopy->rawheaders['Cookie']= $this->cookie;
+		$submit = "https://mp.weixin.qq.com/cgi-bin/appmsg?token=".$this->_token."&lang=zh_CN&type=$type&action=list&begin=$begin&count=$pagesize&f=json&random=0.".$t;
+		$send_snoopy->fetch($submit);
+		$result = $send_snoopy->results;
+		$this->log('newslist:'.$result);
+		$json = json_decode($result,true);
+		if (isset($json['app_msg_info'])) {
+			return $json['app_msg_info'];
+		} 
+		return false;
+	}
+	
+	/**
+	 * 获取与指定用户的对话内容
+	 * @param  $fakeid
+	 * @return  array
+	 */
+	public function getDialogMsg($fakeid) {
+		$send_snoopy = new Snoopy;
+		$t = time().strval(mt_rand(100,999));
+		$send_snoopy->referer = "https://mp.weixin.qq.com/cgi-bin/masssendpage?t=mass/send&token=".$this->_token."&lang=zh_CN";
+		$send_snoopy->rawheaders['Cookie']= $this->cookie;
+		$submit = "https://mp.weixin.qq.com/cgi-bin/singlesendpage?t=message/send&action=index&tofakeid=".$fakeid."&token=".$this->_token."&lang=zh_CN&f=json&random=".$t;
+		$send_snoopy->fetch($submit);
+		$result = $send_snoopy->results;
+		$this->log('DialogMsg:'.$result);
+		$json = json_decode($result,true);
+		if (isset($json['page_info'])) {
+			return $json['page_info'];
+		}
+		return false;
+	}
+	
+	/**
+	 * 发送图文信息,必须从图文库里选取消息ID发送
+	 * @param  string $id      用户的uid(即FakeId)
+	 * @param  string $msgid 图文消息id
+	 */
+	public function sendNews($id,$msgid)
+	{
+		$send_snoopy = new Snoopy; 
+		$post = array();
+		$post['tofakeid'] = $id;
+		$post['type'] = 10;
+		$post['token'] = $this->_token;
+		$post['fid'] = $msgid;
+		$post['appmsgid'] = $msgid;
+		$post['error'] = 'false';
+		$post['ajax'] = 1;
+        $send_snoopy->referer = "https://mp.weixin.qq.com/cgi-bin/singlemsgpage?fromfakeid={$id}&msgid=&source=&count=20&t=wxm-singlechat&lang=zh_CN";
+		$send_snoopy->rawheaders['Cookie']= $this->cookie;
+		$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;
+	}
+	
+	/**
+	 * 上传附件(图片/音频/视频)
+	 * @param string $filepath 本地文件地址
+	 * @param int $type 文件类型: 2:图片 3:音频 4:视频
+	 */
+	public function uploadFile($filepath,$type=2) {
+		$send_snoopy = new Snoopy;
+		$send_snoopy->referer = "http://mp.weixin.qq.com/cgi-bin/indexpage?t=wxm-upload&lang=zh_CN&type=2&formId=1";
+		$t = time().strval(mt_rand(100,999));
+		$post = array('formId'=>'');
+		$postfile = array('uploadfile'=>$filepath);
+		$send_snoopy->rawheaders['Cookie']= $this->cookie;
+		$send_snoopy->set_submit_multipart();
+		$submit = "http://mp.weixin.qq.com/cgi-bin/uploadmaterial?cgi=uploadmaterial&type=$type&token=".$this->_token."&t=iframe-uploadfile&lang=zh_CN&formId=	file_from_".$t;
+		$send_snoopy->submit($submit,$post,$postfile);
+		$tmp = $send_snoopy->results;
+		$this->log('upload:'.$tmp);
+		preg_match("/formId,.*?\'(\d+)\'/",$tmp,$matches);
+		if (isset($matches[1])) {
+			return $matches[1];
+		}
+		return false;
+	}
+	
+	/**
+	 * 创建图文消息
+	 * @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
+	 * @param $type 文件类型
+	 */
+	public function sendFile($id,$fid,$type) {
+		$send_snoopy = new Snoopy; 
+		$post = array();
+		$post['tofakeid'] = $id;
+		$post['type'] = $type;
+		$post['token'] = $this->_token;
+		$post['fid'] = $fid;
+		$post['fileid'] = $fid;
+		$post['error'] = 'false';
+		$post['ajax'] = 1;
+        $send_snoopy->referer = "https://mp.weixin.qq.com/cgi-bin/singlemsgpage?fromfakeid={$id}&msgid=&source=&count=20&t=wxm-singlechat&lang=zh_CN";
+		$send_snoopy->rawheaders['Cookie']= $this->cookie;
+		$submit = "https://mp.weixin.qq.com/cgi-bin/singlesend?t=ajax-response";
+		$send_snoopy->submit($submit,$post);
+		$result = $send_snoopy->results;
+		$this->log('sendfile:'.$result);
+		$json = json_decode($result,true);
+		if ($json && $json['ret']==0) 
+			return true;
+		else
+			return false;
+	}
+	
+	/**
+	 * 获取素材库文件列表
+	 * @param $type 文件类型: 2:图片 3:音频 4:视频
+	 * @param $page 页码(从0开始)
+	 * @param $pagesize 每页大小
+	 * @return array
+	 */
+	public function getFileList($type,$page,$pagesize=10) {
+		$send_snoopy = new Snoopy;
+		$t = time().strval(mt_rand(100,999));
+		$begin = $page*$pagesize;
+		$send_snoopy->referer = "https://mp.weixin.qq.com/cgi-bin/masssendpage?t=mass/send&token=".$this->_token."&lang=zh_CN";
+		$send_snoopy->rawheaders['Cookie']= $this->cookie;
+		$submit = "https://mp.weixin.qq.com/cgi-bin/filepage?token=".$this->_token."&lang=zh_CN&type=$type&random=0.".$t."&begin=$begin&count=$pagesize&f=json";
+		$send_snoopy->fetch($submit);
+		$result = $send_snoopy->results;
+		$this->log('filelist:'.$result);
+		$json = json_decode($result,true);
+		if (isset($json['page_info']))
+			return $json['page_info'];
+		else
+			return false;
+	}
+	
+	/**
+	 * 发送图文信息,必须从库里选取文件ID发送
+	 * @param  string $id      用户的uid(即FakeId)
+	 * @param  string $fid 文件id
+	 */
+	public function sendImage($id,$fid)
+	{
+		return $this->sendFile($id,$fid,2);
+	}
+	
+	/**
+	 * 发送语音信息,必须从库里选取文件ID发送
+	 * @param  string $id      用户的uid(即FakeId)
+	 * @param  string $fid 语音文件id
+	 */
+	public function sendAudio($id,$fid)
+	{
+		return $this->sendFile($id,$fid,3);
+	}
+	
+	/**
+	 * 发送视频信息,必须从库里选取文件ID发送
+	 * @param  string $id      用户的uid(即FakeId)
+	 * @param  string $fid 视频文件id
+	 */
+	public function sendVideo($id,$fid)
+	{
+		return $this->sendFile($id,$fid,4);
+	}
+	
+	/**
+	 * 发送预览图文消息
+	 * @param string $account 账户名称(user_name)
+	 * @param string $title 标题
+	 * @param string $summary 摘要
+	 * @param string $content 内容
+	 * @param string $photoid 素材库里的图片id(可通过uploadFile上传后获取)
+	 * @param string $srcurl 原文链接
+	 * @return json
+	 */
+	public function sendPreview($account,$title,$summary,$content,$photoid,$srcurl='') {
+		$send_snoopy = new Snoopy;
+		$submit = "https://mp.weixin.qq.com/cgi-bin/operate_appmsg?sub=preview&t=ajax-appmsg-preview";
+		$send_snoopy->set_submit_normal();
+		$send_snoopy->rawheaders['Cookie']= $this->cookie;
+		$send_snoopy->referer = 'https://mp.weixin.qq.com/cgi-bin/operate_appmsg?sub=edit&t=wxm-appmsgs-edit-new&type=10&subtype=3&lang=zh_CN';
+		$post = array(
+				'AppMsgId'=>'',
+				'ajax'=>1,
+				'content0'=>$content,
+				'count'=>1,
+				'digest0'=>$summary,
+				'error'=>'false',
+				'fileid0'=>$photoid,
+				'preusername'=>$account,
+				'sourceurl0'=>$srcurl,
+				'title0'=>$title,
+		);
+		$post['token'] = $this->_token;
+		$send_snoopy->submit($submit,$post);
+		$tmp = $send_snoopy->results;
+		$this->log('sendpreview:'.$tmp);
+		$json = json_decode($tmp,true);
+		return $json;
+	}
+	
+	/**
+	 * 获取用户的信息
+	 * @param  string $id 用户的uid(即FakeId)
+	 * @return array  {fake_id:100001,nick_name:'昵称',user_name:'用户名',signature:'签名档',country:'中国',province:'广东',city:'广州',gender:'1',group_id:'0'},groups:{[id:0,name:'未分组',cnt:20]}
+	 */
+	public function getInfo($id)
+	{
+		$send_snoopy = new Snoopy; 
+		$send_snoopy->rawheaders['Cookie']= $this->cookie;
+		$t = time().strval(mt_rand(100,999));
+		$send_snoopy->referer = "https://mp.weixin.qq.com/cgi-bin/getmessage?t=wxm-message&lang=zh_CN&count=50&token=".$this->_token;
+		$submit = "https://mp.weixin.qq.com/cgi-bin/getcontactinfo";
+		$post = array('ajax'=>1,'lang'=>'zh_CN','random'=>'0.'.$t,'token'=>$this->_token,'t'=>'ajax-getcontactinfo','fakeid'=>$id);
+		$send_snoopy->submit($submit,$post);
+		$this->log($send_snoopy->results);
+		$result = json_decode($send_snoopy->results,true);
+		if(isset($result['contact_info'])){
+			return $result['contact_info'];
+		}
+		return false;
+	}
+	
+	/**
+	 * 获得头像数据
+	 *
+	 * @param FakeId $fakeid
+	 * @return JPG二进制数据
+	 */
+	public function getHeadImg($fakeid){
+		$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/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));
+		if(!$result){
+			return false;
+		}
+		return $result;
+	}
+
+	/**
+	 * 获取消息更新数目
+	 * @param int $lastid 最近获取的消息ID,为0时获取总消息数目
+	 * @return int 数目
+	 */
+	public function getNewMsgNum($lastid=0){
+		$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;
+		$submit = "https://mp.weixin.qq.com/cgi-bin/getnewmsgnum?t=ajax-getmsgnum&lastmsgid=".$lastid;
+		$post = array('ajax'=>1,'token'=>$this->_token);
+		$send_snoopy->submit($submit,$post);
+		$this->log($send_snoopy->results);
+		$result = json_decode($send_snoopy->results,1);
+		if(!$result){
+			return false;
+		}
+		return intval($result['newTotalMsgCount']);
+	}
+	
+	/**
+	 * 获取最新一条消息
+	 * @return array {"id":"最新一条id","type":"类型号(1为文字,2为图片,3为语音)","fileId":"0","hasReply":"0","fakeId":"用户uid","nickName":"昵称","dateTime":"时间戳","content":"文字内容","playLength":"0","length":"0","source":"","starred":"0","status":"4"}        
+	 */
+	public function getTopMsg(){
+		$send_snoopy = new Snoopy;
+		$send_snoopy->rawheaders['Cookie']= $this->cookie;
+		$send_snoopy->referer = "https://mp.weixin.qq.com/cgi-bin/message?t=message/list&count=20&day=7&lang=zh_CN&token=".$this->_token;
+		$submit = "https://mp.weixin.qq.com/cgi-bin/message?t=message/list&f=json&count=20&day=7&lang=zh_CN&token=".$this->_token;
+		$send_snoopy->fetch($submit);
+		$this->log($send_snoopy->results);
+		$result = $send_snoopy->results;
+		$json = json_decode($result,true);
+		if (isset($json['msg_items'])) {
+			$json = json_decode($json['msg_items'],true);
+			if(isset($json['msg_item']))
+				return array_shift($json['msg_item']);
+		}
+		return false;
+	}
+	
+	/**
+	 * 获取新消息
+	 * @param $lastid 传入最后的消息id编号,为0则从最新一条起倒序获取
+	 * @param $offset lastid起算第一条的偏移量
+	 * @param $perpage 每页获取多少条
+	 * @param $day 最近几天消息(0:今天,1:昨天,2:前天,3:更早,7:五天内)
+	 * @param $today 是否只显示今天的消息, 与$day参数不能同时大于0
+	 * @param $star 是否星标组信息
+	 * @return array[] 同getTopMsg()返回的字段结构相同
+	 */
+	public function getMsg($lastid=0,$offset=0,$perpage=20,$day=7,$today=0,$star=0){
+		$send_snoopy = new Snoopy; 
+		$send_snoopy->rawheaders['Cookie']= $this->cookie;
+		$send_snoopy->referer = "https://mp.weixin.qq.com/cgi-bin/message?t=message/list&lang=zh_CN&count=50&token=".$this->_token;
+		$lastid = $lastid===0 ? '':$lastid;
+		$addstar = $star?'&action=star':'';
+		$submit = "https://mp.weixin.qq.com/cgi-bin/message?t=message/list&f=json&lang=zh_CN{$addstar}&count=$perpage&timeline=$today&day=$day&frommsgid=$lastid&offset=$offset&token=".$this->_token;
+		$send_snoopy->fetch($submit);
+		$this->log($send_snoopy->results);
+		$result = $send_snoopy->results;
+		$json = json_decode($result,true);
+		if (isset($json['msg_items'])) {
+			$json = json_decode($json['msg_items'],true);
+			if(isset($json['msg_item']))
+				return $json['msg_item'];
+		}
+		return false;
+	}
+	
+	/**
+	 * 获取图片消息
+	 * @param int $msgid 消息id
+	 * @param string $mode 图片尺寸(large/small)
+	 * @return jpg二进制文件
+	 */
+	public function getMsgImage($msgid,$mode='large'){
+		$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/getimgdata?token=".$this->_token."&msgid=$msgid&mode=$mode&source=&fileId=0";
+		$send_snoopy->fetch($url);
+		$result = $send_snoopy->results;
+		$this->log('msg image:'.$msgid.';length:'.strlen($result));
+		if(!$result){
+			return false;
+		}
+		return $result;
+	}
+	
+	/**
+	 * 获取语音消息
+	 * @param int $msgid 消息id
+	 * @return mp3二进制文件
+	 */
+	public function getMsgVoice($msgid){
+		$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/getvoicedata?token=".$this->_token."&msgid=$msgid&fileId=0";
+		$send_snoopy->fetch($url);
+		$result = $send_snoopy->results;
+		$this->log('msg voice:'.$msgid.';length:'.strlen($result));
+		if(!$result){
+			return false;
+		}
+		return $result;
+	}
+	
+	/**
+	 * 开启开发者模式
+	 */
+	public function openDevModel()
+	{
+		$send_snoopy = new Snoopy;
+		$send_snoopy->rawheaders['Cookie']= $this->cookie;
+		$send_snoopy->referer = "https://mp.weixin.qq.com/advanced/advanced?action=dev&t=advanced/dev&lang=zh_CN&token=".$this->_token;
+		$submit = "https://mp.weixin.qq.com/misc/skeyform?form=advancedswitchform&lang=zh_CN";
+		$post['flag']=1;
+        $post['type']=2;   
+        $post['token']=$this->_token;
+		$send_snoopy->submit($submit,$post);
+		$result = $send_snoopy->results;
+		$this->log($send_snoopy->results);
+		$json = json_decode($result,true);
+		if(!$result){
+			return false;
+		}
+		return true;
+	}
+
+	/**
+	 * 关闭编辑模式
+	 */
+	public function closeEditModel()
+	{
+		$send_snoopy = new Snoopy;
+		$send_snoopy->rawheaders['Cookie']= $this->cookie;
+		$send_snoopy->referer = "https://mp.weixin.qq.com/advanced/advanced?action=dev&t=advanced/dev&lang=zh_CN&token=".$this->_token;
+		$submit = "https://mp.weixin.qq.com/misc/skeyform?form=advancedswitchform&lang=zh_CN";
+		$post['flag']=0;
+        $post['type']=1;   
+        $post['token']=$this->_token;
+		$send_snoopy->submit($submit,$post);
+		$result = $send_snoopy->results;
+		$this->log($send_snoopy->results);
+		$json = json_decode($result,true);
+		if(!$result){
+			return false;
+		}
+		return true;
+	}
+
+	/**
+	 * 配置接口信息
+	 * @param  string $url      接口回调URL
+	 * @param  string $token    接口Token
+	 */
+	public function setUrlToken($url, $token)
+	{
+		$send_snoopy = new Snoopy;
+		$send_snoopy->rawheaders['Cookie']= $this->cookie;
+		$send_snoopy->referer = "https://mp.weixin.qq.com/advanced/advanced?action=interface&t=advanced/interface&lang=zh_CN&token=".$this->_token;
+		$submit = "https://mp.weixin.qq.com/advanced/callbackprofile?t=ajax-response&lang=zh_CN&token=".$this->_token;
+		$post['url'] = $url;
+		$post['callback_token'] = $token;
+		$send_snoopy->submit($submit,$post);
+		$result = $send_snoopy->results;
+		$this->log($send_snoopy->results);
+		$json = json_decode($result,true);
+		if ($json && $json['ret']==0) 
+			return true;
+		return false;
+	}
+
+	/**
+	 * 快速设置接口
+	 * @param  string $url      接口回调URL
+	 * @param  string $token    接口Token
+	 */
+	public function quickSetInterface($url, $token)
+	{
+		if ($this->closeEditModel() && $this->openDevModel() && $this->setUrlToken($url, $token))
+			return true;
+		return false;
+	}
+	
+	/**
+	 * 模拟登录获取cookie
+	 * @return [type] [description]
+	 */
+	public function login(){
+		$snoopy = new Snoopy; 
+		$submit = "https://mp.weixin.qq.com/cgi-bin/login?lang=zh_CN";
+		$post["username"] = $this->_account;
+		$post["pwd"] = md5($this->_password);
+		$post["f"] = "json";
+		$post["imgcode"] = "";
+		$snoopy->referer = "https://mp.weixin.qq.com/";
+		$snoopy->submit($submit,$post);
+		$cookie = '';
+		$this->log($snoopy->results);
+		$result = json_decode($snoopy->results,true);
+		
+		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))
+				$cookie .=$match[1].'='.$match[2].'; ';
+		}
+		
+		preg_match("/token=(\d+)/i",$result['redirect_url'],$matches);
+		if($matches){
+			$this->_token = $matches[1];
+			$this->log('token:'.$this->_token);
+		}
+		$cookies='{"cookie":"'.$cookie.'","token":"'.$this->_token.'"}';
+		$this->saveCookie($this->_cookiename,$cookies);
+		return $cookie;
+	}
+
+	/**
+	 * 把cookie写入缓存
+	 * @param  string $filename 缓存文件名
+	 * @param  string $content  文件内容
+	 * @return bool
+	 */
+	public function saveCookie($filename,$content){
+		return S($filename,$content,$this->_cookieexpired);
+	}
+
+	/**
+	 * 读取cookie缓存内容
+	 * @param  string $filename 缓存文件名
+	 * @return string cookie
+	 */
+	public function getCookie($filename){
+		$data = S($filename);
+		if($data){
+			$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=".$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 =$login['token'];
+				return $login['cookie'];
+			}
+		}else{
+			return $this->login();
+		}
+	}
+
+	/**
+	 * 验证cookie的有效性
+	 * @return bool
+	 */
+	public function checkValid()
+	{
+		if (!$this->cookie || !$this->_token) return false;
+		$send_snoopy = new Snoopy; 
+		$post = array('ajax'=>1,'token'=>$this->_token);
+		$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;
+		if(json_decode($result,1)){
+			return true;
+		}else{
+			return false;
+		}
+	}
+
+	private function log($log){
+		if ($this->debug ) {
+			if (function_exists($this->_logcallback)) {
+				if (is_array($log)) $log = print_r($log,true);
+				return call_user_func($this->_logcallback,$log);
+			}elseif (class_exists('Log')) {
+				Log::write('wechat:'.$log, Log::DEBUG);
+			}
+		}
+		return false;
+	}
+}

+ 469 - 0
old_version/Thinkphp/Wechatpay.class.php

@@ -0,0 +1,469 @@
+<?php
+/**
+ *	微信公众平台PHP-SDK, 旧版微信支付接口
+ *  @author  dodge <dodgepudding@gmail.com>
+ *  @link https://github.com/dodgepudding/wechat-php-sdk
+ *  @version 1.2
+ *  参考旧版文档 https://mp.weixin.qq.com/cgi-bin/readtemplate?t=business/course2_tmpl&lang=zh_CN
+ *  usage:
+ *   $options = array(
+ *			'appid'=>'wxdk1234567890', //填写高级调用功能的app id
+ *			'appsecret'=>'xxxxxxxxxxxxxxxxxxx', //填写高级调用功能的密钥
+ *			'partnerid'=>'88888888', //财付通商户身份标识
+ *			'partnerkey'=>'', //财付通商户权限密钥Key
+ *			'paysignkey'=>'' //商户签名密钥Key
+ *		);
+ *	 $payObj = new Wechatpay($options);
+ *   $package = $payObj->createPackage($out_trade_no,$body,$total_fee,$notify_url,$spbill_create_ip,$fee_type,$bank_type,$input_charset,$time_start,$time_expire,$transport_fee,$product_fee,$goods_tag,$attach);
+ *
+ */
+class Wechatpay
+{
+	const API_URL_PREFIX = 'https://api.weixin.qq.com/cgi-bin';
+	const AUTH_URL = '/token?grant_type=client_credential&';
+	const API_BASE_URL_PREFIX = 'https://api.weixin.qq.com'; //以下API接口URL需要使用此前缀
+	const PAY_DELIVERNOTIFY = '/pay/delivernotify?';
+	const PAY_ORDERQUERY = '/pay/orderquery?';
+
+	private $appid;
+	private $appsecret;
+	private $access_token;
+	private $user_token;
+	private $partnerid;
+	private $partnerkey;
+	private $paysignkey;
+
+	public $debug =  false;
+	public $errCode = 40001;
+	public $errMsg = "no access";
+	private $_logcallback;
+
+	public function __construct($options)
+	{
+		$this->appid = isset($options['appid'])?$options['appid']:'';
+		$this->appsecret = isset($options['appsecret'])?$options['appsecret']:'';
+		$this->partnerid = isset($options['partnerid'])?$options['partnerid']:'';
+		$this->partnerkey = isset($options['partnerkey'])?$options['partnerkey']:'';
+		$this->paysignkey = isset($options['paysignkey'])?$options['paysignkey']:'';
+		$this->debug = isset($options['debug'])?$options['debug']:false;
+		$this->_logcallback = isset($options['logcallback'])?$options['logcallback']:false;
+	}
+
+    private function log($log){
+    		if ($this->debug ) {
+    			if (function_exists($this->_logcallback)) {
+    			if (is_array($log)) $log = print_r($log,true);
+    			return call_user_func($this->_logcallback,$log);
+    			}elseif (class_exists('Log')) {
+    				Log::write('wechat:'.$log, Log::DEBUG);
+    			}
+    		}
+    		return false;
+    }
+
+	/**
+	 * GET 请求
+	 * @param string $url
+	 */
+	private function http_get($url){
+		$oCurl = curl_init();
+		if(stripos($url,"https://")!==FALSE){
+			curl_setopt($oCurl, CURLOPT_SSL_VERIFYPEER, FALSE);
+			curl_setopt($oCurl, CURLOPT_SSL_VERIFYHOST, FALSE);
+			curl_setopt($oCurl, CURLOPT_SSLVERSION, 1); //CURL_SSLVERSION_TLSv1
+		}
+		curl_setopt($oCurl, CURLOPT_URL, $url);
+		curl_setopt($oCurl, CURLOPT_RETURNTRANSFER, 1 );
+		$sContent = curl_exec($oCurl);
+		$aStatus = curl_getinfo($oCurl);
+		curl_close($oCurl);
+		if(intval($aStatus["http_code"])==200){
+			return $sContent;
+		}else{
+			return false;
+		}
+	}
+
+	/**
+	 * POST 请求
+	 * @param string $url
+	 * @param array $param
+	 * @param boolean $post_file 是否文件上传
+	 * @return string content
+	 */
+	private function http_post($url,$param,$post_file=false){
+		$oCurl = curl_init();
+		if(stripos($url,"https://")!==FALSE){
+			curl_setopt($oCurl, CURLOPT_SSL_VERIFYPEER, FALSE);
+			curl_setopt($oCurl, CURLOPT_SSL_VERIFYHOST, false);
+			curl_setopt($oCurl, CURLOPT_SSLVERSION, 1); //CURL_SSLVERSION_TLSv1
+		}
+		if (is_string($param) || $post_file) {
+			$strPOST = $param;
+		} else {
+			$aPOST = array();
+			foreach($param as $key=>$val){
+				$aPOST[] = $key."=".urlencode($val);
+			}
+			$strPOST =  join("&", $aPOST);
+		}
+		curl_setopt($oCurl, CURLOPT_URL, $url);
+		curl_setopt($oCurl, CURLOPT_RETURNTRANSFER, 1 );
+		curl_setopt($oCurl, CURLOPT_POST,true);
+		curl_setopt($oCurl, CURLOPT_POSTFIELDS,$strPOST);
+		$sContent = curl_exec($oCurl);
+		$aStatus = curl_getinfo($oCurl);
+		curl_close($oCurl);
+		if(intval($aStatus["http_code"])==200){
+			return $sContent;
+		}else{
+			return false;
+		}
+	}
+
+	/**
+	 * 通用auth验证方法,暂时仅用于菜单更新操作
+	 * @param string $appid
+	 * @param string $appsecret
+	 * @param string $token 手动指定access_token,非必要情况不建议用
+	 */
+	public function checkAuth($appid='',$appsecret='',$token=''){
+		if (!$appid || !$appsecret) {
+			$appid = $this->appid;
+			$appsecret = $this->appsecret;
+		}
+		$authname = 'wechat_access_token'.$appid;
+		if ($token) { //手动指定token,优先使用
+		    $this->access_token=$token;
+		    return $this->access_token;
+		}
+		if ($rs = S($authname))  {
+			$this->access_token = $rs;
+			return $rs;
+		}
+		$result = $this->http_get(self::API_URL_PREFIX.self::AUTH_URL.'appid='.$appid.'&secret='.$appsecret);
+		if ($result)
+		{
+			$json = json_decode($result,true);
+			if (!$json || isset($json['errcode'])) {
+				$this->errCode = $json['errcode'];
+				$this->errMsg = $json['errmsg'];
+				return false;
+			}
+			$this->access_token = $json['access_token'];
+			$expire = $json['expires_in'] ? intval($json['expires_in'])-100 : 3600;
+			S($authname,$this->access_token,$expire);
+			return $this->access_token;
+		}
+		return false;
+	}
+
+	/**
+	 * 删除验证数据
+	 * @param string $appid
+	 */
+	public function resetAuth($appid=''){
+		if (!$appid) $appid = $this->appid;
+		$this->access_token = '';
+		$authname = 'wechat_access_token'.$appid;
+		S($authname,null);
+		return true;
+	}
+
+	/**
+	 * 微信api不支持中文转义的json结构
+	 * @param array $arr
+	 */
+	static function json_encode($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 [] = self::json_encode ( $value ); /* :RECURSION: */
+				else
+					$parts [] = '"' . $key . '":' . self::json_encode ( $value ); /* :RECURSION: */
+			} else {
+				$str = '';
+				if (! $is_list)
+					$str = '"' . $key . '":';
+				//Custom handling for multiple data types
+				if (!is_string ( $value ) && 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
+	}
+
+	/**
+	 * 获取签名
+	 * @param array $arrdata 签名数组
+	 * @param string $method 签名方法
+	 * @return boolean|string 签名值
+	 */
+	public function getSignature($arrdata,$method="sha1") {
+		if (!function_exists($method)) return false;
+		ksort($arrdata);
+		$paramstring = "";
+		foreach($arrdata as $key => $value)
+		{
+			if(strlen($paramstring) == 0)
+				$paramstring .= $key . "=" . $value;
+			else
+				$paramstring .= "&" . $key . "=" . $value;
+		}
+		$paySign = $method($paramstring);
+		return $paySign;
+	}
+
+	/**
+	 * 生成随机字串
+	 * @param number $length 长度,默认为16,最长为32字节
+	 * @return string
+	 */
+	public function generateNonceStr($length=16){
+		// 密码字符集,可任意添加你需要的字符
+		$chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+		$str = "";
+		for($i = 0; $i < $length; $i++)
+		{
+			$str .= $chars[mt_rand(0, strlen($chars) - 1)];
+		}
+		return $str;
+	}
+
+	/**
+	 * 生成原生支付url
+	 * @param number $productid 商品编号,最长为32字节
+	 * @return string
+	 */
+	public function createNativeUrl($productid){
+		    $nativeObj["appid"] = $this->appid;
+		    $nativeObj["appkey"] = $this->paysignkey;
+		    $nativeObj["productid"] = urlencode($productid);
+		    $nativeObj["timestamp"] = time();
+		    $nativeObj["noncestr"] = $this->generateNonceStr();
+		    $nativeObj["sign"] = $this->getSignature($nativeObj);
+		    unset($nativeObj["appkey"]);
+		    $bizString = "";
+		    foreach($nativeObj as $key => $value)
+		    {
+			if(strlen($bizString) == 0)
+				$bizString .= $key . "=" . $value;
+			else
+				$bizString .= "&" . $key . "=" . $value;
+		    }
+		    return "weixin://wxpay/bizpayurl?".$bizString;
+		    //weixin://wxpay/bizpayurl?sign=XXXXX&appid=XXXXXX&productid=XXXXXX&timestamp=XXXXXX&noncestr=XXXXXX
+	}
+
+
+	/**
+	 * 生成订单package字符串
+	 * @param string $out_trade_no 必填,商户系统内部的订单号,32个字符内,确保在商户系统唯一
+	 * @param string $body 必填,商品描述,128 字节以下
+	 * @param int $total_fee 必填,订单总金额,单位为分
+	 * @param string $notify_url 必填,支付完成通知回调接口,255 字节以内
+	 * @param string $spbill_create_ip 必填,用户终端IP,IPV4字串,15字节内
+	 * @param int $fee_type 必填,现金支付币种,默认1:人民币
+	 * @param string $bank_type 必填,银行通道类型,默认WX
+	 * @param string $input_charset 必填,传入参数字符编码,默认UTF-8,取值有UTF-8和GBK
+	 * @param string $time_start 交易起始时间,订单生成时间,格式yyyyMMddHHmmss
+	 * @param string $time_expire 交易结束时间,也是订单失效时间
+	 * @param int $transport_fee 物流费用,单位为分
+	 * @param int $product_fee 商品费用,单位为分,必须保证 transport_fee + product_fee=total_fee
+	 * @param string $goods_tag 商品标记,优惠券时可能用到
+	 * @param string $attach 附加数据,notify接口原样返回
+	 * @return string
+	 */
+	public function 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=""){
+			$arrdata = array("bank_type" => $bank_type, "body" => $body, "partner" => $this->partnerid, "out_trade_no" => $out_trade_no, "total_fee" => $total_fee, "fee_type" => $fee_type, "notify_url" => $notify_url, "spbill_create_ip" => $spbill_create_ip, "input_charset" => $input_charset);
+			if ($time_start)  $arrdata['time_start'] = $time_start;
+			if ($time_expire)  $arrdata['time_expire'] = $time_expire;
+			if ($transport_fee)  $arrdata['transport_fee'] = $transport_fee;
+			if ($product_fee)  $arrdata['product_fee'] = $product_fee;
+			if ($goods_tag)  $arrdata['goods_tag'] = $goods_tag;
+			if ($attach)  $arrdata['attach'] = $attach;
+			ksort($arrdata);
+			$paramstring = "";
+			foreach($arrdata as $key => $value)
+			{
+			if(strlen($paramstring) == 0)
+				$paramstring .= $key . "=" . $value;
+				else
+				$paramstring .= "&" . $key . "=" . $value;
+			}
+			$stringSignTemp = $paramstring . "&key=" . $this->partnerkey;
+			$signValue = strtoupper(md5($stringSignTemp));
+			$package = http_build_query($arrdata) . "&sign=" . $signValue;
+			return $package;
+	}
+
+	/**
+	 * 支付签名(paySign)生成方法
+	 * @param string $package 订单详情字串
+	 * @param string $timeStamp 当前时间戳(需与JS输出的一致)
+	 * @param string $nonceStr 随机串(需与JS输出的一致)
+	 * @return string 返回签名字串
+	 */
+	public function getPaySign($package, $timeStamp, $nonceStr){
+		$arrdata = array("appid" => $this->appid, "timestamp" => $timeStamp, "noncestr" => $nonceStr, "package" => $package, "appkey" => $this->paysignkey);
+		$paySign = $this->getSignature($arrdata);
+		return $paySign;
+	}
+
+	/**
+	 * 回调通知签名验证
+	 * @param array $orderxml 返回的orderXml的数组表示,留空则自动从post数据获取
+	 * @return boolean
+	 */
+	public function checkOrderSignature($orderxml=''){
+		if (!$orderxml) {
+			$postStr = file_get_contents("php://input");
+			if (!empty($postStr)) {
+				$orderxml = (array)simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
+			} else return false;
+		}
+		$arrdata = array('appid'=>$orderxml['AppId'],'appkey'=>$this->paysignkey,'timestamp'=>$orderxml['TimeStamp'],'noncestr'=>$orderxml['NonceStr'],'openid'=>$orderxml['OpenId'],'issubscribe'=>$orderxml['IsSubscribe']);
+		$paySign = $this->getSignature($arrdata);
+		if ($paySign!=$orderxml['AppSignature']) return false;
+		return true;
+	}
+
+	/**
+	 * 发货通知
+	 * @param string $openid 用户open_id
+	 * @param string $transid 交易单号
+	 * @param string $out_trade_no 第三方订单号
+	 * @param int $status 0:发货失败;1:已发货
+	 * @param string $msg 失败原因
+	 * @return boolean|array
+	 */
+	public function sendPayDeliverNotify($openid,$transid,$out_trade_no,$status=1,$msg='ok'){
+		if (!$this->access_token && !$this->checkAuth()) return false;
+		$postdata = array(
+				"appid"=>$this->appid,
+				"appkey"=>$this->paysignkey,
+				"openid"=>$openid,
+				"transid"=>strval($transid),
+				"out_trade_no"=>strval($out_trade_no),
+				"deliver_timestamp"=>strval(time()),
+				"deliver_status"=>strval($status),
+				"deliver_msg"=>$msg,
+		);
+		$postdata['app_signature'] = $this->getSignature($postdata);
+		$postdata['sign_method'] = 'sha1';
+		unset($postdata['appkey']);
+		$result = $this->http_post(self::API_BASE_URL_PREFIX.self::PAY_DELIVERNOTIFY.'access_token='.$this->access_token,self::json_encode($postdata));
+		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 string $out_trade_no 订单号
+	 * @return boolean|array
+	 */
+	public function getPayOrder($out_trade_no) {
+		if (!$this->access_token && !$this->checkAuth()) return false;
+		$sign = strtoupper(md5("out_trade_no=$out_trade_no&partner={$this->partnerid}&key={$this->partnerkey}"));
+		$postdata = array(
+				"appid"=>$this->appid,
+				"appkey"=>$this->paysignkey,
+				"package"=>"out_trade_no=$out_trade_no&partner={$this->partnerid}&sign=$sign",
+				"timestamp"=>strval(time()),
+		);
+		$postdata['app_signature'] = $this->getSignature($postdata);
+		$postdata['sign_method'] = 'sha1';
+		unset($postdata['appkey']);
+		$result = $this->http_post(self::API_BASE_URL_PREFIX.self::PAY_ORDERQUERY.'access_token='.$this->access_token,self::json_encode($postdata));
+		if ($result)
+		{
+			$json = json_decode($result,true);
+			if (!$json || !empty($json['errcode'])) {
+				$this->errCode = $json['errcode'];
+				$this->errMsg = $json['errmsg'].json_encode($postdata);
+				return false;
+			}
+			return $json["order_info"];
+		}
+		return false;
+	}
+	
+	/**
+	 * 设置用户授权密钥
+	 * @param string $user_token
+	 * @return string
+	 */
+	public function setUserToken($user_token) {
+		return $this->user_token = $user_token;
+	}
+	
+	/**
+	 * 设置用户授权密钥
+	 * @param string $user_token
+	 * @return string
+	 */
+	public function setUserToken($user_token) {
+		return $this->user_token = $user_token;
+	}
+
+	/**
+	 * 获取收货地址JS的签名
+	 * @tutorial 参考weixin.js脚本的WeixinJS.editAddress方法调用
+	 * @param string $appId
+	 * @param string $url
+	 * @param int $timeStamp
+	 * @param string $nonceStr
+	 * @param string $user_token
+	 * @return Ambigous <boolean, string>
+	 */
+	public function getAddrSign($url, $timeStamp, $nonceStr, $user_token=''){
+		if (!$user_token) $user_token = $this->user_token;
+		if (!$user_token) {
+			$this->errMsg = 'no user access token found!';
+			return false;
+		}
+		$url = htmlspecialchars_decode($url);
+		$arrdata = array(
+				'appid'=>$this->appid,
+				'url'=>$url,
+				'timestamp'=>strval($timeStamp),
+				'noncestr'=>$nonceStr,
+				'accesstoken'=>$user_token
+		);
+		return $this->getSignature($arrdata);
+	}
+}

+ 271 - 0
old_version/wechatauth.class.php

@@ -0,0 +1,271 @@
+<?php
+/**
+ *	微信公众平台PHP-SDK
+ *  Wechatauth为非官方微信登陆API
+ *  用户通过扫描网页提供的二维码实现登陆信息获取
+ *  主要实现如下功能:
+ *  get_login_code() 获取登陆授权码, 通过授权码才能获取二维码
+ *  get_code_image($code='') 将上面获取的授权码转换为图片二维码
+ *  verify_code() 鉴定是否登陆成功,返回200为最终授权成功.
+ *  get_login_info() 鉴定成功后调用此方法即可获取用户基本信息
+ *  get_avatar($url) 获取用户头像图片数据
+ *  @author dodge <dodgepudding@gmail.com>
+ *  @link https://github.com/dodgepudding/wechat-php-sdk
+ *  @version 1.1
+ *  
+ */
+include "snoopy.class.php";
+class Wechatauth
+{
+	private $cookie;
+	private $skey;
+	private $_cookiename;
+	private $_cookieexpired = 3600;
+	private $_account = 'test';
+	private $_datapath = './data/cookie_';
+	private $debug;
+	private $_logcallback;
+	public $login_user; //当前登陆用户, 调用get_login_info后获取
+	
+	public function __construct($options)
+	{
+		$this->_account = isset($options['account'])?$options['account']:'';
+		$this->_datapath = isset($options['datapath'])?$options['datapath']:$this->_datapath;
+		$this->debug = isset($options['debug'])?$options['debug']:false;
+		$this->_logcallback = isset($options['logcallback'])?$options['logcallback']:false;
+		$this->_cookiename = $this->_datapath.$this->_account;
+		$this->getCookie($this->_cookiename);
+	}
+	/**
+	 * 把cookie写入缓存
+	 * @param  string $filename 缓存文件名
+	 * @param  string $content  文件内容
+	 * @return bool
+	 */
+	public function saveCookie($filename,$content){
+		return file_put_contents($filename,$content);
+	}
+
+	/**
+	 * 读取cookie缓存内容
+	 * @param  string $filename 缓存文件名
+	 * @return string cookie
+	 */
+	public function getCookie($filename){
+		if (file_exists($filename)) {
+			$mtime = filemtime($filename);
+			if ($mtime<time()-$this->_cookieexpired) return false;
+			$data = file_get_contents($filename);
+			if ($data) $this->cookie = $data;
+		} 
+		return $this->cookie;
+	}
+	
+	/*
+	 * 删除cookie
+	 */
+	public function deleteCookie($filename) {
+		$this->cookie = '';
+		@unlink($filename);
+		return true;
+	}
+	
+	private function log($log){
+		if ($this->debug && function_exists($this->_logcallback)) {
+			if (is_array($log)) $log = print_r($log,true);
+			return call_user_func($this->_logcallback,$log);
+		}
+	}
+	
+	/**
+	 * 获取登陆二维码对应的授权码
+	 */
+	public function get_login_code(){
+		if ($this->_logincode) return $this->_logincode;
+		$t = time().strval(mt_rand(100,999));
+		$codeurl = 'https://login.weixin.qq.com/jslogin?appid=wx782c26e4c19acffb&redirect_uri=https%3A%2F%2Fwx.qq.com%2Fcgi-bin%2Fmmwebwx-bin%2Fwebwxnewloginpage&fun=new&lang=zh_CN&_='.$t;
+		$send_snoopy = new Snoopy; 
+		$send_snoopy->fetch($codeurl);
+		$result = $send_snoopy->results;
+		if ($result) {
+			preg_match("/window.QRLogin.uuid\s+=\s+\"([^\"]+)\"/",$result,$matches);
+			if(count($matches)>1) {
+				$this->_logincode = $matches[1];
+				$_SESSION['login_step'] = 0;
+				return $this->_logincode;
+			}
+		}
+		return $result;
+	}
+
+	/**
+	 * 通过授权码获取对应的二维码图片地址
+	 * @param string $code
+	 * @return string image url
+	 */
+	public function get_code_image($code=''){
+		if ($code=='') $code = $this->_logincode;
+		if (!$code) return false;
+		return 'http://login.weixin.qq.com/qrcode/'.$this->_logincode.'?t=webwx';
+	}
+	
+	/**
+	 * 设置二维码对应的授权码
+	 * @param string $code
+	 * @return class $this
+	 */
+	public  function set_login_code($code) {
+		$this->_logincode = $code;
+		return $this;
+	}
+	
+	/**
+	 * 二维码登陆验证
+	 *
+	 * @return status:
+	 * >=400: invaild code; 408: not auth and wait, 400,401: not valid or expired
+	 * 201: just scaned but not confirm
+	 * 200: confirm then you can get user info
+	 */
+	public function verify_code() {
+		if (!$this->_logincode) return false;
+		$t = time().strval(mt_rand(100,999));
+
+			$url = 'https://login.weixin.qq.com/cgi-bin/mmwebwx-bin/login?uuid='.$this->_logincode.'&tip=0&_='.$t;
+			$send_snoopy = new Snoopy; 
+			$send_snoopy->referer = "https://wx.qq.com/";
+			$send_snoopy->fetch($url);
+			$result = $send_snoopy->results;
+			$this->log('step1:'.$result);
+			if ($result) {
+				preg_match("/window\.code=(\d+)/",$result,$matches);
+				if(count($matches)>1) {
+					$status = intval($matches[1]);
+					if ($status==201) $_SESSION['login_step'] = 1;
+					if ($status==200) {
+						preg_match("/ticket=([0-9a-z-_]+)&lang=zh_CN&scan=(\d+)/",$result,$matches);
+						preg_match("/window.redirect_uri=\"([^\"]+)\"/",$result,$matcheurl);
+						$this->log('step2:'.print_r($matches,true));
+						if (count($matcheurl)>1) {
+							$ticket = $matches[1];
+							$scan = $matches[2];
+							//$loginurl = 'https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxnewloginpage?ticket='.$ticket.'&lang=zh_CN&scan='.$scan.'&fun=new';
+							$loginurl = str_replace("wx.qq.com", "wx2.qq.com", $matcheurl[1]).'&fun=old';
+							$urlpart = parse_url($loginurl);
+							$send_snoopy = new Snoopy; 
+							$send_snoopy->referer = "https://{$urlpart['host']}/cgi-bin/mmwebwx-bin/webwxindex?t=chat";
+							$send_snoopy->fetch($loginurl);
+							$result = $send_snoopy->results;
+							$xml = simplexml_load_string($result);
+							if ($xml->ret=="0") $this->skey = $xml->skey;
+							foreach ($send_snoopy->headers as $key => $value) {
+								$value = trim($value);
+								if(strpos($value,'Set-Cookie: ') !== false){
+									$tmp = str_replace("Set-Cookie: ","",$value);
+									$tmparray = explode(';', $tmp);
+									$item = trim($tmparray[0]);
+									$cookie.=$item.';';
+								}
+							}
+							$cookie .="Domain=.qq.com;";
+							$this->cookie = $cookie;
+							$this->log('step3:'.$loginurl.';cookie:'.$cookie.';respond:'.$result);
+							
+							$this->saveCookie($this->_cookiename,$this->cookie);
+						}
+					}
+					return $status;
+				}
+			}
+		return false;
+	}
+	
+	/**
+	 * 获取登陆的cookie
+	 *
+	 * @param bool $is_array 是否以数值方式返回,默认否,返回字符串
+	 * @return string|array
+	 */
+	public function get_login_cookie($is_array = false){
+		if (!$is_array)	return $this->cookie;
+		$c_arr = explode(';',$this->cookie);
+		$cookie = array();
+		foreach($c_arr as $item) {
+			$kitem = explode('=',trim($item));
+			if (count($kitem)>1) {
+				$key = trim($kitem[0]);
+				$val = trim($kitem[1]);
+				if (!empty($val)) $cookie[$key] = $val;
+			}
+		}
+		return $cookie;
+	}
+	
+	/**
+	 * 	 授权登陆后获取用户登陆信息
+	 */
+	public function get_login_info(){
+		if (!$this->cookie) return false;
+		$t = time().strval(mt_rand(100,999));
+		$send_snoopy = new Snoopy; 
+		$submit = 'https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxinit?r='.$t.'&skey='.urlencode($this->skey);
+		$send_snoopy->rawheaders['Cookie']= $this->cookie;
+		$send_snoopy->referer = "https://wx2.qq.com/";
+		$citems = $this->get_login_cookie(true);
+		$post = array(
+			"BaseRequest"=>array(
+				array(
+					"Uin"=>$citems['wxuin'],
+					"Sid"=>$citems['wxsid'],
+					"Skey"=>$this->skey,
+					"DeviceID"=>''
+				)
+			)
+		);
+		$send_snoopy->submit($submit,json_encode($post));
+		$this->log('login_info:'.$send_snoopy->results);
+		$result = json_decode($send_snoopy->results,true);
+		if ($result['BaseResponse']['Ret']<0) return false;
+		$this->_login_user = $result['User'];
+		return $result;
+	}
+	
+	/**
+	 *  获取头像
+	 *  @param string $url 传入从用户信息接口获取到的头像地址
+	 */
+	public function get_avatar($url) {
+		if (!$this->cookie) return false;
+		if (strpos($url, 'http')===false) {
+			$url = 'http://wx2.qq.com'.$url;
+		}
+		$send_snoopy = new Snoopy; 
+		$send_snoopy->rawheaders['Cookie']= $this->cookie;
+		$send_snoopy->referer = "https://wx2.qq.com/";
+		$send_snoopy->fetch($url);
+		$result = $send_snoopy->results;
+		if ($result) 
+			return $result;
+		else
+			return false;
+	}
+	
+	/**
+	 * 登出当前登陆用户
+	 */
+	public function logout(){
+		if (!$this->cookie) return false;
+		preg_match("/wxuin=(\w+);/",$this->cookie,$matches);
+		if (count($matches)>1) $uid = $matches[1];
+		preg_match("/wxsid=(\w+);/",$this->cookie,$matches);
+		if (count($matches)>1) $sid = $matches[1];
+		$this->log('logout: uid='.$uid.';sid='.$sid);
+		$send_snoopy = new Snoopy; 
+		$submit = 'https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxlogout?redirect=1&type=1';
+		$send_snoopy->rawheaders['Cookie']= $this->cookie;
+		$send_snoopy->referer = "https://wx2.qq.com/";
+		$send_snoopy->submit($submit,array('uin'=>$uid,'sid'=>$sid));
+		$this->deleteCookie($this->_cookiename);
+		return true;
+	}
+}

+ 923 - 0
old_version/wechatext.class.php

@@ -0,0 +1,923 @@
+<?php
+/**
+ *	微信公众平台PHP-SDK
+ *  Wechatext为非官方微信发送API
+ *  注: 用户id为通过getMsg()方法获取的FakeId值
+ *  主要实现如下功能:
+ *  send($id,$content) 向某用户id发送微信文字信息
+ *  getUserList($page,$pagesize,$groupid) 获取用户信息
+ *  getGroupList($page,$pagesize) 获取群组信息
+ *  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) 发送音频消息
+ *  sendVideo($id,$fid) 发送视频消息
+ *  getInfo($id) 根据id获取用户资料
+ *  getNewMsgNum($lastid) 获取从$lastid算起新消息的数目
+ *  getTopMsg() 获取最新一条消息的数据, 此方法获取的消息id可以作为检测新消息的$lastid依据
+ *  getMsg($lastid,$offset=0,$perpage=50,$day=0,$today=0,$star=0) 获取最新的消息列表, 列表将返回消息id, 用户id, 消息类型, 文字消息等参数
+ *  消息返回结构:  {"id":"消息id","type":"类型号(1为文字,2为图片,3为语音)","fileId":"0","hasReply":"0","fakeId":"用户uid","nickName":"昵称","dateTime":"时间戳","content":"文字内容"} 
+ *  getMsgImage($msgid,$mode='large') 若消息type类型为2, 调用此方法获取图片数据
+ *  getMsgVoice($msgid) 若消息type类型为3, 调用此方法获取语音数据
+ *  quickSetInterface($url, $token) 快速设置接口信息
+ *  getCommonInfo($dir) 获取公众账号基本信息, 其中包含:nickname,avatar,type,qrcode,appid,appsecret
+ *  @author dodge <dodgepudding@gmail.com>
+ *  @link https://github.com/dodgepudding/wechat-php-sdk
+ *  @version 1.2
+ *  
+ */
+
+include "snoopy.class.php";
+class Wechatext
+{
+	private $cookie;
+	private $_cookiename;
+	private $_cookieexpired = 3600;
+	private $_account;
+	private $_password;
+	private $_datapath = './data/cookie_';
+	private $debug;
+	private $_logcallback;
+	private $_token;
+	
+	public function __construct($options)
+	{
+		$this->_account = isset($options['account'])?$options['account']:'';
+		$this->_password = isset($options['password'])?$options['password']:'';
+		$this->_datapath = isset($options['datapath'])?$options['datapath']:$this->_datapath;
+		$this->debug = isset($options['debug'])?$options['debug']:false;
+		$this->_logcallback = isset($options['logcallback'])?$options['logcallback']:false;
+		$this->_cookiename = $this->_datapath.$this->_account;
+		$this->cookie = $this->getCookie($this->_cookiename);
+	}
+
+	/**
+	 * 主动发消息
+	 * @param  string $id      用户的uid(即FakeId)
+	 * @param  string $content 发送的内容
+	 */
+	public function send($id,$content)
+	{
+		$send_snoopy = new Snoopy; 
+		$post = array();
+		$post['tofakeid'] = $id;
+		$post['type'] = 1;
+		$post['token'] = $this->_token;
+		$post['content'] = $content;
+		$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 = "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;
+	}
+	
+	/**
+	 * 群发功能 纯文本
+	 * @param string $content
+	 * @return string
+	 */
+	public function mass($content) {
+		$send_snoopy = new Snoopy;
+		$post = array();
+		$post['type'] = 1;
+		$post['token'] = $this->_token;
+		$post['content'] = $content;
+		$post['ajax'] = 1;
+		$post['city']='';
+		$post['country']='';
+		$post['f']='json';
+		$post['groupid']='-1';
+		$post['imgcode']='';
+		$post['lang']='zh_CN';
+		$post['province']='';
+		$post['random']=  rand(0, 1);
+		$post['sex']=0;
+		$post['synctxnews']=0;
+		$post['synctxweibo']=0;
+		$post['t']='ajax-response';
+		$send_snoopy->referer = "https://mp.weixin.qq.com/cgi-bin/masssendpage?t=mass/send&token={$this->_token}&lang=zh_CN";
+		$send_snoopy->rawheaders['Cookie']= $this->cookie;
+		$submit = "https://mp.weixin.qq.com/cgi-bin/masssend";
+		$send_snoopy->submit($submit,$post);
+		$this->log($send_snoopy->results);
+		return $send_snoopy->results;
+	}
+	
+	/**
+	 * 群发功能 图文素材
+	 * @param int $appmsgid 图文素材ID
+	 * @return string
+	 */
+	function massNews($appmsgid){
+		$send_snoopy = new Snoopy;
+		$post = array();
+		$post['type'] = 10;
+		$post['token'] = $this->_token;
+		$post['appmsgid'] = $appmsgid;
+		$post['ajax'] = 1;
+		$post['city']='';
+		$post['country']='';
+		$post['f']='json';
+		$post['groupid']='-1';
+		$post['imgcode']='';
+		$post['lang']='zh_CN';
+		$post['province']='';
+		$post['random']=  rand(0, 1);
+		$post['sex']=0;
+		$post['synctxnews']=0;
+		$post['synctxweibo']=0;
+		$post['t']='ajax-response';
+		$send_snoopy->referer = "https://mp.weixin.qq.com/cgi-bin/masssendpage?t=mass/send&token={$this->_token}&lang=zh_CN";
+		$send_snoopy->rawheaders['Cookie']= $this->cookie;
+		$submit = "https://mp.weixin.qq.com/cgi-bin/masssend";
+		$send_snoopy->submit($submit,$post);
+		$this->log($send_snoopy->results);
+		return $send_snoopy->results;
+	}
+	
+	/**
+	 * 获取用户列表列表
+	 * @param $page 页码(从0开始)
+	 * @param $pagesize 每页大小
+	 * @param $groupid 分组id
+	 * @return array ({contacts:[{id:12345667,nick_name:"昵称",remark_name:"备注名",group_id:0},{}....]})
+	 */
+	function getUserList($page=0,$pagesize=10,$groupid=0){
+		$send_snoopy = new Snoopy;
+		$t = time().strval(mt_rand(100,999));
+		$send_snoopy->referer = "https://mp.weixin.qq.com/cgi-bin/contactmanage?t=user/index&pagesize=".$pagesize."&pageidx=".$page."&type=0&groupid=0&lang=zh_CN&token=".$this->_token;
+		$send_snoopy->rawheaders['Cookie']= $this->cookie;
+		$submit = "https://mp.weixin.qq.com/cgi-bin/contactmanage?t=user/index&pagesize=".$pagesize."&pageidx=".$page."&type=0&groupid=$groupid&lang=zh_CN&f=json&token=".$this->_token;
+		$send_snoopy->fetch($submit);
+		$result = $send_snoopy->results;
+		$this->log('userlist:'.$result);
+		$json = json_decode($result,true);
+		if (isset($json['contact_list'])) {
+			$json = json_decode($json['contact_list'],true);
+			if (isset($json['contacts']))
+				return $json['contacts'];
+		}
+		return false;
+	}
+	
+	/**
+	 * 获取分组列表
+	 * 
+	 */
+	function getGroupList(){
+		$send_snoopy = new Snoopy;
+		$t = time().strval(mt_rand(100,999));
+		$send_snoopy->referer = "https://mp.weixin.qq.com/cgi-bin/contactmanage?t=user/index&pagesize=10&pageidx=0&type=0&groupid=0&lang=zh_CN&token=".$this->_token;
+		$send_snoopy->rawheaders['Cookie']= $this->cookie;
+		$submit = "https://mp.weixin.qq.com/cgi-bin/contactmanage?t=user/index&pagesize=10&pageidx=0&type=0&groupid=0&lang=zh_CN&f=json&token=".$this->_token;
+		$send_snoopy->fetch($submit);
+		$result = $send_snoopy->results;
+		$this->log('userlist:'.$result);
+		$json = json_decode($result,true);
+		if (isset($json['group_list'])){
+			$json = json_decode($json['group_list'],true);
+			if (isset($json['groups']))
+				return $json['groups'];
+		}
+		return false;
+	}
+	
+	/**
+	 * 获取图文信息列表
+	 * @param $page 页码(从0开始)
+	 * @param $pagesize 每页大小
+	 * @return array
+	 */
+	public function getNewsList($page,$pagesize=10) {
+		$send_snoopy = new Snoopy;
+		$t = time().strval(mt_rand(100,999));
+		$type=10;
+		$begin = $page*$pagesize;
+		$send_snoopy->referer = "https://mp.weixin.qq.com/cgi-bin/masssendpage?t=mass/send&token=".$this->_token."&lang=zh_CN";
+		$send_snoopy->rawheaders['Cookie']= $this->cookie;
+		$submit = "https://mp.weixin.qq.com/cgi-bin/appmsg?token=".$this->_token."&lang=zh_CN&type=$type&action=list&begin=$begin&count=$pagesize&f=json&random=0.".$t;
+		$send_snoopy->fetch($submit);
+		$result = $send_snoopy->results;
+		$this->log('newslist:'.$result);
+		$json = json_decode($result,true);
+		if (isset($json['app_msg_info'])) {
+			return $json['app_msg_info'];
+		} 
+		return false;
+	}
+	
+	/**
+	 * 获取与指定用户的对话内容
+	 * @param  $fakeid
+	 * @return  array
+	 */
+	public function getDialogMsg($fakeid) {
+		$send_snoopy = new Snoopy;
+		$t = time().strval(mt_rand(100,999));
+		$send_snoopy->referer = "https://mp.weixin.qq.com/cgi-bin/masssendpage?t=mass/send&token=".$this->_token."&lang=zh_CN";
+		$send_snoopy->rawheaders['Cookie']= $this->cookie;
+		$submit = "https://mp.weixin.qq.com/cgi-bin/singlesendpage?t=message/send&action=index&tofakeid=".$fakeid."&token=".$this->_token."&lang=zh_CN&f=json&random=".$t;
+		$send_snoopy->fetch($submit);
+		$result = $send_snoopy->results;
+		$this->log('DialogMsg:'.$result);
+		$json = json_decode($result,true);
+		if (isset($json['page_info'])) {
+			return $json['page_info'];
+		}
+		return false;
+	}
+	
+	/**
+	 * 发送图文信息,必须从图文库里选取消息ID发送
+	 * @param  string $id      用户的uid(即FakeId)
+	 * @param  string $msgid 图文消息id
+	 */
+	public function sendNews($id,$msgid)
+	{
+		$send_snoopy = new Snoopy; 
+		$post = array();
+		$post['tofakeid'] = $id;
+		$post['type'] = 10;
+		$post['token'] = $this->_token;
+		$post['fid'] = $msgid;
+		$post['appmsgid'] = $msgid;
+		$post['error'] = 'false';
+		$post['ajax'] = 1;
+        $send_snoopy->referer = "https://mp.weixin.qq.com/cgi-bin/singlemsgpage?fromfakeid={$id}&msgid=&source=&count=20&t=wxm-singlechat&lang=zh_CN";
+		$send_snoopy->rawheaders['Cookie']= $this->cookie;
+		$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;
+	}
+	
+	/**
+	 * 上传附件(图片/音频/视频)
+	 * @param string $filepath 本地文件地址
+	 * @param int $type 文件类型: 2:图片 3:音频 4:视频
+	 */
+	public function uploadFile($filepath,$type=2) {
+		$send_snoopy = new Snoopy;
+		$send_snoopy->referer = "http://mp.weixin.qq.com/cgi-bin/indexpage?t=wxm-upload&lang=zh_CN&type=2&formId=1";
+		$t = time().strval(mt_rand(100,999));
+		$post = array('formId'=>'');
+		$postfile = array('uploadfile'=>$filepath);
+		$send_snoopy->rawheaders['Cookie']= $this->cookie;
+		$send_snoopy->set_submit_multipart();
+		$submit = "http://mp.weixin.qq.com/cgi-bin/uploadmaterial?cgi=uploadmaterial&type=$type&token=".$this->_token."&t=iframe-uploadfile&lang=zh_CN&formId=	file_from_".$t;
+		$send_snoopy->submit($submit,$post,$postfile);
+		$tmp = $send_snoopy->results;
+		$this->log('upload:'.$tmp);
+		preg_match("/formId,.*?\'(\d+)\'/",$tmp,$matches);
+		if (isset($matches[1])) {
+			return $matches[1];
+		}
+		return false;
+	}
+	
+	/**
+	 * 创建图文消息
+	 * @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
+	 * @param $type 文件类型
+	 */
+	public function sendFile($id,$fid,$type) {
+		$send_snoopy = new Snoopy; 
+		$post = array();
+		$post['tofakeid'] = $id;
+		$post['type'] = $type;
+		$post['token'] = $this->_token;
+		$post['fid'] = $fid;
+		$post['fileid'] = $fid;
+		$post['error'] = 'false';
+		$post['ajax'] = 1;
+        $send_snoopy->referer = "https://mp.weixin.qq.com/cgi-bin/singlemsgpage?fromfakeid={$id}&msgid=&source=&count=20&t=wxm-singlechat&lang=zh_CN";
+		$send_snoopy->rawheaders['Cookie']= $this->cookie;
+		$submit = "https://mp.weixin.qq.com/cgi-bin/singlesend?t=ajax-response";
+		$send_snoopy->submit($submit,$post);
+		$result = $send_snoopy->results;
+		$this->log('sendfile:'.$result);
+		$json = json_decode($result,true);
+		if ($json && $json['ret']==0) 
+			return true;
+		else
+			return false;
+	}
+	
+	/**
+	 * 获取素材库文件列表
+	 * @param $type 文件类型: 2:图片 3:音频 4:视频
+	 * @param $page 页码(从0开始)
+	 * @param $pagesize 每页大小
+	 * @return array
+	 */
+	public function getFileList($type,$page,$pagesize=10) {
+		$send_snoopy = new Snoopy;
+		$t = time().strval(mt_rand(100,999));
+		$begin = $page*$pagesize;
+		$send_snoopy->referer = "https://mp.weixin.qq.com/cgi-bin/masssendpage?t=mass/send&token=".$this->_token."&lang=zh_CN";
+		$send_snoopy->rawheaders['Cookie']= $this->cookie;
+		$submit = "https://mp.weixin.qq.com/cgi-bin/filepage?token=".$this->_token."&lang=zh_CN&type=$type&random=0.".$t."&begin=$begin&count=$pagesize&f=json";
+		$send_snoopy->fetch($submit);
+		$result = $send_snoopy->results;
+		$this->log('filelist:'.$result);
+		$json = json_decode($result,true);
+		if (isset($json['page_info']))
+			return $json['page_info'];
+		else
+			return false;
+	}
+	
+	/**
+	 * 发送图文信息,必须从库里选取文件ID发送
+	 * @param  string $id      用户的uid(即FakeId)
+	 * @param  string $fid 文件id
+	 */
+	public function sendImage($id,$fid)
+	{
+		return $this->sendFile($id,$fid,2);
+	}
+	
+	/**
+	 * 发送语音信息,必须从库里选取文件ID发送
+	 * @param  string $id      用户的uid(即FakeId)
+	 * @param  string $fid 语音文件id
+	 */
+	public function sendAudio($id,$fid)
+	{
+		return $this->sendFile($id,$fid,3);
+	}
+	
+	/**
+	 * 发送视频信息,必须从库里选取文件ID发送
+	 * @param  string $id      用户的uid(即FakeId)
+	 * @param  string $fid 视频文件id
+	 */
+	public function sendVideo($id,$fid)
+	{
+		return $this->sendFile($id,$fid,4);
+	}
+	
+	/**
+	 * 发送预览图文消息
+	 * @param string $account 账户名称(user_name)
+	 * @param string $title 标题
+	 * @param string $summary 摘要
+	 * @param string $content 内容
+	 * @param string $photoid 素材库里的图片id(可通过uploadFile上传后获取)
+	 * @param string $srcurl 原文链接
+	 * @return json
+	 */
+	public function sendPreview($account,$title,$summary,$content,$photoid,$srcurl='') {
+		$send_snoopy = new Snoopy;
+		$submit = "https://mp.weixin.qq.com/cgi-bin/operate_appmsg?sub=preview&t=ajax-appmsg-preview";
+		$send_snoopy->set_submit_normal();
+		$send_snoopy->rawheaders['Cookie']= $this->cookie;
+		$send_snoopy->referer = 'https://mp.weixin.qq.com/cgi-bin/operate_appmsg?sub=edit&t=wxm-appmsgs-edit-new&type=10&subtype=3&lang=zh_CN';
+		$post = array(
+				'AppMsgId'=>'',
+				'ajax'=>1,
+				'content0'=>$content,
+				'count'=>1,
+				'digest0'=>$summary,
+				'error'=>'false',
+				'fileid0'=>$photoid,
+				'preusername'=>$account,
+				'sourceurl0'=>$srcurl,
+				'title0'=>$title,
+		);
+		$post['token'] = $this->_token;
+		$send_snoopy->submit($submit,$post);
+		$tmp = $send_snoopy->results;
+		$this->log('sendpreview:'.$tmp);
+		$json = json_decode($tmp,true);
+		return $json;
+	}
+	
+	/**
+	 * 获取用户的信息
+	 * @param  string $id 用户的uid(即FakeId)
+	 * @return array  {fake_id:100001,nick_name:'昵称',user_name:'用户名',signature:'签名档',country:'中国',province:'广东',city:'广州',gender:'1',group_id:'0'},groups:{[id:0,name:'未分组',cnt:20]}
+	 */
+	public function getInfo($id)
+	{
+		$send_snoopy = new Snoopy; 
+		$send_snoopy->rawheaders['Cookie']= $this->cookie;
+		$t = time().strval(mt_rand(100,999));
+		$send_snoopy->referer = "https://mp.weixin.qq.com/cgi-bin/getmessage?t=wxm-message&lang=zh_CN&count=50&token=".$this->_token;
+		$submit = "https://mp.weixin.qq.com/cgi-bin/getcontactinfo";
+		$post = array('ajax'=>1,'lang'=>'zh_CN','random'=>'0.'.$t,'token'=>$this->_token,'t'=>'ajax-getcontactinfo','fakeid'=>$id);
+		$send_snoopy->submit($submit,$post);
+		$this->log($send_snoopy->results);
+		$result = json_decode($send_snoopy->results,true);
+		if(isset($result['contact_info'])){
+			return $result['contact_info'];
+		}
+		return false;
+	}
+	
+	/**
+	 * 获得头像数据
+	 *
+	 * @param FakeId $fakeid
+	 * @return JPG二进制数据
+	 */
+	public function getHeadImg($fakeid){
+		$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/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));
+		if(!$result){
+			return false;
+		}
+		return $result;
+	}
+
+	/**
+	 * 获取消息更新数目
+	 * @param int $lastid 最近获取的消息ID,为0时获取总消息数目
+	 * @return int 数目
+	 */
+	public function getNewMsgNum($lastid=0){
+		$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;
+		$submit = "https://mp.weixin.qq.com/cgi-bin/getnewmsgnum?t=ajax-getmsgnum&lastmsgid=".$lastid;
+		$post = array('ajax'=>1,'token'=>$this->_token);
+		$send_snoopy->submit($submit,$post);
+		$this->log($send_snoopy->results);
+		$result = json_decode($send_snoopy->results,1);
+		if(!$result){
+			return false;
+		}
+		return intval($result['newTotalMsgCount']);
+	}
+	
+	/**
+	 * 获取最新一条消息
+	 * @return array {"id":"最新一条id","type":"类型号(1为文字,2为图片,3为语音)","fileId":"0","hasReply":"0","fakeId":"用户uid","nickName":"昵称","dateTime":"时间戳","content":"文字内容","playLength":"0","length":"0","source":"","starred":"0","status":"4"}        
+	 */
+	public function getTopMsg(){
+		$send_snoopy = new Snoopy;
+		$send_snoopy->rawheaders['Cookie']= $this->cookie;
+		$send_snoopy->referer = "https://mp.weixin.qq.com/cgi-bin/message?t=message/list&count=20&day=7&lang=zh_CN&token=".$this->_token;
+		$submit = "https://mp.weixin.qq.com/cgi-bin/message?t=message/list&f=json&count=20&day=7&lang=zh_CN&token=".$this->_token;
+		$send_snoopy->fetch($submit);
+		$this->log($send_snoopy->results);
+		$result = $send_snoopy->results;
+		$json = json_decode($result,true);
+		if (isset($json['msg_items'])) {
+			$json = json_decode($json['msg_items'],true);
+			if(isset($json['msg_item']))
+				return array_shift($json['msg_item']);
+		}
+		return false;
+	}
+	
+	/**
+	 * 获取新消息
+	 * @param $lastid 传入最后的消息id编号,为0则从最新一条起倒序获取
+	 * @param $offset lastid起算第一条的偏移量
+	 * @param $perpage 每页获取多少条
+	 * @param $day 最近几天消息(0:今天,1:昨天,2:前天,3:更早,7:五天内)
+	 * @param $today 是否只显示今天的消息, 与$day参数不能同时大于0
+	 * @param $star 是否星标组信息
+	 * @return array[] 同getTopMsg()返回的字段结构相同
+	 */
+	public function getMsg($lastid=0,$offset=0,$perpage=20,$day=7,$today=0,$star=0){
+		$send_snoopy = new Snoopy; 
+		$send_snoopy->rawheaders['Cookie']= $this->cookie;
+		$send_snoopy->referer = "https://mp.weixin.qq.com/cgi-bin/message?t=message/list&lang=zh_CN&count=50&token=".$this->_token;
+		$lastid = $lastid===0 ? '':$lastid;
+		$addstar = $star?'&action=star':'';
+		$submit = "https://mp.weixin.qq.com/cgi-bin/message?t=message/list&f=json&lang=zh_CN{$addstar}&count=$perpage&timeline=$today&day=$day&frommsgid=$lastid&offset=$offset&token=".$this->_token;
+		$send_snoopy->fetch($submit);
+		$this->log($send_snoopy->results);
+		$result = $send_snoopy->results;
+		$json = json_decode($result,true);
+		if (isset($json['msg_items'])) {
+			$json = json_decode($json['msg_items'],true);
+			if(isset($json['msg_item']))
+				return $json['msg_item'];
+		}
+		return false;
+	}
+	
+	/**
+	 * 获取图片消息
+	 * @param int $msgid 消息id
+	 * @param string $mode 图片尺寸(large/small)
+	 * @return jpg二进制文件
+	 */
+	public function getMsgImage($msgid,$mode='large'){
+		$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/getimgdata?token=".$this->_token."&msgid=$msgid&mode=$mode&source=&fileId=0";
+		$send_snoopy->fetch($url);
+		$result = $send_snoopy->results;
+		$this->log('msg image:'.$msgid.';length:'.strlen($result));
+		if(!$result){
+			return false;
+		}
+		return $result;
+	}
+	
+	/**
+	 * 获取语音消息
+	 * @param int $msgid 消息id
+	 * @return mp3二进制文件
+	 */
+	public function getMsgVoice($msgid){
+		$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/getvoicedata?token=".$this->_token."&msgid=$msgid&fileId=0";
+		$send_snoopy->fetch($url);
+		$result = $send_snoopy->results;
+		$this->log('msg voice:'.$msgid.';length:'.strlen($result));
+		if(!$result){
+			return false;
+		}
+		return $result;
+	}
+
+	/**
+	 * 开启开发者模式
+	 */
+	public function openDevModel()
+	{
+		$send_snoopy = new Snoopy;
+		$send_snoopy->rawheaders['Cookie']= $this->cookie;
+		$send_snoopy->referer = "https://mp.weixin.qq.com/advanced/advanced?action=dev&t=advanced/dev&lang=zh_CN&token=".$this->_token;
+		$submit = "https://mp.weixin.qq.com/misc/skeyform?form=advancedswitchform&lang=zh_CN";
+		$post['flag']=1;
+        $post['type']=2;   
+        $post['token']=$this->_token;
+		$send_snoopy->submit($submit,$post);
+		$result = $send_snoopy->results;
+		$this->log($send_snoopy->results);
+		$json = json_decode($result,true);
+		if(!$result){
+			return false;
+		}
+		return true;
+	}
+
+	/**
+	 * 关闭编辑模式
+	 */
+	public function closeEditModel()
+	{
+		$send_snoopy = new Snoopy;
+		$send_snoopy->rawheaders['Cookie']= $this->cookie;
+		$send_snoopy->referer = "https://mp.weixin.qq.com/advanced/advanced?action=dev&t=advanced/dev&lang=zh_CN&token=".$this->_token;
+		$submit = "https://mp.weixin.qq.com/misc/skeyform?form=advancedswitchform&lang=zh_CN";
+		$post['flag']=0;
+        $post['type']=1;   
+        $post['token']=$this->_token;
+		$send_snoopy->submit($submit,$post);
+		$result = $send_snoopy->results;
+		$this->log($send_snoopy->results);
+		$json = json_decode($result,true);
+		if(!$result){
+			return false;
+		}
+		return true;
+	}
+
+	/**
+	 * 配置接口信息
+	 * @param  string $url      接口回调URL
+	 * @param  string $token    接口Token
+	 */
+	public function setUrlToken($url, $token)
+	{
+		$send_snoopy = new Snoopy;
+		$send_snoopy->rawheaders['Cookie']= $this->cookie;
+		$send_snoopy->referer = "https://mp.weixin.qq.com/advanced/advanced?action=interface&t=advanced/interface&lang=zh_CN&token=".$this->_token;
+		$submit = "https://mp.weixin.qq.com/advanced/callbackprofile?t=ajax-response&lang=zh_CN&token=".$this->_token;
+		$post['url'] = $url;
+		$post['callback_token'] = $token;
+		$send_snoopy->submit($submit,$post);
+		$result = $send_snoopy->results;
+		$this->log($send_snoopy->results);
+		$json = json_decode($result,true);
+		if ($json && $json['ret']==0) 
+			return true;
+		return false;
+	}
+
+	/**
+	 * 快速设置接口
+	 * @param  string $url      接口回调URL
+	 * @param  string $token    接口Token
+	 */
+	public function quickSetInterface($url, $token)
+	{
+		if ($this->closeEditModel() && $this->openDevModel() && $this->setUrlToken($url, $token))
+			return true;
+		return false;
+	}
+
+	/**
+	 * 获取公众账号基本信息
+	 * @param  [string] $dir [指定相对于网站根目录的下载路径,因为需要下载二维码和用户头像]
+	 * @return [array]       [公众账号信息,其中包含:nickname,avatar,type,qrcode,appid,appsecret]
+	 */
+	public function getCommonInfo($dir)
+	{
+		$userInfo = array();
+		$send_snoopy = new Snoopy; 
+		$send_snoopy->rawheaders['Cookie']= $this->cookie;
+		$send_snoopy->referer = "https://mp.weixin.qq.com/cgi-bin/message?t=message/list&count=20&day=7&lang=zh_CN&token=".$this->_token;
+		$url = "https://mp.weixin.qq.com/cgi-bin/home?t=home/index&lang=zh_CN&token=".$this->_token;
+		$send_snoopy->fetch($url);
+		$result = $send_snoopy->results;
+		// 分析首页内容,获取nickname,avatar,usertype
+		preg_match_all('/class=\"nickname\">(.*)<\/a>/', $result, $matches1);
+        preg_match_all('/<img src=\"(.*)\" class=\"avatar\"/', $result, $matches2);
+        preg_match_all('/<label for=\"\" class=\"type icon_service_label\">(.*)<\/label>/', $result, $matches3);
+        $userInfo["nickname"] = $nickname = $matches1[1][0];
+        if(strpos($nickname, '<') !== false)
+        {
+        	$userInfo["nickname"] = $nickname = substr($nickname, 0, strpos($nickname, '<'));
+        }
+        $userInfo["avatar"] = $avatar = $matches2[1][0];
+        if( ! empty($matches3[1][0]))
+        {
+            $userInfo["type"] = $usertype = $matches3[1][0];
+        }
+        else
+        {
+            $userInfo["type"] = $usertype = "订阅号";
+        }
+		$this->log('Analysis account info:'. "\nNickname:". $nickname. "\nAvatar:". $avatar. "\nUsertype:". $usertype);
+		// 分析设置页面,获取二维码
+		$send_snoopy = new Snoopy; 
+		$send_snoopy->rawheaders['Cookie']= $this->cookie;
+		$send_snoopy->referer = "https://mp.weixin.qq.com/cgi-bin/message?t=message/list&count=20&day=7&lang=zh_CN&token=".$this->_token;
+		$url = "https://mp.weixin.qq.com/cgi-bin/settingpage?t=setting/index&action=index&lang=zh_CN&token=".$this->_token;
+		$send_snoopy->fetch($url);
+		$result = $send_snoopy->results;
+		// $this->log("QRCODE contents:". $result);
+		preg_match_all('/<img src=\"(.*)\" width=\"150\"/', $result, $matches4);
+        $userInfo["qrcode"] = $qrcode = $matches4[1][0];
+        // downloads the avatar
+        $send_snoopy = new Snoopy; 
+		$send_snoopy->rawheaders['Cookie']= $this->cookie;
+		$send_snoopy->referer = "https://mp.weixin.qq.com/cgi-bin/settingpage?t=setting/index&action=index&lang=zh_CN&token=".$this->_token;
+		$url = "https://mp.weixin.qq.com". $avatar;
+		$send_snoopy->fetch($url);
+		$result = $send_snoopy->results;
+        $userInfo["avatar"] = $this->downloadImage($result, $dir. DIRECTORY_SEPARATOR. 'avatars');
+        // downloads the qrcode
+        $send_snoopy = new Snoopy; 
+		$send_snoopy->rawheaders['Cookie']= $this->cookie;
+		$send_snoopy->referer = "https://mp.weixin.qq.com/cgi-bin/settingpage?t=setting/index&action=index&lang=zh_CN&token=".$this->_token;
+		$url = "https://mp.weixin.qq.com". $qrcode;
+		$send_snoopy->fetch($url);
+		$result = $send_snoopy->results;
+        $userInfo["qrcode"] = $this->downloadImage($result, $dir. DIRECTORY_SEPARATOR. 'qrcodes');
+        // 获取appid和appsecret
+        $send_snoopy = new Snoopy; 
+		$send_snoopy->rawheaders['Cookie']= $this->cookie;
+		$send_snoopy->referer = "https://mp.weixin.qq.com/cgi-bin/settingpage?t=setting/index&action=index&lang=zh_CN&token=".$this->_token;
+		$url = "https://mp.weixin.qq.com/advanced/advanced?action=dev&t=advanced/dev&lang=zh_CN&token=".$this->_token;
+		$send_snoopy->fetch($url);
+		$result = $send_snoopy->results;
+
+		preg_match_all('/name:\"AppId\",value:\"(.*)\"/', $result, $matches_id);
+		preg_match_all('/name:\"AppSecret\",value:\"(.*)\"/', $result, $matches_secret);
+		
+        $userInfo["appid"] = $AppId = $matches_id[1][0];
+        $userInfo["appsecret"] = $AppSecret = $matches_secret[1][0];
+        
+		if(! empty($userInfo)){
+			return $userInfo;
+		}
+		return false;
+	}
+
+	/**
+	 * 下载图片资源
+	 * @param  [string] $from    [资源链接]
+	 * @param  [string] $dir     [相对于网站根目录]
+	 * @return [string]          [返回相对地址]
+	 */
+	public function downloadImage($from, $dir)
+	{
+	    $random_name =  str_replace('.', '', microtime(true)). rand(2, 10000);
+	    if( ! is_dir($dir))
+	    {
+	    	mkdir($dir, 0755, true);	
+	    }
+	    $savefile = preg_replace('/[\\\\\/]+/', DIRECTORY_SEPARATOR, $dir. '/'. $random_name);
+	    file_put_contents($savefile, $from);
+	    $filesize = filesize($savefile);
+	    $avatar_type = $this->checkImgType($savefile);
+	    if ($filesize <= 0 || $avatar_type=='unknown') 
+	    {
+	        unlink($savefile);
+	    }
+	    exec("mv $savefile ". $savefile. '.'. $avatar_type);
+	    return $dir. '/'. $random_name. '.'. $avatar_type;
+	}
+
+	/**
+	 * 检测图片类型
+	 * @param  [string] $imgName [文件路径]
+	 * @return [string]          [文件类型]
+	 */
+	public function checkImgType($imgName){
+	    $file = fopen($imgName, "rb");
+	    $bin = fread($file, 2);
+	    $strInfo  = @unpack("C2chars", $bin);
+	    $typeCode = intval($strInfo['chars1'].$strInfo['chars2']);
+	    switch($typeCode)
+	    {
+	        case '255216':
+	            return 'jpg';
+	            break;
+	        case '7173':
+	            return 'gif';
+	            break;
+	        case '13780':
+	            return 'png';
+	            break;
+	        case '6677':
+	            return 'bmp';
+	            break;
+	        default:
+	            return 'unknown';
+	            break;
+	    }
+	}
+	
+	/**
+	 * 模拟登录获取cookie
+	 * @return [type] [description]
+	 */
+	public function login(){
+		$snoopy = new Snoopy; 
+		$submit = "https://mp.weixin.qq.com/cgi-bin/login?lang=zh_CN";
+		$post["username"] = $this->_account;
+		$post["pwd"] = md5($this->_password);
+		$post["f"] = "json";
+		$post["imgcode"] = "";
+		$snoopy->referer = "https://mp.weixin.qq.com/";
+		$snoopy->submit($submit,$post);
+		$cookie = '';
+		$this->log($snoopy->results);
+		$result = json_decode($snoopy->results,true);
+		
+		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))
+				$cookie .=$match[1].'='.$match[2].'; ';
+		}
+		
+		preg_match("/token=(\d+)/i",$result['redirect_url'],$matches);
+		if($matches){
+			$this->_token = $matches[1];
+			$this->log('token:'.$this->_token);
+		}
+		$cookies='{"cookie":"'.$cookie.'","token":"'.$this->_token.'"}';
+		$this->saveCookie($this->_cookiename,$cookies);
+		return $cookie;
+	}
+
+	/**
+	 * 把cookie写入缓存
+	 * @param  string $filename 缓存文件名
+	 * @param  string $content  文件内容
+	 * @return bool
+	 */
+	public function saveCookie($filename,$content){
+		return file_put_contents($filename,$content);
+	}
+
+	/**
+	 * 读取cookie缓存内容
+	 * @param  string $filename 缓存文件名
+	 * @return string cookie
+	 */
+	public function getCookie($filename){
+		if (file_exists($filename)) {
+			$mtime = filemtime($filename);
+			if ($mtime<time()-$this->_cookieexpired) 
+				$data = '';
+			else
+				$data = file_get_contents($filename);
+		} else
+			$data = '';
+		if($data){
+			$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=".$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 =$login['token'];
+				$this->log('token:'.$this->_token);
+				return $login['cookie'];
+			}
+		}else{
+			return $this->login();
+		}
+	}
+
+	/**
+	 * 验证cookie的有效性
+	 * @return bool
+	 */
+	public function checkValid()
+	{
+		if (!$this->cookie || !$this->_token) return false;
+		$send_snoopy = new Snoopy; 
+		$post = array('ajax'=>1,'token'=>$this->_token);
+		$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;
+		if(json_decode($result,1)){
+			return true;
+		}else{
+			return false;
+		}
+	}
+	
+	private function log($log){
+		if ($this->debug && function_exists($this->_logcallback)) {
+			if (is_array($log)) $log = print_r($log,true);
+			return call_user_func($this->_logcallback,$log);
+		}
+	}
+	
+}

+ 450 - 0
old_version/wechatpay.class.php

@@ -0,0 +1,450 @@
+<?php
+/**
+ *	微信公众平台PHP-SDK, 旧版微信支付接口
+ *  @author  dodge <dodgepudding@gmail.com>
+ *  @link https://github.com/dodgepudding/wechat-php-sdk
+ *  @version 1.2
+ *  参考旧版文档 https://mp.weixin.qq.com/cgi-bin/readtemplate?t=business/course2_tmpl&lang=zh_CN
+ *  usage:
+ *   $options = array(
+ *			'appid'=>'wxdk1234567890', //填写高级调用功能的app id
+ *			'appsecret'=>'xxxxxxxxxxxxxxxxxxx', //填写高级调用功能的密钥
+ *			'partnerid'=>'88888888', //财付通商户身份标识
+ *			'partnerkey'=>'', //财付通商户权限密钥Key
+ *			'paysignkey'=>'' //商户签名密钥Key
+ *		);
+ *	 $payObj = new Wechatpay($options);
+ *   $package = $payObj->createPackage($out_trade_no,$body,$total_fee,$notify_url,$spbill_create_ip,$fee_type,$bank_type,$input_charset,$time_start,$time_expire,$transport_fee,$product_fee,$goods_tag,$attach);
+ *
+ */
+class Wechatpay
+{
+	const API_URL_PREFIX = 'https://api.weixin.qq.com/cgi-bin';
+	const AUTH_URL = '/token?grant_type=client_credential&';
+	const API_BASE_URL_PREFIX = 'https://api.weixin.qq.com'; //以下API接口URL需要使用此前缀
+	const PAY_DELIVERNOTIFY = '/pay/delivernotify?';
+	const PAY_ORDERQUERY = '/pay/orderquery?';
+
+	private $appid;
+	private $appsecret;
+	private $access_token;
+	private $user_token;
+	private $partnerid;
+	private $partnerkey;
+	private $paysignkey;
+
+	public $debug =  false;
+	public $errCode = 40001;
+	public $errMsg = "no access";
+	private $_logcallback;
+
+	public function __construct($options)
+	{
+		$this->appid = isset($options['appid'])?$options['appid']:'';
+		$this->appsecret = isset($options['appsecret'])?$options['appsecret']:'';
+		$this->partnerid = isset($options['partnerid'])?$options['partnerid']:'';
+		$this->partnerkey = isset($options['partnerkey'])?$options['partnerkey']:'';
+		$this->paysignkey = isset($options['paysignkey'])?$options['paysignkey']:'';
+		$this->debug = isset($options['debug'])?$options['debug']:false;
+		$this->_logcallback = isset($options['logcallback'])?$options['logcallback']:false;
+	}
+
+    private function log($log){
+    		if ($this->debug && function_exists($this->_logcallback)) {
+    			if (is_array($log)) $log = print_r($log,true);
+    			return call_user_func($this->_logcallback,$log);
+    		}
+    }
+
+	/**
+	 * GET 请求
+	 * @param string $url
+	 */
+	private function http_get($url){
+		$oCurl = curl_init();
+		if(stripos($url,"https://")!==FALSE){
+			curl_setopt($oCurl, CURLOPT_SSL_VERIFYPEER, FALSE);
+			curl_setopt($oCurl, CURLOPT_SSL_VERIFYHOST, FALSE);
+			curl_setopt($oCurl, CURLOPT_SSLVERSION, 1); //CURL_SSLVERSION_TLSv1
+		}
+		curl_setopt($oCurl, CURLOPT_URL, $url);
+		curl_setopt($oCurl, CURLOPT_RETURNTRANSFER, 1 );
+		$sContent = curl_exec($oCurl);
+		$aStatus = curl_getinfo($oCurl);
+		curl_close($oCurl);
+		if(intval($aStatus["http_code"])==200){
+			return $sContent;
+		}else{
+			return false;
+		}
+	}
+
+	/**
+	 * POST 请求
+	 * @param string $url
+	 * @param array $param
+	 * @param boolean $post_file 是否文件上传
+	 * @return string content
+	 */
+	private function http_post($url,$param,$post_file=false){
+		$oCurl = curl_init();
+		if(stripos($url,"https://")!==FALSE){
+			curl_setopt($oCurl, CURLOPT_SSL_VERIFYPEER, FALSE);
+			curl_setopt($oCurl, CURLOPT_SSL_VERIFYHOST, false);
+			curl_setopt($oCurl, CURLOPT_SSLVERSION, 1); //CURL_SSLVERSION_TLSv1
+		}
+		if (is_string($param) || $post_file) {
+			$strPOST = $param;
+		} else {
+			$aPOST = array();
+			foreach($param as $key=>$val){
+				$aPOST[] = $key."=".urlencode($val);
+			}
+			$strPOST =  join("&", $aPOST);
+		}
+		curl_setopt($oCurl, CURLOPT_URL, $url);
+		curl_setopt($oCurl, CURLOPT_RETURNTRANSFER, 1 );
+		curl_setopt($oCurl, CURLOPT_POST,true);
+		curl_setopt($oCurl, CURLOPT_POSTFIELDS,$strPOST);
+		$sContent = curl_exec($oCurl);
+		$aStatus = curl_getinfo($oCurl);
+		curl_close($oCurl);
+		if(intval($aStatus["http_code"])==200){
+			return $sContent;
+		}else{
+			return false;
+		}
+	}
+
+	/**
+	 * 通用auth验证方法,暂时仅用于菜单更新操作
+	 * @param string $appid
+	 * @param string $appsecret
+	 * @param string $token 手动指定access_token,非必要情况不建议用
+	 */
+	public function checkAuth($appid='',$appsecret='',$token=''){
+		if (!$appid || !$appsecret) {
+			$appid = $this->appid;
+			$appsecret = $this->appsecret;
+		}
+		if ($token) { //手动指定token,优先使用
+		    $this->access_token=$token;
+		    return $this->access_token;
+		}
+		//TODO: get the cache access_token
+		$result = $this->http_get(self::API_URL_PREFIX.self::AUTH_URL.'appid='.$appid.'&secret='.$appsecret);
+		if ($result)
+		{
+			$json = json_decode($result,true);
+			if (!$json || isset($json['errcode'])) {
+				$this->errCode = $json['errcode'];
+				$this->errMsg = $json['errmsg'];
+				return false;
+			}
+			$this->access_token = $json['access_token'];
+			$expire = $json['expires_in'] ? intval($json['expires_in'])-100 : 3600;
+			//TODO: cache access_token
+			return $this->access_token;
+		}
+		return false;
+	}
+
+	/**
+	 * 删除验证数据
+	 * @param string $appid
+	 */
+	public function resetAuth($appid=''){
+		if (!$appid) $appid = $this->appid;
+		$this->access_token = '';
+		//TODO: remove cache
+		return true;
+	}
+
+	/**
+	 * 微信api不支持中文转义的json结构
+	 * @param array $arr
+	 */
+	static function json_encode($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 [] = self::json_encode ( $value ); /* :RECURSION: */
+				else
+					$parts [] = '"' . $key . '":' . self::json_encode ( $value ); /* :RECURSION: */
+			} else {
+				$str = '';
+				if (! $is_list)
+					$str = '"' . $key . '":';
+				//Custom handling for multiple data types
+				if (!is_string ( $value ) && 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
+	}
+
+	/**
+	 * 获取签名
+	 * @param array $arrdata 签名数组
+	 * @param string $method 签名方法
+	 * @return boolean|string 签名值
+	 */
+	public function getSignature($arrdata,$method="sha1") {
+		if (!function_exists($method)) return false;
+		ksort($arrdata);
+		$paramstring = "";
+		foreach($arrdata as $key => $value)
+		{
+			if(strlen($paramstring) == 0)
+				$paramstring .= $key . "=" . $value;
+			else
+				$paramstring .= "&" . $key . "=" . $value;
+		}
+		$paySign = $method($paramstring);
+		return $paySign;
+	}
+
+	/**
+	 * 生成随机字串
+	 * @param number $length 长度,默认为16,最长为32字节
+	 * @return string
+	 */
+	public function generateNonceStr($length=16){
+		// 密码字符集,可任意添加你需要的字符
+		$chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+		$str = "";
+		for($i = 0; $i < $length; $i++)
+		{
+			$str .= $chars[mt_rand(0, strlen($chars) - 1)];
+		}
+		return $str;
+	}
+
+	/**
+	 * 生成原生支付url
+	 * @param number $productid 商品编号,最长为32字节
+	 * @return string
+	 */
+	public function createNativeUrl($productid){
+		    $nativeObj["appid"] = $this->appid;
+		    $nativeObj["appkey"] = $this->paysignkey;
+		    $nativeObj["productid"] = urlencode($productid);
+		    $nativeObj["timestamp"] = time();
+		    $nativeObj["noncestr"] = $this->generateNonceStr();
+		    $nativeObj["sign"] = $this->getSignature($nativeObj);
+		    unset($nativeObj["appkey"]);
+		    $bizString = "";
+		    foreach($nativeObj as $key => $value)
+		    {
+			if(strlen($bizString) == 0)
+				$bizString .= $key . "=" . $value;
+			else
+				$bizString .= "&" . $key . "=" . $value;
+		    }
+		    return "weixin://wxpay/bizpayurl?".$bizString;
+		    //weixin://wxpay/bizpayurl?sign=XXXXX&appid=XXXXXX&productid=XXXXXX&timestamp=XXXXXX&noncestr=XXXXXX
+	}
+
+
+	/**
+	 * 生成订单package字符串
+	 * @param string $out_trade_no 必填,商户系统内部的订单号,32个字符内,确保在商户系统唯一
+	 * @param string $body 必填,商品描述,128 字节以下
+	 * @param int $total_fee 必填,订单总金额,单位为分
+	 * @param string $notify_url 必填,支付完成通知回调接口,255 字节以内
+	 * @param string $spbill_create_ip 必填,用户终端IP,IPV4字串,15字节内
+	 * @param int $fee_type 必填,现金支付币种,默认1:人民币
+	 * @param string $bank_type 必填,银行通道类型,默认WX
+	 * @param string $input_charset 必填,传入参数字符编码,默认UTF-8,取值有UTF-8和GBK
+	 * @param string $time_start 交易起始时间,订单生成时间,格式yyyyMMddHHmmss
+	 * @param string $time_expire 交易结束时间,也是订单失效时间
+	 * @param int $transport_fee 物流费用,单位为分
+	 * @param int $product_fee 商品费用,单位为分,必须保证 transport_fee + product_fee=total_fee
+	 * @param string $goods_tag 商品标记,优惠券时可能用到
+	 * @param string $attach 附加数据,notify接口原样返回
+	 * @return string
+	 */
+	public function 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=""){
+			$arrdata = array("bank_type" => $bank_type, "body" => $body, "partner" => $this->partnerid, "out_trade_no" => $out_trade_no, "total_fee" => $total_fee, "fee_type" => $fee_type, "notify_url" => $notify_url, "spbill_create_ip" => $spbill_create_ip, "input_charset" => $input_charset);
+			if ($time_start)  $arrdata['time_start'] = $time_start;
+			if ($time_expire)  $arrdata['time_expire'] = $time_expire;
+			if ($transport_fee)  $arrdata['transport_fee'] = $transport_fee;
+			if ($product_fee)  $arrdata['product_fee'] = $product_fee;
+			if ($goods_tag)  $arrdata['goods_tag'] = $goods_tag;
+			if ($attach)  $arrdata['attach'] = $attach;
+			ksort($arrdata);
+			$paramstring = "";
+			foreach($arrdata as $key => $value)
+			{
+			if(strlen($paramstring) == 0)
+				$paramstring .= $key . "=" . $value;
+				else
+				$paramstring .= "&" . $key . "=" . $value;
+			}
+			$stringSignTemp = $paramstring . "&key=" . $this->partnerkey;
+			$signValue = strtoupper(md5($stringSignTemp));
+			$package = http_build_query($arrdata) . "&sign=" . $signValue;
+			return $package;
+	}
+
+	/**
+	 * 支付签名(paySign)生成方法
+	 * @param string $package 订单详情字串
+	 * @param string $timeStamp 当前时间戳(需与JS输出的一致)
+	 * @param string $nonceStr 随机串(需与JS输出的一致)
+	 * @return string 返回签名字串
+	 */
+	public function getPaySign($package, $timeStamp, $nonceStr){
+		$arrdata = array("appid" => $this->appid, "timestamp" => $timeStamp, "noncestr" => $nonceStr, "package" => $package, "appkey" => $this->paysignkey);
+		$paySign = $this->getSignature($arrdata);
+		return $paySign;
+	}
+
+	/**
+	 * 回调通知签名验证
+	 * @param array $orderxml 返回的orderXml的数组表示,留空则自动从post数据获取
+	 * @return boolean
+	 */
+	public function checkOrderSignature($orderxml=''){
+		if (!$orderxml) {
+			$postStr = file_get_contents("php://input");
+			if (!empty($postStr)) {
+				$orderxml = (array)simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
+			} else return false;
+		}
+		$arrdata = array('appid'=>$orderxml['AppId'],'appkey'=>$this->paysignkey,'timestamp'=>$orderxml['TimeStamp'],'noncestr'=>$orderxml['NonceStr'],'openid'=>$orderxml['OpenId'],'issubscribe'=>$orderxml['IsSubscribe']);
+		$paySign = $this->getSignature($arrdata);
+		if ($paySign!=$orderxml['AppSignature']) return false;
+		return true;
+	}
+
+	/**
+	 * 发货通知
+	 * @param string $openid 用户open_id
+	 * @param string $transid 交易单号
+	 * @param string $out_trade_no 第三方订单号
+	 * @param int $status 0:发货失败;1:已发货
+	 * @param string $msg 失败原因
+	 * @return boolean|array
+	 */
+	public function sendPayDeliverNotify($openid,$transid,$out_trade_no,$status=1,$msg='ok'){
+		if (!$this->access_token && !$this->checkAuth()) return false;
+		$postdata = array(
+				"appid"=>$this->appid,
+				"appkey"=>$this->paysignkey,
+				"openid"=>$openid,
+				"transid"=>strval($transid),
+				"out_trade_no"=>strval($out_trade_no),
+				"deliver_timestamp"=>strval(time()),
+				"deliver_status"=>strval($status),
+				"deliver_msg"=>$msg,
+		);
+		$postdata['app_signature'] = $this->getSignature($postdata);
+		$postdata['sign_method'] = 'sha1';
+		unset($postdata['appkey']);
+		$result = $this->http_post(self::API_BASE_URL_PREFIX.self::PAY_DELIVERNOTIFY.'access_token='.$this->access_token,self::json_encode($postdata));
+		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 string $out_trade_no 订单号
+	 * @return boolean|array
+	 */
+	public function getPayOrder($out_trade_no) {
+		if (!$this->access_token && !$this->checkAuth()) return false;
+		$sign = strtoupper(md5("out_trade_no=$out_trade_no&partner={$this->partnerid}&key={$this->partnerkey}"));
+		$postdata = array(
+				"appid"=>$this->appid,
+				"appkey"=>$this->paysignkey,
+				"package"=>"out_trade_no=$out_trade_no&partner={$this->partnerid}&sign=$sign",
+				"timestamp"=>strval(time()),
+		);
+		$postdata['app_signature'] = $this->getSignature($postdata);
+		$postdata['sign_method'] = 'sha1';
+		unset($postdata['appkey']);
+		$result = $this->http_post(self::API_BASE_URL_PREFIX.self::PAY_ORDERQUERY.'access_token='.$this->access_token,self::json_encode($postdata));
+		if ($result)
+		{
+			$json = json_decode($result,true);
+			if (!$json || !empty($json['errcode'])) {
+				$this->errCode = $json['errcode'];
+				$this->errMsg = $json['errmsg'].json_encode($postdata);
+				return false;
+			}
+			return $json["order_info"];
+		}
+		return false;
+	}
+	
+	/**
+	 * 设置用户授权密钥
+	 * @param string $user_token
+	 * @return string
+	 */
+	public function setUserToken($user_token) {
+		return $this->user_token = $user_token;
+	}
+
+	/**
+	 * 获取收货地址JS的签名
+	 * @tutorial 参考weixin.js脚本的WeixinJS.editAddress方法调用
+	 * @param string $appId
+	 * @param string $url
+	 * @param int $timeStamp
+	 * @param string $nonceStr
+	 * @param string $user_token
+	 * @return Ambigous <boolean, string>
+	 */
+	public function getAddrSign($url, $timeStamp, $nonceStr, $user_token=''){
+		if (!$user_token) $user_token = $this->user_token;
+		if (!$user_token) {
+			$this->errMsg = 'no user access token found!';
+			return false;
+		}
+		$url = htmlspecialchars_decode($url);
+		$arrdata = array(
+				'appid'=>$this->appid,
+				'url'=>$url,
+				'timestamp'=>strval($timeStamp),
+				'noncestr'=>$nonceStr,
+				'accesstoken'=>$user_token
+		);
+		return $this->getSignature($arrdata);
+	}
+}

+ 23 - 240
wechat.class.php

@@ -9,10 +9,7 @@
  *			'token'=>'tokenaccesskey', //填写你设定的key
  *			'encodingaeskey'=>'encodingaeskey', //填写加密用的EncodingAESKey
  *			'appid'=>'wxdk1234567890', //填写高级调用功能的app id
- *			'appsecret'=>'xxxxxxxxxxxxxxxxxxx', //填写高级调用功能的密钥
- *			'partnerid'=>'88888888', //财付通商户身份标识
- *			'partnerkey'=>'', //财付通商户权限密钥Key
- *			'paysignkey'=>'' //商户签名密钥Key
+ *			'appsecret'=>'xxxxxxxxxxxxxxxxxxx' //填写高级调用功能的密钥
  *		);
  *	 $weObj = new Wechat($options);
  *   $weObj->valid();
@@ -117,8 +114,6 @@ class Wechat
 	const OAUTH_REFRESH_URL = '/sns/oauth2/refresh_token?';
 	const OAUTH_USERINFO_URL = '/sns/userinfo?';
 	const OAUTH_AUTH_URL = '/sns/auth?';
-	const PAY_DELIVERNOTIFY = '/pay/delivernotify?';
-	const PAY_ORDERQUERY = '/pay/orderquery?';
 	///多客服相关地址
 	const CUSTOM_SERVICE_GET_RECORD = '/customservice/getrecord?';
 	const CUSTOM_SERVICE_GET_KFLIST = '/customservice/getkflist?';
@@ -185,9 +180,6 @@ class Wechat
 		$this->encodingAesKey = isset($options['encodingaeskey'])?$options['encodingaeskey']:'';
 		$this->appid = isset($options['appid'])?$options['appid']:'';
 		$this->appsecret = isset($options['appsecret'])?$options['appsecret']:'';
-		$this->partnerid = isset($options['partnerid'])?$options['partnerid']:'';
-		$this->partnerkey = isset($options['partnerkey'])?$options['partnerkey']:'';
-		$this->paysignkey = isset($options['paysignkey'])?$options['paysignkey']:'';
 		$this->debug = isset($options['debug'])?$options['debug']:false;
 		$this->_logcallback = isset($options['logcallback'])?$options['logcallback']:false;
 	}
@@ -1231,6 +1223,27 @@ class Wechat
 	}
 
 	/**
+	 * 获取签名
+	 * @param array $arrdata 签名数组
+	 * @param string $method 签名方法
+	 * @return boolean|string 签名值
+	 */
+	public function getSignature($arrdata,$method="sha1") {
+		if (!function_exists($method)) return false;
+		ksort($arrdata);
+		$paramstring = "";
+		foreach($arrdata as $key => $value)
+		{
+			if(strlen($paramstring) == 0)
+				$paramstring .= $key . "=" . $value;
+			else
+				$paramstring .= "&" . $key . "=" . $value;
+		}
+		$paySign = $method($paramstring);
+		return $paySign;
+	}
+	
+	/**
 	 * 获取微信服务器IP地址列表
 	 * @return array('127.0.0.1','127.0.0.1')
 	 */
@@ -1967,237 +1980,6 @@ class Wechat
 	}
 
 	/**
-	 * 获取签名
-	 * @param array $arrdata 签名数组
-	 * @param string $method 签名方法
-	 * @return boolean|string 签名值
-	 */
-	public function getSignature($arrdata,$method="sha1") {
-		if (!function_exists($method)) return false;
-		ksort($arrdata);
-		$paramstring = "";
-		foreach($arrdata as $key => $value)
-		{
-			if(strlen($paramstring) == 0)
-				$paramstring .= $key . "=" . $value;
-			else
-				$paramstring .= "&" . $key . "=" . $value;
-		}
-		$paySign = $method($paramstring);
-		return $paySign;
-	}
-
-	/**
-	 * 生成随机字串
-	 * @param number $length 长度,默认为16,最长为32字节
-	 * @return string
-	 */
-	public function generateNonceStr($length=16){
-		// 密码字符集,可任意添加你需要的字符
-		$chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
-		$str = "";
-		for($i = 0; $i < $length; $i++)
-		{
-			$str .= $chars[mt_rand(0, strlen($chars) - 1)];
-		}
-		return $str;
-	}
-
-	/**
-	 * 生成原生支付url
-	 * @param number $productid 商品编号,最长为32字节
-	 * @return string
-	 */
-	public function createNativeUrl($productid){
-		    $nativeObj["appid"] = $this->appid;
-		    $nativeObj["appkey"] = $this->paysignkey;
-		    $nativeObj["productid"] = urlencode($productid);
-		    $nativeObj["timestamp"] = time();
-		    $nativeObj["noncestr"] = $this->generateNonceStr();
-		    $nativeObj["sign"] = $this->getSignature($nativeObj);
-		    unset($nativeObj["appkey"]);
-		    $bizString = "";
-		    foreach($nativeObj as $key => $value)
-		    {
-			if(strlen($bizString) == 0)
-				$bizString .= $key . "=" . $value;
-			else
-				$bizString .= "&" . $key . "=" . $value;
-		    }
-		    return "weixin://wxpay/bizpayurl?".$bizString;
-		    //weixin://wxpay/bizpayurl?sign=XXXXX&appid=XXXXXX&productid=XXXXXX&timestamp=XXXXXX&noncestr=XXXXXX
-	}
-
-
-	/**
-	 * 生成订单package字符串
-	 * @param string $out_trade_no 必填,商户系统内部的订单号,32个字符内,确保在商户系统唯一
-	 * @param string $body 必填,商品描述,128 字节以下
-	 * @param int $total_fee 必填,订单总金额,单位为分
-	 * @param string $notify_url 必填,支付完成通知回调接口,255 字节以内
-	 * @param string $spbill_create_ip 必填,用户终端IP,IPV4字串,15字节内
-	 * @param int $fee_type 必填,现金支付币种,默认1:人民币
-	 * @param string $bank_type 必填,银行通道类型,默认WX
-	 * @param string $input_charset 必填,传入参数字符编码,默认UTF-8,取值有UTF-8和GBK
-	 * @param string $time_start 交易起始时间,订单生成时间,格式yyyyMMddHHmmss
-	 * @param string $time_expire 交易结束时间,也是订单失效时间
-	 * @param int $transport_fee 物流费用,单位为分
-	 * @param int $product_fee 商品费用,单位为分,必须保证 transport_fee + product_fee=total_fee
-	 * @param string $goods_tag 商品标记,优惠券时可能用到
-	 * @param string $attach 附加数据,notify接口原样返回
-	 * @return string
-	 */
-	public function 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=""){
-			$arrdata = array("bank_type" => $bank_type, "body" => $body, "partner" => $this->partnerid, "out_trade_no" => $out_trade_no, "total_fee" => $total_fee, "fee_type" => $fee_type, "notify_url" => $notify_url, "spbill_create_ip" => $spbill_create_ip, "input_charset" => $input_charset);
-			if ($time_start)  $arrdata['time_start'] = $time_start;
-			if ($time_expire)  $arrdata['time_expire'] = $time_expire;
-			if ($transport_fee)  $arrdata['transport_fee'] = $transport_fee;
-			if ($product_fee)  $arrdata['product_fee'] = $product_fee;
-			if ($goods_tag)  $arrdata['goods_tag'] = $goods_tag;
-			if ($attach)  $arrdata['attach'] = $attach;
-			ksort($arrdata);
-			$paramstring = "";
-			foreach($arrdata as $key => $value)
-			{
-			if(strlen($paramstring) == 0)
-				$paramstring .= $key . "=" . $value;
-				else
-				$paramstring .= "&" . $key . "=" . $value;
-			}
-			$stringSignTemp = $paramstring . "&key=" . $this->partnerkey;
-			$signValue = strtoupper(md5($stringSignTemp));
-			$package = http_build_query($arrdata) . "&sign=" . $signValue;
-			return $package;
-	}
-
-	/**
-	 * 支付签名(paySign)生成方法
-	 * @param string $package 订单详情字串
-	 * @param string $timeStamp 当前时间戳(需与JS输出的一致)
-	 * @param string $nonceStr 随机串(需与JS输出的一致)
-	 * @return string 返回签名字串
-	 */
-	public function getPaySign($package, $timeStamp, $nonceStr){
-		$arrdata = array("appid" => $this->appid, "timestamp" => $timeStamp, "noncestr" => $nonceStr, "package" => $package, "appkey" => $this->paysignkey);
-		$paySign = $this->getSignature($arrdata);
-		return $paySign;
-	}
-
-	/**
-	 * 回调通知签名验证
-	 * @param array $orderxml 返回的orderXml的数组表示,留空则自动从post数据获取
-	 * @return boolean
-	 */
-	public function checkOrderSignature($orderxml=''){
-		if (!$orderxml) {
-			$postStr = file_get_contents("php://input");
-			if (!empty($postStr)) {
-				$orderxml = (array)simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
-			} else return false;
-		}
-		$arrdata = array('appid'=>$orderxml['AppId'],'appkey'=>$this->paysignkey,'timestamp'=>$orderxml['TimeStamp'],'noncestr'=>$orderxml['NonceStr'],'openid'=>$orderxml['OpenId'],'issubscribe'=>$orderxml['IsSubscribe']);
-		$paySign = $this->getSignature($arrdata);
-		if ($paySign!=$orderxml['AppSignature']) return false;
-		return true;
-	}
-
-	/**
-	 * 发货通知
-	 * @param string $openid 用户open_id
-	 * @param string $transid 交易单号
-	 * @param string $out_trade_no 第三方订单号
-	 * @param int $status 0:发货失败;1:已发货
-	 * @param string $msg 失败原因
-	 * @return boolean|array
-	 */
-	public function sendPayDeliverNotify($openid,$transid,$out_trade_no,$status=1,$msg='ok'){
-		if (!$this->access_token && !$this->checkAuth()) return false;
-		$postdata = array(
-				"appid"=>$this->appid,
-				"appkey"=>$this->paysignkey,
-				"openid"=>$openid,
-				"transid"=>strval($transid),
-				"out_trade_no"=>strval($out_trade_no),
-				"deliver_timestamp"=>strval(time()),
-				"deliver_status"=>strval($status),
-				"deliver_msg"=>$msg,
-		);
-		$postdata['app_signature'] = $this->getSignature($postdata);
-		$postdata['sign_method'] = 'sha1';
-		unset($postdata['appkey']);
-		$result = $this->http_post(self::API_BASE_URL_PREFIX.self::PAY_DELIVERNOTIFY.'access_token='.$this->access_token,self::json_encode($postdata));
-		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 string $out_trade_no 订单号
-	 * @return boolean|array
-	 */
-	public function getPayOrder($out_trade_no) {
-		if (!$this->access_token && !$this->checkAuth()) return false;
-		$sign = strtoupper(md5("out_trade_no=$out_trade_no&partner={$this->partnerid}&key={$this->partnerkey}"));
-		$postdata = array(
-				"appid"=>$this->appid,
-				"appkey"=>$this->paysignkey,
-				"package"=>"out_trade_no=$out_trade_no&partner={$this->partnerid}&sign=$sign",
-				"timestamp"=>strval(time()),
-		);
-		$postdata['app_signature'] = $this->getSignature($postdata);
-		$postdata['sign_method'] = 'sha1';
-		unset($postdata['appkey']);
-		$result = $this->http_post(self::API_BASE_URL_PREFIX.self::PAY_ORDERQUERY.'access_token='.$this->access_token,self::json_encode($postdata));
-		if ($result)
-		{
-			$json = json_decode($result,true);
-			if (!$json || !empty($json['errcode'])) {
-				$this->errCode = $json['errcode'];
-				$this->errMsg = $json['errmsg'].json_encode($postdata);
-				return false;
-			}
-			return $json["order_info"];
-		}
-		return false;
-	}
-
-	/**
-	 * 获取收货地址JS的签名
-	 * @tutorial 参考weixin.js脚本的WeixinJS.editAddress方法调用
-	 * @param string $appId
-	 * @param string $url
-	 * @param int $timeStamp
-	 * @param string $nonceStr
-	 * @param string $user_token
-	 * @return Ambigous <boolean, string>
-	 */
-	public function getAddrSign($url, $timeStamp, $nonceStr, $user_token=''){
-		if (!$user_token) $user_token = $this->user_token;
-		if (!$user_token) {
-			$this->errMsg = 'no user access token found!';
-			return false;
-		}
-		$url = htmlspecialchars_decode($url);
-		$arrdata = array(
-				'appid'=>$this->appid,
-				'url'=>$url,
-				'timestamp'=>strval($timeStamp),
-				'noncestr'=>$nonceStr,
-				'accesstoken'=>$user_token
-		);
-		return $this->getSignature($arrdata);
-	}
-
-	/**
 	 * 模板消息 设置所属行业
 	 * @param int $id1  公众号模板消息所属行业编号,参看官方开发文档 行业代码
 	 * @param int $id2  同$id1。但如果只有一个行业,此参数可省略
@@ -2271,6 +2053,7 @@ class Wechat
 		}
 	 * @return boolean|array
 	 */
+	
 	public function sendTemplateMessage($data){
 		if (!$this->access_token && !$this->checkAuth()) return false;
 		$result = $this->http_post(self::API_URL_PREFIX.self::TEMPLATE_SEND_URL.'access_token='.$this->access_token,self::json_encode($data));