dever 6 years ago
parent
commit
ae5c9d4ebb

+ 82 - 0
component/config/wechat.php

@@ -0,0 +1,82 @@
+<?php
+# wechat基本配置
+
+# 基本的component token
+$config['token'] = array
+(
+	'method' => 'post',
+	'json' => true,
+	'url' => 'https://api.weixin.qq.com/cgi-bin/component/api_component_token?',
+	'param' => array
+	(
+		'component_appid' => 'appid',
+		'component_appsecret' => 'secret',
+		'component_verify_ticket' => 'ticket',
+	),
+	//针对一些返回的名称,做转换
+	'response' => array
+	(
+		'component_access_token' => 'token',
+		//'expires_in' => 'expires_in',
+	),
+);
+
+# oauth token
+$config['oauth'] = array
+(
+	//第一步,请求code
+	'code' => array
+	(
+		'method' => 'post',
+		'json' => true,
+		'url' => 'https://api.weixin.qq.com/cgi-bin/component/api_create_preauthcode?',
+		'param' => array
+		(
+			'component_access_token' => 'token',
+			'component_appid' => 'appid',
+		),
+		'response' => array
+		(
+			'pre_auth_code' => 'oauth.code',
+		),
+	),
+	
+	//第二步,拼装redirect,进行授权登录
+	'login' => array
+	(
+		'method' => 'get',
+		'json' => false,
+		'url' => 'https://mp.weixin.qq.com/cgi-bin/componentloginpage?',
+		'param' => array
+		(
+			'component_appid' => 'appid',
+			'pre_auth_code' => 'code',
+			'redirect_uri' => 'redirect',
+			'auth_type' => '3',
+		),
+	),
+
+	//第三步,获取到token
+	'oauth' => array
+	(
+		'method' => 'post',
+		'json' => true,
+		'url' => 'https://api.weixin.qq.com/cgi-bin/component/api_query_auth?',
+		'param' => array
+		(
+			'component_access_token' => 'token',
+			'component_appid' => 'appid',
+			'authorization_code' => 'code',
+		),
+		'response' => array
+		(
+			'authorization_info.authorizer_appid' => 'openid',
+			'authorization_info.authorizer_appid' => 'unionid',
+			'authorization_info.authorizer_access_token' => 'oauth.oauth',
+			'authorization_info.authorizer_refresh_token' => 'refresh',
+		),
+	),
+);
+
+
+return $config;

+ 65 - 12
component/service/Auth.php

@@ -1,7 +1,7 @@
 <?php
 /*
 |--------------------------------------------------------------------------
-| receive.php 用于接收微信发过来的信息
+| auth.php 用于做权限验证
 |--------------------------------------------------------------------------
 */
 namespace Component\Service;
@@ -41,7 +41,48 @@ class Auth
      */
 	public function __construct()
 	{
-		
+		$this->wechat = new Wechat(self::TYPE);
+	}
+
+	/**
+     * 获取component token 一般为系统token
+     * 
+     * @return mixed
+     */
+	public function token_api()
+	{
+		return $this->wechat->token();
+	}
+
+	/**
+     * 获取预授权码 开始用户授权
+     * 
+     * @return mixed
+     */
+	public function test_api()
+	{
+		$link = $this->wechat->login('component/auth.oauth', false, false);
+		echo '<a href="'.$link.'">第三方平台授权</a>';die;
+	}
+
+	/**
+     * 获取预授权码 开始用户授权
+     * 
+     * @return mixed
+     */
+	public function get_api()
+	{
+		$this->wechat->login('component/auth.oauth');
+	}
+
+	/**
+     * 获取oauth的token 用户token
+     * 
+     * @return mixed
+     */
+	public function oauth_api()
+	{
+		$this->wechat->oauth();
 	}
 	
 	/**
@@ -84,17 +125,29 @@ class Auth
     private function request()
     {
 		//$post = $_GET ? $_GET : $_POST;
-		$post = file_get_contents('php://input');
-		
-		Dever::log(time());
-		if (!empty($post)) {
-			$post = json_encode($post);
-			Dever::log($post);
-			return;
-			libxml_disable_entity_loader(true);
-          	$result = (array) simplexml_load_string($post, 'SimpleXMLElement', LIBXML_NOCDATA);
+		$data = array();
+		$data['signature'] = '432ec06aa3a0f680924c9587ea215b4e490382b3';
+		$data['timestamp'] = '1525677152';
+		$data['nonce']	= '377902872';
+		$data['encrypt_type'] = 'aes';
+		$data['msg_signature'] = '7f62174a1402d955c2d8e61f69a309540714c579';
 
-          	$this->handle($result);
+
+		$xml = file_get_contents('php://input');
+
+		$xml = "<xml>
+    <AppId><![CDATA[wxc50846069a0ae2d2]]></AppId>
+    <Encrypt><![CDATA[SYTZJTU4ZWOKAWhjWYgVEZQMRplYNo1ZuN5dL3hQoQmbLbYM0O5Iaw/FqpigtOAyIL3dIgoA1ti91C0Z45/qgl9w4Fxa1yi94tugaWQfq5pQGbRwBte5uR3okaFxVYW0ZQd3k0HWuMgAvt/pDoMn5hLpvxhfEKX4ZVvkY4fcgb0D4bz1xba0DCdpVqHmzk1ewbD01LeUNw9JQSSBiFX24x7JruXSvsXMn0gKfYUR1s5vavnoVz6CeyUYzW63Id+b4gxKDnBGAfsBQWFdtgoJg9Ze6AN2EBGmbltx8qr7L+UKCrExgpdBRyG2vDu4QQvk+lp/jjbao721zQGpgFqr1hIJjSiXX6M8my7l3wI+nHJpdF3PpCsEiml2zcFGDrd7PSS1A8PAYrDG8W84NNpK4Onz2ZxrRI/BusI999TiS/I88fT5XM4qMo2j2F488vvSRHdJxo7C+3V+rQFkBXSbVA==]]></Encrypt>
+</xml>";
+
+		if (!empty($xml)) {
+			libxml_disable_entity_loader(true);
+          	$result = (array) simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
+			$result = $this->wechat->decode($data['msg_signature'], $data['timestamp'], $data['nonce'], $result['Encrypt']);
+			if (isset($result['ComponentVerifyTicket'])) {
+				$this->wechat->ticket($result['ComponentVerifyTicket'], 600, 100);
+			}
+			return true;
 		} else {
 			return false;
 		}

+ 1 - 9
component/service/Receive.php

@@ -41,15 +41,7 @@ class Receive
      */
 	public function __construct()
 	{
-		$appid = Dever::input('appid');
-		$project = false;
-		if ($appid) {
-			$info = Dever::db('main/project')->one(array('option_type' => self::TYPE, 'option_appid' => $appid));
-			if ($info) {
-				$project = $info['id'];
-			}
-		}
-		$this->wechat = new Wechat('component', $project);
+		$this->wechat = new Wechat(self::TYPE);
 	}
 	
 	/**

+ 0 - 31
config/sign.php

@@ -1,31 +0,0 @@
-<?php
-
-# 数据收集的配置
-$config['accessToken'] = array
-(
-	'url' => 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential',
-	
-	/*
-	1 => array
-	(
-		'appid' => 'wx1bd1c3bfc6b0515e', 
-		'secret' => '21f8ebe7b419a4920eb9b72532798523'
-	),
-
-	# 牛游
-	2 => array
-	(
-		'appid' => 'wx4978eeb711847a5a', 
-		'secret' => '510645c52d352d915773999f3a3cf5c1'
-	),
-	*/
-);
-
-//$config['accessToken'] += Dever::load('weixin/site-getAll');
-
-//print_r($config['accessToken']);die;
-
-$config['ticket'] = 'https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi&access_token=';
-
-
-return $config;

+ 4 - 0
example/ReadMe.txt

@@ -0,0 +1,4 @@
+注意事项:
+1.WXBizMsgCrypt.php文件提供了WXBizMsgCrypt类的实现,是用户接入企业微信的接口类。Sample.php提供了示例以供开发者参考。errorCode.php, pkcs7Encoder.php, sha1.php, xmlparse.php文件是实现这个类的辅助类,开发者无须关心其具体实现。
+2.WXBizMsgCrypt类封装了 DecryptMsg, EncryptMsg两个接口,分别用于开发者解密以及开发者回复消息的加密。使用方法可以参考Sample.php文件。
+3.加解密协议请参考微信公众平台官方文档。

+ 40 - 0
example/demo.php

@@ -0,0 +1,40 @@
+<?php
+
+include_once "wxBizMsgCrypt.php";
+
+// 第三方发送消息给公众平台
+$encodingAesKey = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFG";
+$token = "pamtest";
+$timeStamp = "1409304348";
+$nonce = "xxxxxx";
+$appId = "wxb11529c136998cb6";
+$text = "<xml><ToUserName><![CDATA[oia2Tj我是中文jewbmiOUlr6X-1crbLOvLw]]></ToUserName><FromUserName><![CDATA[gh_7f083739789a]]></FromUserName><CreateTime>1407743423</CreateTime><MsgType><![CDATA[video]]></MsgType><Video><MediaId><![CDATA[eYJ1MbwPRJtOvIEabaxHs7TX2D-HV71s79GUxqdUkjm6Gs2Ed1KF3ulAOA9H1xG0]]></MediaId><Title><![CDATA[testCallBackReplyVideo]]></Title><Description><![CDATA[testCallBackReplyVideo]]></Description></Video></xml>";
+
+
+$pc = new WXBizMsgCrypt($token, $encodingAesKey, $appId);
+$encryptMsg = '';
+$errCode = $pc->encryptMsg($text, $timeStamp, $nonce, $encryptMsg);
+if ($errCode == 0) {
+	print("加密后: " . $encryptMsg . "\n");
+} else {
+	print($errCode . "\n");
+}
+
+$xml_tree = new DOMDocument();
+$xml_tree->loadXML($encryptMsg);
+$array_e = $xml_tree->getElementsByTagName('Encrypt');
+$array_s = $xml_tree->getElementsByTagName('MsgSignature');
+$encrypt = $array_e->item(0)->nodeValue;
+$msg_sign = $array_s->item(0)->nodeValue;
+
+$format = "<xml><ToUserName><![CDATA[toUser]]></ToUserName><Encrypt><![CDATA[%s]]></Encrypt></xml>";
+$from_xml = sprintf($format, $encrypt);
+
+// 第三方收到公众号平台发送的消息
+$msg = '';
+$errCode = $pc->decryptMsg($msg_sign, $timeStamp, $nonce, $from_xml, $msg);
+if ($errCode == 0) {
+	print("解密后: " . $msg . "\n");
+} else {
+	print($errCode . "\n");
+}

+ 35 - 0
example/errorCode.php

@@ -0,0 +1,35 @@
+<?php
+
+/**
+ * error code 说明.
+ * <ul>
+ *    <li>-40001: 签名验证错误</li>
+ *    <li>-40002: xml解析失败</li>
+ *    <li>-40003: sha加密生成签名失败</li>
+ *    <li>-40004: encodingAesKey 非法</li>
+ *    <li>-40005: appid 校验错误</li>
+ *    <li>-40006: aes 加密失败</li>
+ *    <li>-40007: aes 解密失败</li>
+ *    <li>-40008: 解密后得到的buffer非法</li>
+ *    <li>-40009: base64加密失败</li>
+ *    <li>-40010: base64解密失败</li>
+ *    <li>-40011: 生成xml失败</li>
+ * </ul>
+ */
+class ErrorCode
+{
+	public static $OK = 0;
+	public static $ValidateSignatureError = -40001;
+	public static $ParseXmlError = -40002;
+	public static $ComputeSignatureError = -40003;
+	public static $IllegalAesKey = -40004;
+	public static $ValidateAppidError = -40005;
+	public static $EncryptAESError = -40006;
+	public static $DecryptAESError = -40007;
+	public static $IllegalBuffer = -40008;
+	public static $EncodeBase64Error = -40009;
+	public static $DecodeBase64Error = -40010;
+	public static $GenReturnXmlError = -40011;
+}
+
+?>

+ 167 - 0
example/pkcs7Encoder.php

@@ -0,0 +1,167 @@
+<?php
+
+include_once "errorCode.php";
+
+/**
+ * PKCS7Encoder class
+ *
+ * 提供基于PKCS7算法的加解密接口.
+ */
+class PKCS7Encoder
+{
+	public static $block_size = 32;
+
+	/**
+	 * 对需要加密的明文进行填充补位
+	 * @param $text 需要进行填充补位操作的明文
+	 * @return 补齐明文字符串
+	 */
+	function encode($text)
+	{
+		$block_size = PKCS7Encoder::$block_size;
+		$text_length = strlen($text);
+		//计算需要填充的位数
+		$amount_to_pad = PKCS7Encoder::$block_size - ($text_length % PKCS7Encoder::$block_size);
+		if ($amount_to_pad == 0) {
+			$amount_to_pad = PKCS7Encoder::block_size;
+		}
+		//获得补位所用的字符
+		$pad_chr = chr($amount_to_pad);
+		$tmp = "";
+		for ($index = 0; $index < $amount_to_pad; $index++) {
+			$tmp .= $pad_chr;
+		}
+		return $text . $tmp;
+	}
+
+	/**
+	 * 对解密后的明文进行补位删除
+	 * @param decrypted 解密后的明文
+	 * @return 删除填充补位后的明文
+	 */
+	function decode($text)
+	{
+
+		$pad = ord(substr($text, -1));
+		if ($pad < 1 || $pad > 32) {
+			$pad = 0;
+		}
+		return substr($text, 0, (strlen($text) - $pad));
+	}
+
+}
+
+/**
+ * Prpcrypt class
+ *
+ * 提供接收和推送给公众平台消息的加解密接口.
+ */
+class Prpcrypt
+{
+	public $key;
+
+	function Prpcrypt($k)
+	{
+		$this->key = base64_decode($k . "=");
+	}
+
+	/**
+	 * 对明文进行加密
+	 * @param string $text 需要加密的明文
+	 * @return string 加密后的密文
+	 */
+	public function encrypt($text, $appid)
+	{
+
+		try {
+			//获得16位随机字符串,填充到明文之前
+			$random = $this->getRandomStr();
+			$text = $random . pack("N", strlen($text)) . $text . $appid;
+			// 网络字节序
+			$size = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
+			$module = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');
+			$iv = substr($this->key, 0, 16);
+			//使用自定义的填充方式对明文进行补位填充
+			$pkc_encoder = new PKCS7Encoder;
+			$text = $pkc_encoder->encode($text);
+			mcrypt_generic_init($module, $this->key, $iv);
+			//加密
+			$encrypted = mcrypt_generic($module, $text);
+			mcrypt_generic_deinit($module);
+			mcrypt_module_close($module);
+
+			//print(base64_encode($encrypted));
+			//使用BASE64对加密后的字符串进行编码
+			return array(ErrorCode::$OK, base64_encode($encrypted));
+		} catch (Exception $e) {
+			//print $e;
+			return array(ErrorCode::$EncryptAESError, null);
+		}
+	}
+
+	/**
+	 * 对密文进行解密
+	 * @param string $encrypted 需要解密的密文
+	 * @return string 解密得到的明文
+	 */
+	public function decrypt($encrypted, $appid)
+	{
+
+		try {
+			//使用BASE64对需要解密的字符串进行解码
+			$ciphertext_dec = base64_decode($encrypted);
+			$module = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');
+			$iv = substr($this->key, 0, 16);
+			mcrypt_generic_init($module, $this->key, $iv);
+
+			//解密
+			$decrypted = mdecrypt_generic($module, $ciphertext_dec);
+			mcrypt_generic_deinit($module);
+			mcrypt_module_close($module);
+		} catch (Exception $e) {
+			return array(ErrorCode::$DecryptAESError, null);
+		}
+
+
+		try {
+			//去除补位字符
+			$pkc_encoder = new PKCS7Encoder;
+			$result = $pkc_encoder->decode($decrypted);
+			//去除16位随机字符串,网络字节序和AppId
+			if (strlen($result) < 16)
+				return "";
+			$content = substr($result, 16, strlen($result));
+			$len_list = unpack("N", substr($content, 0, 4));
+			$xml_len = $len_list[1];
+			$xml_content = substr($content, 4, $xml_len);
+			$from_appid = substr($content, $xml_len + 4);
+		} catch (Exception $e) {
+			//print $e;
+			return array(ErrorCode::$IllegalBuffer, null);
+		}
+		if ($from_appid != $appid)
+			return array(ErrorCode::$ValidateAppidError, null);
+		return array(0, $xml_content);
+
+	}
+
+
+	/**
+	 * 随机生成16位字符串
+	 * @return string 生成的字符串
+	 */
+	function getRandomStr()
+	{
+
+		$str = "";
+		$str_pol = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz";
+		$max = strlen($str_pol) - 1;
+		for ($i = 0; $i < 16; $i++) {
+			$str .= $str_pol[mt_rand(0, $max)];
+		}
+		return $str;
+	}
+
+}
+
+?>

+ 36 - 0
example/sha1.php

@@ -0,0 +1,36 @@
+<?php
+
+include_once "errorCode.php";
+
+/**
+ * SHA1 class
+ *
+ * 计算公众平台的消息签名接口.
+ */
+class SHA1
+{
+	/**
+	 * 用SHA1算法生成安全签名
+	 * @param string $token 票据
+	 * @param string $timestamp 时间戳
+	 * @param string $nonce 随机字符串
+	 * @param string $encrypt 密文消息
+	 */
+	public function getSHA1($token, $timestamp, $nonce, $encrypt_msg)
+	{
+		//排序
+		try {
+			$array = array($encrypt_msg, $token, $timestamp, $nonce);
+			sort($array, SORT_STRING);
+			$str = implode($array);
+			return array(ErrorCode::$OK, sha1($str));
+		} catch (Exception $e) {
+			//print $e . "\n";
+			return array(ErrorCode::$ComputeSignatureError, null);
+		}
+	}
+
+}
+
+
+?>

+ 150 - 0
example/wxBizMsgCrypt.php

@@ -0,0 +1,150 @@
+<?php
+
+/**
+ * 对公众平台发送给公众账号的消息加解密示例代码.
+ *
+ * @copyright Copyright (c) 1998-2014 Tencent Inc.
+ */
+
+
+include_once "sha1.php";
+include_once "xmlparse.php";
+include_once "pkcs7Encoder.php";
+include_once "errorCode.php";
+
+/**
+ * 1.第三方回复加密消息给公众平台;
+ * 2.第三方收到公众平台发送的消息,验证消息的安全性,并对消息进行解密。
+ */
+class WXBizMsgCrypt
+{
+	private $token;
+	private $encodingAesKey;
+	private $appId;
+
+	/**
+	 * 构造函数
+	 * @param $token string 公众平台上,开发者设置的token
+	 * @param $encodingAesKey string 公众平台上,开发者设置的EncodingAESKey
+	 * @param $appId string 公众平台的appId
+	 */
+	public function WXBizMsgCrypt($token, $encodingAesKey, $appId)
+	{
+		$this->token = $token;
+		$this->encodingAesKey = $encodingAesKey;
+		$this->appId = $appId;
+	}
+
+	/**
+	 * 将公众平台回复用户的消息加密打包.
+	 * <ol>
+	 *    <li>对要发送的消息进行AES-CBC加密</li>
+	 *    <li>生成安全签名</li>
+	 *    <li>将消息密文和安全签名打包成xml格式</li>
+	 * </ol>
+	 *
+	 * @param $replyMsg string 公众平台待回复用户的消息,xml格式的字符串
+	 * @param $timeStamp string 时间戳,可以自己生成,也可以用URL参数的timestamp
+	 * @param $nonce string 随机串,可以自己生成,也可以用URL参数的nonce
+	 * @param &$encryptMsg string 加密后的可以直接回复用户的密文,包括msg_signature, timestamp, nonce, encrypt的xml格式的字符串,
+	 *                      当return返回0时有效
+	 *
+	 * @return int 成功0,失败返回对应的错误码
+	 */
+	public function encryptMsg($replyMsg, $timeStamp, $nonce, &$encryptMsg)
+	{
+		$pc = new Prpcrypt($this->encodingAesKey);
+
+		//加密
+		$array = $pc->encrypt($replyMsg, $this->appId);
+		$ret = $array[0];
+		if ($ret != 0) {
+			return $ret;
+		}
+
+		if ($timeStamp == null) {
+			$timeStamp = time();
+		}
+		$encrypt = $array[1];
+
+		//生成安全签名
+		$sha1 = new SHA1;
+		$array = $sha1->getSHA1($this->token, $timeStamp, $nonce, $encrypt);
+		$ret = $array[0];
+		if ($ret != 0) {
+			return $ret;
+		}
+		$signature = $array[1];
+
+		//生成发送的xml
+		$xmlparse = new XMLParse;
+		$encryptMsg = $xmlparse->generate($encrypt, $signature, $timeStamp, $nonce);
+		return ErrorCode::$OK;
+	}
+
+
+	/**
+	 * 检验消息的真实性,并且获取解密后的明文.
+	 * <ol>
+	 *    <li>利用收到的密文生成安全签名,进行签名验证</li>
+	 *    <li>若验证通过,则提取xml中的加密消息</li>
+	 *    <li>对消息进行解密</li>
+	 * </ol>
+	 *
+	 * @param $msgSignature string 签名串,对应URL参数的msg_signature
+	 * @param $timestamp string 时间戳 对应URL参数的timestamp
+	 * @param $nonce string 随机串,对应URL参数的nonce
+	 * @param $postData string 密文,对应POST请求的数据
+	 * @param &$msg string 解密后的原文,当return返回0时有效
+	 *
+	 * @return int 成功0,失败返回对应的错误码
+	 */
+	public function decryptMsg($msgSignature, $timestamp = null, $nonce, $postData, &$msg)
+	{
+		if (strlen($this->encodingAesKey) != 43) {
+			return ErrorCode::$IllegalAesKey;
+		}
+
+		$pc = new Prpcrypt($this->encodingAesKey);
+
+		//提取密文
+		$xmlparse = new XMLParse;
+		$array = $xmlparse->extract($postData);
+		$ret = $array[0];
+
+		if ($ret != 0) {
+			return $ret;
+		}
+
+		if ($timestamp == null) {
+			$timestamp = time();
+		}
+
+		$encrypt = $array[1];
+		$touser_name = $array[2];
+
+		//验证安全签名
+		$sha1 = new SHA1;
+		$array = $sha1->getSHA1($this->token, $timestamp, $nonce, $encrypt);
+		$ret = $array[0];
+
+		if ($ret != 0) {
+			return $ret;
+		}
+
+		$signature = $array[1];
+		if ($signature != $msgSignature) {
+			return ErrorCode::$ValidateSignatureError;
+		}
+
+		$result = $pc->decrypt($encrypt, $this->appId);
+		if ($result[0] != 0) {
+			return $result[0];
+		}
+		$msg = $result[1];
+
+		return ErrorCode::$OK;
+	}
+
+}
+

+ 54 - 0
example/xmlparse.php

@@ -0,0 +1,54 @@
+<?php
+include_once "errorCode.php";
+
+/**
+ * XMLParse class
+ *
+ * 提供提取消息格式中的密文及生成回复消息格式的接口.
+ */
+class XMLParse
+{
+
+	/**
+	 * 提取出xml数据包中的加密消息
+	 * @param string $xmltext 待提取的xml字符串
+	 * @return string 提取出的加密消息字符串
+	 */
+	public function extract($xmltext)
+	{
+		try {
+			$xml = new DOMDocument();
+			$xml->loadXML($xmltext);
+			$array_e = $xml->getElementsByTagName('Encrypt');
+			$array_a = $xml->getElementsByTagName('ToUserName');
+			$encrypt = $array_e->item(0)->nodeValue;
+			$tousername = $array_a->item(0)->nodeValue;
+			return array(0, $encrypt, $tousername);
+		} catch (Exception $e) {
+			//print $e . "\n";
+			return array(ErrorCode::$ParseXmlError, null, null);
+		}
+	}
+
+	/**
+	 * 生成xml消息
+	 * @param string $encrypt 加密后的消息密文
+	 * @param string $signature 安全签名
+	 * @param string $timestamp 时间戳
+	 * @param string $nonce 随机字符串
+	 */
+	public function generate($encrypt, $signature, $timestamp, $nonce)
+	{
+		$format = "<xml>
+<Encrypt><![CDATA[%s]]></Encrypt>
+<MsgSignature><![CDATA[%s]]></MsgSignature>
+<TimeStamp>%s</TimeStamp>
+<Nonce><![CDATA[%s]]></Nonce>
+</xml>";
+		return sprintf($format, $encrypt, $signature, $timestamp, $nonce);
+	}
+
+}
+
+
+?>

+ 98 - 0
main/database/code.php

@@ -0,0 +1,98 @@
+<?php
+/**
+ * code 一般用于保存oauth code
+ */
+
+return array
+(
+	# 表名
+	'name' => 'code',
+	# 显示给用户看的名称
+	'lang' => 'code数据表',
+	'menu' => false,
+	# 数据结构
+	'struct' => array
+	(
+		'id' 		=> array
+		(
+			'type' 		=> 'int-11',
+			'name' 		=> 'ID',
+			'default' 	=> '',
+			'desc' 		=> '',
+			'match' 	=> 'is_numeric',
+			'search'	=> 'order',
+			'list'		=> true,
+		),
+
+		'project_id'		=> array
+		(
+			'type' 		=> 'int-11',
+			'name' 		=> '项目',
+			'default' 	=> '',
+			'desc' 		=> '请输入项目',
+			'match' 	=> 'is_numeric',
+			//'search'	=> 'order,fulltext',
+			'update'	=> 'text',
+			'list'		=> '{project_id} > 0 ? Dever::load("main/project-one#name", {project_id}) : "未知"',
+		),
+		
+		'value'		=> array
+		(
+			'type' 		=> 'varchar-255',
+			'name' 		=> 'code标识',
+			'default' 	=> '',
+			'desc' 		=> 'code标识',
+			'match' 	=> 'is_string',
+			'update'	=> 'text',
+			'list'		=> true,
+			'modal'		=> '查看',
+		),
+		
+		'expires'		=> array
+		(
+			'type' 		=> 'int-11',
+			'name' 		=> '过期时间',
+			'default' 	=> '',
+			'desc' 		=> '过期时间',
+			'match' 	=> 'is_numeric',
+			'update'	=> 'text',
+			'list'		=> true,
+		),
+		
+		'mdate'		=> array
+		(
+			'type' 		=> 'int-11',
+			'name' 		=> '更新时间',
+			'match' 	=> array('is_numeric', time()),
+			'desc' 		=> '',
+			'list'		=> 'date("Y-m-d H:i:s", {mdate})',
+		),
+		
+		'state'		=> array
+		(
+			'type' 		=> 'tinyint-1',
+			'name' 		=> '状态',
+			'default' 	=> '1',
+			'desc' 		=> '请选择状态',
+		),
+		
+		'cdate'		=> array
+		(
+			'type' 		=> 'int-11',
+			'name' 		=> '录入时间',
+			'match' 	=> array('is_numeric', time()),
+			'desc' 		=> '',
+			# 只有insert时才生效
+			'insert'	=> true,
+		),
+	),
+
+	//'top' => 'main/project_id',
+
+	'manage' => array
+	(
+		'delete' => false,
+		'insert' => false,
+		'edit' => false,
+	),
+);

+ 0 - 81
main/database/col.php

@@ -1,81 +0,0 @@
-<?php
-
-return array
-(
-	# 表名
-	'name' => 'col',
-	# 显示给用户看的名称
-	'lang' => '维度管理',
-	'order' => -10,
-	'check' => 'key',
-	# 数据结构
-	'struct' => array
-	(
-		'id' 		=> array
-		(
-			'type' 		=> 'int-11',
-			'name' 		=> 'ID',
-			'default' 	=> '',
-			'desc' 		=> '',
-			'match' 	=> 'is_numeric',
-			//'search'	=> 'order',
-			'order'		=> 'desc',
-			'list'		=> true,
-		),
-		
-		'name'		=> array
-		(
-			'type' 		=> 'varchar-60',
-			'name' 		=> '维度名称',
-			'default' 	=> '',
-			'desc' 		=> '请输入维度名称',
-			'match' 	=> 'is_string',
-			'update'	=> 'text',
-			'search'	=> 'fulltext',
-			'list'		=> true,
-		),
-
-		'key'		=> array
-		(
-			'type' 		=> 'varchar-60',
-			'name' 		=> '维度key',
-			'default' 	=> '',
-			'desc' 		=> '请输入维度key',
-			'match' 	=> 'is_string',
-			'update'	=> 'text',
-			'search'	=> 'fulltext',
-			'list'		=> true,
-		),
-
-		'state'		=> array
-		(
-			'type' 		=> 'tinyint-1',
-			'name' 		=> '状态',
-			'default' 	=> '1',
-			'desc' 		=> '请选择状态',
-			'match' 	=> 'is_numeric',
-		),
-		
-		'cdate'		=> array
-		(
-			'type' 		=> 'int-11',
-			'name' 		=> '录入时间',
-			'match' 	=> array('is_numeric', time()),
-			'desc' 		=> '',
-			# 只有insert时才生效
-			'insert'	=> true,
-			'list'		=> 'date("Y-m-d H:i:s", {cdate})',
-		),
-	),
-	
-	'manage' => array
-	(
-
-	),
-	
-	# request 请求接口定义
-	'request' => array
-	(
-		
-	),
-);

+ 134 - 0
main/database/oauth.php

@@ -0,0 +1,134 @@
+<?php
+/**
+ * token
+ */
+
+return array
+(
+	# 表名
+	'name' => 'oauth',
+	# 显示给用户看的名称
+	'lang' => 'oauth数据表',
+	'menu' => false,
+	# 数据结构
+	'struct' => array
+	(
+		'id' 		=> array
+		(
+			'type' 		=> 'int-11',
+			'name' 		=> 'ID',
+			'default' 	=> '',
+			'desc' 		=> '',
+			'match' 	=> 'is_numeric',
+			'search'	=> 'order',
+			'list'		=> true,
+		),
+
+		'project_id'		=> array
+		(
+			'type' 		=> 'int-11',
+			'name' 		=> '项目',
+			'default' 	=> '',
+			'desc' 		=> '请输入项目',
+			'match' 	=> 'is_numeric',
+			//'search'	=> 'order,fulltext',
+			'update'	=> 'text',
+			'list'		=> '{project_id} > 0 ? Dever::load("main/project-one#name", {project_id}) : "未知"',
+		),
+
+		'openid'		=> array
+		(
+			'type' 		=> 'varchar-60',
+			'name' 		=> '用户id-如果是第三方平台,则为appid',
+			'default' 	=> '',
+			'desc' 		=> '用户id',
+			'match' 	=> 'is_string',
+			//'search'	=> 'order,fulltext',
+			'update'	=> 'text',
+			'list'		=> true,
+		),
+
+		'unionid'		=> array
+		(
+			'type' 		=> 'varchar-60',
+			'name' 		=> '用户唯一id-如果是第三方平台,则为appid',
+			'default' 	=> '',
+			'desc' 		=> '用户唯一id',
+			'match' 	=> 'is_string',
+			//'search'	=> 'order,fulltext',
+			'update'	=> 'text',
+			'list'		=> true,
+		),
+		
+		'value'		=> array
+		(
+			'type' 		=> 'varchar-255',
+			'name' 		=> 'token标识',
+			'default' 	=> '',
+			'desc' 		=> 'token标识',
+			'match' 	=> 'is_string',
+			'update'	=> 'text',
+			'list'		=> true,
+			'modal'		=> '查看',
+		),
+
+		'refresh'		=> array
+		(
+			'type' 		=> 'varchar-255',
+			'name' 		=> 'refresh token标识',
+			'default' 	=> '',
+			'desc' 		=> 'refresh token标识',
+			'match' 	=> 'is_string',
+			'update'	=> 'text',
+			'list'		=> true,
+			'modal'		=> '查看',
+		),
+		
+		'expires'		=> array
+		(
+			'type' 		=> 'int-11',
+			'name' 		=> '过期时间',
+			'default' 	=> '',
+			'desc' 		=> '过期时间',
+			'match' 	=> 'is_numeric',
+			'update'	=> 'text',
+			'list'		=> true,
+		),
+		
+		'mdate'		=> array
+		(
+			'type' 		=> 'int-11',
+			'name' 		=> '更新时间',
+			'match' 	=> array('is_numeric', time()),
+			'desc' 		=> '',
+			'list'		=> 'date("Y-m-d H:i:s", {mdate})',
+		),
+		
+		'state'		=> array
+		(
+			'type' 		=> 'tinyint-1',
+			'name' 		=> '状态',
+			'default' 	=> '1',
+			'desc' 		=> '请选择状态',
+		),
+		
+		'cdate'		=> array
+		(
+			'type' 		=> 'int-11',
+			'name' 		=> '录入时间',
+			'match' 	=> array('is_numeric', time()),
+			'desc' 		=> '',
+			# 只有insert时才生效
+			'insert'	=> true,
+		),
+	),
+
+	//'top' => 'main/project_id',
+
+	'manage' => array
+	(
+		'delete' => false,
+		'insert' => false,
+		'edit' => false,
+	),
+);

+ 60 - 0
main/database/project.php

@@ -56,6 +56,52 @@ return array
 			'list'		=> true,
 		),
 
+		'appid'		=> array
+		(
+			'type' 		=> 'varchar-150',
+			'name' 		=> '微信appid',
+			'default' 	=> '',
+			'desc' 		=> '请输入微信appid',
+			'match' 	=> 'is_string',
+			'search'	=> 'order,fulltext',
+			'update'	=> 'text',
+			'list'		=> 'table',
+			'modal' 	=> '详细信息',
+		),
+
+		'secret'		=> array
+		(
+			'type' 		=> 'varchar-150',
+			'name' 		=> '微信secret',
+			'default' 	=> '',
+			'desc' 		=> '请输入微信secret',
+			'match' 	=> 'is_string',
+			'search'	=> 'order,fulltext',
+			'update'	=> 'text',
+			//'list'		=> 'table',
+			//'modal' 	=> '详细信息',
+		),
+
+		'token'		=> array
+		(
+			'type' 		=> 'varchar-150',
+			'name' 		=> '通信token(注意不是access_token)',
+			'default' 	=> '',
+			'desc' 		=> '请输入通信token',
+			'match' 	=> 'is_string',
+			'update'	=> 'text',
+		),
+
+		'key'		=> array
+		(
+			'type' 		=> 'varchar-150',
+			'name' 		=> '消息加解密密钥',
+			'default' 	=> '',
+			'desc' 		=> '请输入消息加解密密钥',
+			'match' 	=> 'option',
+			'update'	=> 'text',
+		),
+
 		'state'		=> array
 		(
 			'type' 		=> 'tinyint-1',
@@ -81,6 +127,20 @@ return array
 	(
 
 	),
+
+	'top' => array
+	(
+		# 数据来源
+		'data' => 'state',
+		# 菜单名
+		'name' => '项目选择',
+		# 默认值
+		'value' => 1,
+		# 对应的字段值,设置这个之后,所有设置等于这个值的字段,都要遵循这个权限的控制
+		'key' => 'main/project_id',
+		# 本表中代表名称的字段
+		'col' => 'name',
+	),
 	
 	# request 请求接口定义
 	'request' => array

+ 98 - 0
main/database/ticket.php

@@ -0,0 +1,98 @@
+<?php
+/**
+ * ticket
+ */
+
+return array
+(
+	# 表名
+	'name' => 'ticket',
+	# 显示给用户看的名称
+	'lang' => 'ticket数据表',
+	'menu' => false,
+	# 数据结构
+	'struct' => array
+	(
+		'id' 		=> array
+		(
+			'type' 		=> 'int-11',
+			'name' 		=> 'ID',
+			'default' 	=> '',
+			'desc' 		=> '',
+			'match' 	=> 'is_numeric',
+			'search'	=> 'order',
+			'list'		=> true,
+		),
+
+		'project_id'		=> array
+		(
+			'type' 		=> 'int-11',
+			'name' 		=> '项目',
+			'default' 	=> '',
+			'desc' 		=> '请输入项目',
+			'match' 	=> 'is_numeric',
+			//'search'	=> 'order,fulltext',
+			'update'	=> 'text',
+			'list'		=> '{project_id} > 0 ? Dever::load("main/project-one#name", {project_id}) : "未知"',
+		),
+		
+		'value'		=> array
+		(
+			'type' 		=> 'varchar-255',
+			'name' 		=> 'ticket标识',
+			'default' 	=> '',
+			'desc' 		=> 'ticket标识',
+			'match' 	=> 'is_string',
+			'update'	=> 'text',
+			'list'		=> true,
+			'modal'		=> '查看',
+		),
+		
+		'expires'		=> array
+		(
+			'type' 		=> 'int-11',
+			'name' 		=> '过期时间',
+			'default' 	=> '',
+			'desc' 		=> '过期时间',
+			'match' 	=> 'is_numeric',
+			'update'	=> 'text',
+			'list'		=> true,
+		),
+		
+		'mdate'		=> array
+		(
+			'type' 		=> 'int-11',
+			'name' 		=> '更新时间',
+			'match' 	=> array('is_numeric', time()),
+			'desc' 		=> '',
+			'list'		=> 'date("Y-m-d H:i:s", {mdate})',
+		),
+		
+		'state'		=> array
+		(
+			'type' 		=> 'tinyint-1',
+			'name' 		=> '状态',
+			'default' 	=> '1',
+			'desc' 		=> '请选择状态',
+		),
+		
+		'cdate'		=> array
+		(
+			'type' 		=> 'int-11',
+			'name' 		=> '录入时间',
+			'match' 	=> array('is_numeric', time()),
+			'desc' 		=> '',
+			# 只有insert时才生效
+			'insert'	=> true,
+		),
+	),
+
+	//'top' => 'main/project_id',
+
+	'manage' => array
+	(
+		'delete' => false,
+		'insert' => false,
+		'edit' => false,
+	),
+);

+ 98 - 0
main/database/token.php

@@ -0,0 +1,98 @@
+<?php
+/**
+ * token
+ */
+
+return array
+(
+	# 表名
+	'name' => 'token',
+	# 显示给用户看的名称
+	'lang' => 'token数据表',
+	'menu' => false,
+	# 数据结构
+	'struct' => array
+	(
+		'id' 		=> array
+		(
+			'type' 		=> 'int-11',
+			'name' 		=> 'ID',
+			'default' 	=> '',
+			'desc' 		=> '',
+			'match' 	=> 'is_numeric',
+			'search'	=> 'order',
+			'list'		=> true,
+		),
+
+		'project_id'		=> array
+		(
+			'type' 		=> 'int-11',
+			'name' 		=> '项目',
+			'default' 	=> '',
+			'desc' 		=> '请输入项目',
+			'match' 	=> 'is_numeric',
+			//'search'	=> 'order,fulltext',
+			'update'	=> 'text',
+			'list'		=> '{project_id} > 0 ? Dever::load("main/project-one#name", {project_id}) : "未知"',
+		),
+		
+		'value'		=> array
+		(
+			'type' 		=> 'varchar-255',
+			'name' 		=> 'token标识',
+			'default' 	=> '',
+			'desc' 		=> 'token标识',
+			'match' 	=> 'is_string',
+			'update'	=> 'text',
+			'list'		=> true,
+			'modal'		=> '查看',
+		),
+		
+		'expires'		=> array
+		(
+			'type' 		=> 'int-11',
+			'name' 		=> '过期时间',
+			'default' 	=> '',
+			'desc' 		=> '过期时间',
+			'match' 	=> 'is_numeric',
+			'update'	=> 'text',
+			'list'		=> true,
+		),
+		
+		'mdate'		=> array
+		(
+			'type' 		=> 'int-11',
+			'name' 		=> '更新时间',
+			'match' 	=> array('is_numeric', time()),
+			'desc' 		=> '',
+			'list'		=> 'date("Y-m-d H:i:s", {mdate})',
+		),
+		
+		'state'		=> array
+		(
+			'type' 		=> 'tinyint-1',
+			'name' 		=> '状态',
+			'default' 	=> '1',
+			'desc' 		=> '请选择状态',
+		),
+		
+		'cdate'		=> array
+		(
+			'type' 		=> 'int-11',
+			'name' 		=> '录入时间',
+			'match' 	=> array('is_numeric', time()),
+			'desc' 		=> '',
+			# 只有insert时才生效
+			'insert'	=> true,
+		),
+	),
+
+	//'top' => 'main/project_id',
+
+	'manage' => array
+	(
+		'delete' => false,
+		'insert' => false,
+		'edit' => false,
+	),
+);

+ 257 - 151
main/lib/Wechat.php

@@ -32,188 +32,303 @@ class Wechat
 	private $project;
 	
 	/**
-     * 构造函数 初始化
-     * 
-     * @return mixed
-     */
-	public function __construct($type = 'component', $project = false)
+	 * 构造函数 初始化
+	 * 
+	 * @return mixed
+	 */
+	public function __construct($type = 1, $project = false)
 	{
-		$this->config = Dever::config('sign')->cAll;
-		
+		$this->config = Dever::config('wechat')->cAll;
+
 		if (!$project) {
-			$project = Dever::input('project', 1);
+			$appid = Dever::input('appid');
+			if ($appid) {
+				$project = Dever::db('main/project')->one(array('option_type' => $type, 'option_appid' => $appid));
+			}
+			if (!$project) {
+				$project = Dever::input('project', 1);
+			}
 		}
 
 		if (!$project) {
 			Dever::alert('project is not exits!');
 		}
 
+		if (is_numeric($project)) {
+			$project = Dever::db('main/project')->one($project);
+		}
+
 		$this->project = $project;
 	}
 	
 	/**
-     * 获取当前站点的配置
-     * 
-     * @return mixed
-     */
+	 * 获取当前站点的配置
+	 * 
+	 * @return mixed
+	 */
 	public function project()
 	{
 		return $this->project;
 	}
 
 	/**
-     * 获取当前站点的配置
-     * 
-     * @return mixed
-     */
+	 * 获取当前基本的配置
+	 * 
+	 * @return mixed
+	 */
 	public function config()
 	{
-		return $this->config['accessToken'][$this->project];
+		return $this->config;
 	}
-	
+
 	/**
-     * 获取签名信息
-     * 
-     * @return mixed
-     */
-	public function get($url)
+	 * 更新数据库
+	 * 
+	 * @return mixed
+	 */
+	private function save($type = 'ticket', $value, $expires = false, $interval = 2000)
 	{
-		$ticket = $this->ticket($this->token());
-		
-		if (!$ticket) {
-			$return['status'] = 0;
-			$return['msg'] 	= 'error';
+		if (strpos($type, '.')) {
+			$temp = explode('.', $type);
+			$table = 'main/' . $temp[1];
 		} else {
-			$timestamp = time();
-			$nonce = $this->nonce();
-			$signature = $this->signature($ticket, $url, $timestamp, $nonce);
-			$return = array
-			(
-				'appId'		=> $this->config['accessToken'][$this->project]['appid'],
-				'timestamp'	=> $timestamp,
-				'nonceStr'	=> $nonce,
-				'signature'	=> $signature,
-				'status'	=> 1,
-				'msg'		=> '成功',
-			);
+			$table = 'main/' . $type;
+		}
+		$db = Dever::db($table);
+		$where['option_project_id'] = $this->project['id'];
+		$info = $db->one($where);
+
+		$update = false;
+			
+		if ($info && time() - $info['mdate'] >= $info['expires']) {
+			$update = true;
+		} elseif($info) {
+			return $info['value'];
+		}
+		if (!$info) {
+			$update = false;
+		}
+
+		if (!$value) {
+			$value = $this->param($type);
+		}
+
+		$data = array();
+		if (is_array($value) || (is_string($value) && strstr($value, 'http://'))) {
+			$result = $this->curl(false, $value);
+
+			$key = $type;
+			if ($type == 'token') {
+				$key = 'access_token';
+			}
+			if ($result && isset($result[$key])) {
+				$data = $result;
+				$data['value'] = $result[$key];
+				$data['expires'] = $result['expires_in'];
+			}
+		} else {
+			$data['value'] = $value;
+			$data['expires'] = $expires;
 		}
 		
-		Dever::out($return);
+		if ($data && isset($data['value']) && $data['value']) {
+			$data['project_id'] = $this->project['id'];
+			$expires = $data['expires'] - $interval;
+			if ($expires <= 0) {
+				$data['expires'] = $data['expires'] - 300;
+			} else {
+				$data['expires'] = $expires;
+			}
+			if ($update == true) {
+				$data['where_id'] = $info['id'];
+				$db->update($data);
+			} else {
+				$db->insert($data);
+			}
+		} elseif($info['value']) {
+			$data['value'] = $info['value'];
+		}
+
+		return $data['value'];
 	}
-	
+
 	/**
-     * 获取nonce
-     * 
-     * @return mixed
-     */
-	private function nonce()
+	 * 获取最新的token
+	 * 
+	 * @return mixed
+	 */
+	public function token($value = false, $expires = false, $interval = 2000)
 	{
-		return substr(md5(microtime()), rand(10, 15));
+		return $this->save('token', $value, $expires, $interval);
 	}
-	
-    /**
-     * 获取accessToken
-     * 
-     * @return mixed
-     */
-    public function token($state = 1)
-    {
-		$url = $this->config['accessToken']['url'] . '&' . http_build_query($this->config['accessToken'][$this->project]);
-		
-		$where['where_project'] = $this->project;
-		$info = Dever::load('main/token-info', $where);
 
-		$request = $update = false;
-			
-		if ($info && ((time() - $info['mdate'] >= $info['expires_in']) || $state == 2)) {
-			$request = $update = true;
-		} elseif ($info) {
-			return $info['token'];
+	/**
+	 * 获取最新的ticket
+	 * 
+	 * @return mixed
+	 */
+	public function ticket($value = false, $expires = false, $interval = 200)
+	{
+		return $this->save('ticket', $value, $expires, $interval);
+	}
+
+	/**
+	 * 获取最新的oauth token
+	 * 
+	 * @return mixed
+	 */
+	public function oauth($value = false, $expires = false, $interval = 200)
+	{
+		return $this->save('oauth.oauth', $value, $expires, $interval);
+	}
+
+	/**
+	 * 获取最新的code
+	 * 
+	 * @return mixed
+	 */
+	public function code($value = false, $expires = false, $interval = 200)
+	{
+		return $this->save('oauth.code', $value, $expires, $interval);
+	}
+
+	/**
+	 * 获取最新的oauth login地址
+	 * 
+	 * @return mixed
+	 */
+	public function login($callback = false, $code = false, $location = true)
+	{
+		if (!$code) {
+			$code = $this->code();
 		}
-		if (!$info) {
-			$request = true;
-			$update = false;
+		$callback = urlencode(Dever::url($callback));
+		$config = $this->param('oauth.login', array('code' => $code, 'redirect' => $callback));
+		$url = $config['url'] . http_build_query($config['param']);
+		if ($location == true) {
+			Dever::location($url);
 		}
-		
-		if ($request == true) {
-			$data = json_decode(Dever::curl($url), true);
-			
-			if ($data && isset($data['access_token'])) {
-				$data['expires_in'] = $data['expires_in'] - 2000;
-				if ($update == true) {
-					$set['set_project'] = $this->project;
-					$set['set_token'] = $data['access_token'];
-					$set['set_expires_in'] = $data['expires_in'];
-					$set['where_id'] = $info['id'];
-					Dever::load('main/token-update', $set);
-				} else {
-					$insert['add_project'] = $this->project;
-					$insert['add_token'] = $data['access_token'];
-					$insert['add_expires_in'] = $data['expires_in'];
-					Dever::load('main/token-insert', $insert);
-				}
-				
-				return $data['access_token'];
+		return $url;
+	}
+
+	/**
+	 * 从wechat获取数据
+	 * 
+	 * @return mixed
+	 */
+	public function curl($method, $param = array())
+	{
+		if (is_string($param)) {
+			$result = json_decode(Dever::curl($param), true);
+		} else {
+			if ($method) {
+				$param = $this->param($method, $param);
 			}
+
+			$result = json_decode(Dever::curl($param['url'], $param['param'], $param['method'], $param['json']), true);
 		}
-    }
-    
-    
-    /**
-     * 获取ticket
-     * 
-     * @return mixed
-     */
-    private function ticket($token)
-    {
-		$url = $this->config['ticket'] . $token;
-		
-		$where['where_project'] = $this->project;
-		$info = Dever::load('main/ticket-info', $where);
-		
-		$request = $update = false;
-			
-		if ($info && time() - $info['mdate'] >= $info['expires_in']) {
-			$request = $update = true;
-		} elseif($info) {
-			return $info['ticket'];
+		if (isset($result['errcode']) && $result['errcode'] != 0) {
+			$result = $param + $result;
+			Dever::log($result);
+			Dever::alert(json_encode($result));
 		}
-		if (!$info) {
-			$request = true;
-			$update = false;
+
+		if (isset($param['response'])) {
+			foreach ($param['response'] as $k => $v) {
+				if (strpos($k, '.')) {
+					$temp = explode('.', $k);
+					if (isset($result[$temp[0]][$temp[1]])) {
+						$result[$v] = $result[$temp[0]][$temp[1]];
+					}
+				} elseif (isset($result[$k])) {
+					$result[$v] = $result[$k];
+				}
+			}
+		}
+		return $result;
+	}
+
+	/**
+	 * 拼装wechat需要的参数
+	 * 
+	 * @return mixed
+	 */
+	public function param($method, $param = array())
+	{
+		if (strpos($method, '.')) {
+			$temp = explode('.', $method);
+			$config = $this->config[$temp[0]][$temp[1]];
+		} else {
+			if (!isset($this->config[$method])) {
+				return false;
+			}
+			$config = $this->config[$method];
 		}
 		
-		if ($request == true) {
-			$data = json_decode(Dever::curl($url), true);
-			
-			if ($data && isset($data['ticket'])) {
-				$data['expires_in'] = $data['expires_in'] - 2000;
-				if ($update == true) {
-					$set['set_project'] = $this->project;
-					$set['set_ticket'] = $data['ticket'];
-					$set['set_expires_in'] = $data['expires_in'];
-					$set['where_name'] = $this->project;
-					Dever::load('main/ticket-update', $set);
-				} else {
-					$insert['add_project'] = $this->project;
-					$insert['add_ticket'] = $data['ticket'];
-					$insert['add_expires_in'] = $data['expires_in'];
-					Dever::load('main/ticket-insert', $insert);
-				}
-				
-				return $data['ticket'];
+		$param = $this->project + $param;
+
+		foreach ($config['param'] as $k => $v) {
+			if ($v == 'token') {
+				$config['url'] .= $k . '=' . $this->token();
+				unset($config['param'][$k]);
+			} elseif ($v == 'ticket') {
+				$config['param'][$k] = $this->ticket();
+			} elseif ($v == 'code') {
+				$config['param'][$k] = $this->code();
+			}elseif ($v == 'oauth') {
+				$config['param'][$k] = $this->oauth();
+			} elseif (isset($param[$v]) && $param[$v]) {
+				$config['param'][$k] = $param[$v];
+			} elseif($v) {
+				$config['param'][$k] = $v;
 			}
 		}
-    }
-    
-    
-    /**
-     * 获取signature
-     * 
-     * @return mixed
-     */
-    private function signature($ticket, $url, $timestamp, $noncestr)
-    {
+
+		$config['json'] = isset($config['json']) && $config['json'] ? true : false;
+
+		return $config;
+	}
+
+	/**
+	 * 消息解密
+	 * 
+	 * @return mixed
+	 */
+	public function decode($sign, $timestamp, $nonce, $encrypt)
+	{
+		include(DEVER_PROJECT_PATH . 'example/wxBizMsgCrypt.php');
+		$crypt = new \WXBizMsgCrypt($this->project['token'], $this->project['key'], $this->project['appid']);
+
+		$format = "<xml><ToUserName><![CDATA[toUser]]></ToUserName><Encrypt><![CDATA[%s]]></Encrypt></xml>";
+		$xml = sprintf($format, $encrypt);
+
+		$result = '';
+		$code = $crypt->decryptMsg($sign, $timestamp, $nonce, $xml, $result);
+		if ($code == 0) {
+			libxml_disable_entity_loader(true);
+		  	$result = (array) simplexml_load_string($result, 'SimpleXMLElement', LIBXML_NOCDATA);
+		}
+
+		return $result;
+	}
+	
+	/**
+	 * 获取nonce
+	 * 
+	 * @return mixed
+	 */
+	public function nonce()
+	{
+		return substr(md5(microtime()), rand(10, 15));
+	}
+
+	/**
+	 * 获取signature
+	 * 
+	 * @return mixed
+	 */
+	public function signature($ticket, $url, $timestamp, $noncestr)
+	{
 		$info = array();
 		$info['jsapi_ticket'] = $ticket;
 		$info['url'] = $url;
@@ -222,15 +337,6 @@ class Wechat
 		ksort($info);
 
 		$signature_string = substr(http_build_query($info), 0, -1);
-
-		/*
-		foreach($info as $k => $v)
-		{
-			$signature_string .= $k . '=' . $v . '&';
-		}
-		
-		$signature_string = substr($signature_string, 0, -1);
-		*/
 		return sha1($signature_string);
 	}
 }