dever пре 6 година
комит
a2d123cf72

+ 14 - 0
LICENSE

@@ -0,0 +1,14 @@
+Apache License
+Copyright 2016-2017 Dever(dever.cc)
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.

+ 27 - 0
README.md

@@ -0,0 +1,27 @@
+# 支付组件
+
+使用方法:
+
+```
+//下单
+
+//page页面下单
+$type = 1;
+//$param参数
+$param = array
+(
+	'account_id' => '1',
+	'uid' => '1',
+	'username' => 'test',
+	'name' => '1',
+	'cash' => '1',
+	'refer' => '1',
+	'order_id' => '1',
+	'openid' => '1',
+);
+
+$result = Dever::load('pay/api')->get(1, $param);
+
+//测试地址
+http://192.168.33.10/grow/pay/?api.get?account_id=1&uid=10&username=test&product_id=1&name=test&cash=1&refer=2&json=1
+```

+ 23 - 0
config/base.php

@@ -0,0 +1,23 @@
+<?php
+
+$config['base'] = array
+(
+	# 支付组件支持的支付
+	'pay' => array
+	(
+		'type' => array
+		(
+			'wechat' => '微信支付',
+			//'alipay' => '支付宝',
+		),
+
+		'status' => array
+		(
+			1 => '待支付',
+			2 => '已支付',
+			3 => '支付失败',
+		),
+	),
+);
+
+return $config;

+ 9 - 0
config/env/localhost/default.php

@@ -0,0 +1,9 @@
+<?php
+
+$config['debug'] = array
+(
+	'log' => array('type' => 'file','host' => 'host', 'port' => 'port'),
+);
+
+
+return $config;

+ 7 - 0
daemon/notify/wechat.php

@@ -0,0 +1,7 @@
+<?php
+
+define('DEVER_DAEMON', true);
+
+include(dirname(__FILE__) . DIRECTORY_SEPARATOR . '../../index.php');
+
+Dever::load('pay/notify.wechat');

+ 159 - 0
database/account.php

@@ -0,0 +1,159 @@
+<?php
+
+$type = Dever::config('base', 'pay')->pay['type'];
+
+return array
+(
+	# 表名
+	'name' => 'account',
+	# 显示给用户看的名称
+	'lang' => '账户管理',
+	'order' => 10,
+	# 数据结构
+	'struct' => array
+	(
+	
+		'id' 		=> array
+		(
+			'type' 		=> 'int-11',
+			'name' 		=> 'ID',
+			'default' 	=> '',
+			'desc' 		=> '',
+			'match' 	=> 'is_numeric',
+			'search'	=> 'order',
+			//'list'		=> true,
+		),
+
+		'name'		=> array
+		(
+			'type' 		=> 'varchar-60',
+			'name' 		=> '账户名称',
+			'default' 	=> '',
+			'desc' 		=> '账户名称',
+			'match' 	=> 'is_string',
+			'update'	=> 'text',
+			'search'	=> 'fulltext',
+			'list'		=> true,
+		),
+
+		'type'		=> array
+		(
+			'type' 		=> 'varchar-30',
+			'name' 		=> '支付类型',
+			'default' 	=> 'wechat',
+			'desc' 		=> '支付类型',
+			'match' 	=> 'is_string',
+			'update'	=> 'radio',
+			'option'	=> $type,
+			'search'	=> 'select',
+			'list'		=> true,
+			'control'	=> 'type',
+		),
+
+		'mchid'		=> array
+		(
+			'type' 		=> 'varchar-150',
+			'name' 		=> '商户号',
+			'default' 	=> '',
+			'desc' 		=> '商户号',
+			'match' 	=> 'is_string',
+			'update'	=> 'text',
+		),
+
+		'key'		=> array
+		(
+			'type' 		=> 'varchar-150',
+			'name' 		=> '密匙key',
+			'default' 	=> '',
+			'desc' 		=> '密匙key',
+			'match' 	=> 'is_string',
+			'update'	=> 'text',
+		),
+
+		'appid'		=> array
+		(
+			'type' 		=> 'varchar-150',
+			'name' 		=> 'appid',
+			'default' 	=> '',
+			'desc' 		=> 'appid',
+			'match' 	=> 'is_string',
+			'update'	=> 'text',
+			'show'	=> 'type=wechat',
+		),
+
+		'appsecret'		=> array
+		(
+			'type' 		=> 'varchar-300',
+			'name' 		=> 'appsecret',
+			'default' 	=> '',
+			'desc' 		=> 'appsecret',
+			'match' 	=> 'is_string',
+			'update'	=> 'text',
+			'show'	=> 'type=wechat',
+		),
+
+		'account'		=> array
+		(
+			'type' 		=> 'varchar-150',
+			'name' 		=> '支付账号',
+			'default' 	=> '',
+			'desc' 		=> '支付账号',
+			'match' 	=> 'is_string',
+			'update'	=> 'text',
+			'show'	=> 'type=alipay',
+		),
+
+		'file_cert'		=> array
+		(
+			'type' 		=> 'varchar-150',
+			'name' 		=> '证书cert文件',
+			'default' 	=> '',
+			'desc' 		=> '证书cert文件',
+			'match' 	=> 'option',
+			'update'	=> 'upload',
+			'key'		=> '4',
+		),
+
+		'file_key'		=> array
+		(
+			'type' 		=> 'varchar-150',
+			'name' 		=> '证书key文件',
+			'default' 	=> '',
+			'desc' 		=> '证书key文件',
+			'match' 	=> 'option',
+			'update'	=> 'upload',
+			'key'		=> '4',
+		),
+
+		'timeout'		=> array
+		(
+			'type' 		=> 'int-11',
+			'name' 		=> '支付有效期-秒',
+			'default' 	=> '600',
+			'desc' 		=> '支付有效期',
+			'match' 	=> 'is_numeric',
+			'update'	=> 'text',
+		),
+
+		'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,
+			'search'	=> 'date',
+			'list'		=> 'date("Y-m-d H:i:s", {cdate})',
+		),
+	),
+);

+ 198 - 0
database/order.php

@@ -0,0 +1,198 @@
+<?php
+
+$type = Dever::config('base', 'pay')->pay['type'];
+
+$account = function()
+{
+	return Dever::db('pay/account')->state();
+};
+
+$status = Dever::config('base', 'pay')->pay['status'];
+
+return array
+(
+	# 表名
+	'name' => 'order',
+	# 显示给用户看的名称
+	'lang' => '订单管理',
+	'order' => 1,
+	# 数据结构
+	'struct' => array
+	(
+	
+		'id' 		=> array
+		(
+			'type' 		=> 'int-11',
+			'name' 		=> 'ID',
+			'default' 	=> '',
+			'desc' 		=> '',
+			'match' 	=> 'is_numeric',
+			'search'	=> 'order',
+			//'list'		=> true,
+		),
+
+		'uid'		=> array
+		(
+			'type' 		=> 'int-11',
+			'name' 		=> '用户',
+			'default' 	=> '1',
+			'desc' 		=> '用户',
+			'match' 	=> 'is_numeric',
+			'update'	=> 'text',
+			/*
+			'search'	=> array
+			(
+				'api' => 'passport/user-all',
+				'col' => 'username',
+				'result' => 'id',
+			),
+			'list'		=> 'Dever::load("passport/user-one#username", {uid})',
+			*/
+		),
+
+		'username'		=> array
+		(
+			'type' 		=> 'varchar-200',
+			'name' 		=> '用户名称',
+			'default' 	=> '',
+			'desc' 		=> '用户名称',
+			'match' 	=> 'is_string',
+			'update'	=> 'text',
+			'search'	=> 'fulltext',
+			'list'		=> true,
+		),
+
+		'name'		=> array
+		(
+			'type' 		=> 'varchar-200',
+			'name' 		=> '订单名称',
+			'default' 	=> '',
+			'desc' 		=> '订单名称',
+			'match' 	=> 'is_string',
+			'update'	=> 'text',
+			'search'	=> 'fulltext',
+			'list'		=> true,
+		),
+
+		'order_id'		=> array
+		(
+			'type' 		=> 'varchar-100',
+			'name' 		=> '订单id',
+			'default' 	=> '',
+			'desc' 		=> '订单id',
+			'match' 	=> 'is_numeric',
+			'update'	=> 'text',
+			'list'		=> true,
+		),
+
+		'type'		=> array
+		(
+			'type' 		=> 'varchar-30',
+			'name' 		=> '支付类型',
+			'default' 	=> 'wechat',
+			'desc' 		=> '支付类型',
+			'match' 	=> 'is_string',
+			'update'	=> 'radio',
+			'option'	=> $type,
+			'search'	=> 'select',
+			'list'		=> true,
+			'control'	=> 'type',
+		),
+
+		'product_id'		=> array
+		(
+			'type' 		=> 'int-11',
+			'name' 		=> '产品id',
+			'default' 	=> '1',
+			'desc' 		=> '产品id',
+			'match' 	=> 'is_numeric',
+			'update'	=> 'text',
+		),
+
+		'account_id'		=> array
+		(
+			'type' 		=> 'int-11',
+			'name' 		=> '支付账户',
+			'default' 	=> '1',
+			'desc' 		=> '支付账户',
+			'match' 	=> 'is_numeric',
+			'update'	=> 'select',
+			'option'	=> $account,
+			'search'	=> 'select',
+			'list'		=> true,
+		),
+
+		'cash'		=> array
+		(
+			'type' 		=> 'varchar-11',
+			'name' 		=> '金额',
+			'default' 	=> '',
+			'desc' 		=> '金额',
+			'match' 	=> 'is_string',
+			'update'	=> 'text',
+			'list'		=> true,
+		),
+
+		'status'		=> array
+		(
+			'type' 		=> 'tinyint-1',
+			'name' 		=> '支付状态',
+			'default' 	=> '1',
+			'desc' 		=> '支付状态',
+			'match' 	=> 'is_numeric',
+			'update'	=> 'radio',
+			'option'	=> $status,
+			'search'	=> 'select',
+			'list'		=> true,
+			'control'	=> 'status',
+		),
+
+		'status_desc'		=> array
+		(
+			'type' 		=> 'varchar-300',
+			'name' 		=> '支付状态说明',
+			'default' 	=> '',
+			'desc' 		=> '请输入支付状态说明',
+			'match' 	=> 'option',
+			'update'	=> 'textarea',
+			'show'		=> 'status=3',
+		),
+
+		'param'		=> array
+		(
+			'type' 		=> 'text-255',
+			'name' 		=> '支付信息-用于二次支付',
+			'default' 	=> '',
+			'desc' 		=> '支付信息',
+			'match' 	=> 'option',
+		),
+
+		'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,
+			'search'	=> 'date',
+			'list'		=> 'date("Y-m-d H:i:s", {cdate})',
+		),
+	),
+
+	'manage' => array
+	(
+		'insert' => false,
+		'edit' => false,
+		'delete' => false,
+	),
+);

+ 8 - 0
index.php

@@ -0,0 +1,8 @@
+<?php
+
+define('DEVER_APP_NAME', 'pay');
+define('DEVER_APP_LANG', '支付管理');
+define('DEVER_APP_PATH', dirname(__FILE__) . DIRECTORY_SEPARATOR);
+define('DEVER_MANAGE_ORDER', 30);
+define('DEVER_MANAGE_ICON', 'glyphicon glyphicon-usd');
+include(DEVER_APP_PATH . '../boot.php');

+ 71 - 0
lib/Api.php

@@ -0,0 +1,71 @@
+<?php
+
+namespace Attr\Src;
+
+use Dever;
+
+class Api
+{
+	/**
+	 * 获取属性配置
+	 *
+	 * @return mixed
+	 */
+	public function get()
+	{
+		$cate = Dever::db('attr/cate')->state();
+
+		if ($cate) {
+			foreach ($cate as $k => $v) {
+				$cate[$k]['child'] = Dever::db('attr/info')->state(array('cate_id' => $v['id']));
+			}
+		}
+
+		$cate['state'] = 1;
+
+		return $cate;
+	}
+
+	/**
+	 * 获取属性详细信息
+	 *
+	 * @return mixed
+	 */
+	public function getInfo($ids, $value)
+	{
+		$result = array();
+		if ($ids) {
+			$where['ids'] = $ids;
+			$cate = Dever::db('attr/cate')->state();
+			$data = Dever::db('attr/info')->getAllByIds($where);
+
+			$ids = explode(',', $ids);
+			$value = explode(',', $value);
+			if ($data) {
+				foreach ($ids as $k => $v) {
+					if (isset($data[$v])) {
+						$cate_id = $data[$v]['cate_id'];
+
+						if (!isset($result[$cate_id])) {
+							$result[$cate_id] = array
+							(
+								'name' => $cate[$cate_id]['name'],
+								'id' => $cate_id
+							);
+						}
+
+						$result[$cate_id]['attr'][$v] = array
+						(
+							'name' => $data[$v]['name'],
+							'value' => $value[$k],
+							'id' => $v
+						);
+					}
+				}
+			}
+		}
+		
+
+		return $result;
+	}
+}

+ 94 - 0
lib/Core.php

@@ -0,0 +1,94 @@
+<?php namespace Pay\Lib;
+use Dever;
+
+class Core
+{
+	/**
+	 * 更新订单状态
+	 */
+	protected function updateOrder($order_id, $cash, $desc = '')
+	{
+		$db = Dever::db('pay/order');
+		$info = $db->one(array('order_id' => $order_id, 'status' => 1));
+		if ($info) {
+			$param['where_id'] = $info['id'];
+			$param['status'] = 2;
+			$msg = '支付成功';
+			if ($desc) {
+				$param['status'] = 3;
+				$param['status_desc'] = $desc;
+				$msg = '支付失败||' . $desc;
+			}
+			$this->log($msg, $info);
+			$db->update($param);
+		}
+	}
+
+	/**
+	 * 更新订单的支付信息
+	 */
+	protected function updateOrderParam($order_id, $param)
+	{
+		$db = Dever::db('pay/order');
+		$info = $db->one(array('order_id' => $order_id, 'status' => 1));
+		if ($info) {
+			$param['where_id'] = $info['id'];
+			$param['param'] = Dever::array_encode($param);
+			$db->update($param);
+		}
+	}
+
+	/**
+	 * 创建订单
+	 */
+	protected function createOrder($uid, $username, $account_id, $product_id, $name, $cash, $type)
+	{
+		$db = Dever::db('pay/order');
+		$order_id = Dever::order(Dever::uid($uid));
+		$info = $db->one(array('order_id' => $order_id));
+		if ($info) {
+			return $this->createOrder();
+		} else {
+			$add['status'] = 1;
+			$add['uid'] = $uid;
+			$add['username'] = $username;
+			$add['account_id'] = $account_id;
+			$add['name'] = $name;
+			$add['cash'] = $cash;
+			$add['type'] = $type;
+			$add['order_id'] = $order_id;
+			$add['product_id'] = $product_id;
+			$add['id'] = $db->insert($add);
+			$msg = '发起支付';
+			$this->log($msg, $add);
+		}
+		return $order_id;
+	}
+
+	/**
+	 * 获取回调url
+	 */
+	protected function url($type)
+	{
+		$project = Dever::project('pay');
+		return $project['url'] . 'daemon/notify/'.$type.'.php';
+	}
+
+	/**
+	 * 写日志
+	 */
+	protected function log($msg, $data = array())
+	{
+		if ($data) {
+			$data = Dever::json_encode($data);
+			$msg .= '||' . $data;
+			/*
+			$insert = $data;
+			$insert['cdate'] = time();
+			Dever::db('pay/order_log')->insert($insert);
+			*/
+		}
+
+		Dever::log($msg, 'pay');
+	}
+}

+ 188 - 0
lib/Wechat.php

@@ -0,0 +1,188 @@
+<?php namespace Pay\Lib;
+use Dever;
+Dever::apply('sdk/wechat', 'pay');
+
+class Wechat extends Core
+{
+	public function __construct($config)
+	{
+		$project = Dever::project('pay');
+		$this->config = new \WxPayConfig();
+		# 通知接口
+		$config['notify'] = $this->url($config['type']);
+		# 证书
+		$config['ssl'] = array
+		(
+			'cert' => $config['file_cert'],
+			'key' => $config['file_key'],
+		);
+
+		$this->config->set($config['appid'], $config['appsecret'], $config['mchid'], $config['notify'], $config['key'], $config['ssl'], $config['type'], $config['timeout']);
+	}
+
+	/**
+	 * 通知
+	 */
+	public function notify()
+	{
+		$callback = new Callback();
+		$result = $callback->Handle($this->config, false);
+	}
+
+	/**
+	 * 获取统一下单的基本信息
+	 */
+	public function order($account_id, $uid, $username, $product_id, $name, $cash, $openid = false, $type = 1)
+	{
+		$trade_type = $this->getType($type);
+		$order_id = $this->createOrder($uid, $username, $account_id, $product_id, $name, $cash, $this->config->GetType());
+		$tools = new \JsApiPay($this->config);
+		$openid = $openid ? $openid : $tools->GetOpenid();
+		$input = new \WxPayUnifiedOrder();
+		$input->SetBody($name);
+		$input->SetAttach($name);
+		$input->SetOut_trade_no($order_id);
+		$input->SetTotal_fee($num);
+		$input->SetTime_start(date("YmdHis"));
+		$input->SetTime_expire(date("YmdHis", time() + $this->config->GetTimeOut()));
+		//$input->SetGoods_tag($name);
+		$input->SetNotify_url($this->config->GetNotifyUrl());
+		$input->SetTrade_type($trade_type);
+		$input->SetProduct_id($product_id);
+		$input->SetOpenid($openid);
+
+		if ($type == 1) {
+			$order = \WxPayApi::unifiedOrder($this->config, $input);
+			# 下单信息
+			$this->updateOrderParam($order_id, $order);
+			return array($order_id, $order);
+		} else {
+			# 下单信息
+			$this->updateOrderParam($order_id, $input);
+			return array($order_id, $input);
+		}
+	}
+
+	/**
+	 * 获取二维码支付
+	 */
+	public function qrcode($order, $refer)
+	{
+		$notify = new \NativePay();
+		$result = $notify->GetPayUrl($order[1]);
+		$url = $result['code_url'];
+		return $url;
+	}
+
+
+	/**
+	 * 获取页面支付
+	 */
+	public function page($order, $refer)
+	{
+		$tools = new \JsApiPay($this->config);
+		$info = $tools->GetJsApiParameters($order[1]);
+
+		$html = '<script type="text/javascript">
+		function jsApiCall()
+		{
+			WeixinJSBridge.invoke(
+				"getBrandWCPayRequest",
+				'.$info.',
+				function(res){
+					//WeixinJSBridge.log(res.err_msg);
+					if(res.err_msg == "get_brand_wcpay_request:ok")
+					{
+						location.href = "'.$refer.'";
+					} else {
+						alert(res.err_code+res.err_desc+res.err_msg);
+					}
+				}
+			);
+		}
+
+		function callpay()
+		{
+			if (typeof WeixinJSBridge == "undefined"){
+			    if( document.addEventListener ){
+			        document.addEventListener("WeixinJSBridgeReady", jsApiCall, false);
+			    }else if (document.attachEvent){
+			        document.attachEvent("WeixinJSBridgeReady", jsApiCall); 
+			        document.attachEvent("onWeixinJSBridgeReady", jsApiCall);
+			    }
+			}else{
+			    jsApiCall();
+			}
+		}
+		callpay();
+		</script>';
+
+		return $html;
+	}
+
+	private function getType($type)
+	{
+		switch ($type) {
+			case 1:
+				$type = 'JSAPI';
+				break;
+			
+			case 2:
+				$type = 'NATIVE';
+				break;
+		}
+
+		return $type;
+	}
+}
+
+class Callback extends \WxPayNotify
+{
+	public function NotifyProcess($objData, $config, &$msg)
+	{
+		$data = $objData->GetValues();
+		$obj = Dever::load('pay/lib/wechat');
+		$callback = function($msg = '') use ($obj, $data) {
+			if ($msg) {
+				$msg = $data['transaction_id'] . ':' . $msg;
+			}
+			$obj->updateOrder($data['out_trade_no'], $data['cash_fee'], $msg);
+		};
+		# 参数校验
+		if(!array_key_exists("return_code", $data) 
+			||(array_key_exists("return_code", $data) && $data['return_code'] != "SUCCESS")) {
+			$msg = '异常';
+			return false;
+		}
+		if(!array_key_exists("transaction_id", $data)){
+			$msg = '输入参数不正确';
+			return false;
+		}
+
+		# 进行签名验证
+		try {
+			$checkResult = $objData->CheckSign($config);
+			if($checkResult == false){
+				$msg = '签名错误';
+				$callback($msg);
+				return false;
+			}
+		} catch(Exception $e) {
+			$msg = '签名异常';
+			$callback($msg);
+			return false;
+		}
+
+		# 查询订单,判断订单真实性
+		if(!$this->Queryorder($data["transaction_id"])){
+			$msg = '订单查询失败';
+			$callback($msg);
+			return false;
+		}
+
+		# 处理业务逻辑
+		$callback();
+
+		return true;
+	}
+}

+ 3312 - 0
sdk/qrcode.php

@@ -0,0 +1,3312 @@
+<?php
+
+/*
+ * PHP QR Code encoder
+ *
+ * This file contains MERGED version of PHP QR Code library.
+ * It was auto-generated from full version for your convenience.
+ *
+ * This merged version was configured to not requre any external files,
+ * with disabled cache, error loging and weker but faster mask matching.
+ * If you need tune it up please use non-merged version.
+ *
+ * For full version, documentation, examples of use please visit:
+ *
+ *    http://phpqrcode.sourceforge.net/
+ *    https://sourceforge.net/projects/phpqrcode/
+ *
+ * PHP QR Code is distributed under LGPL 3
+ * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+ 
+ 
+
+/*
+ * Version: 1.1.4
+ * Build: 2010100721
+ */
+
+
+
+//---- qrconst.php -----------------------------
+
+
+
+
+
+/*
+ * PHP QR Code encoder
+ *
+ * Common constants
+ *
+ * Based on libqrencode C library distributed under LGPL 2.1
+ * Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>
+ *
+ * PHP QR Code is distributed under LGPL 3
+ * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+ 
+	// Encoding modes
+	 
+	define('QR_MODE_NUL', -1);
+	define('QR_MODE_NUM', 0);
+	define('QR_MODE_AN', 1);
+	define('QR_MODE_8', 2);
+	define('QR_MODE_KANJI', 3);
+	define('QR_MODE_STRUCTURE', 4);
+
+	// Levels of error correction.
+
+	define('QR_ECLEVEL_L', 0);
+	define('QR_ECLEVEL_M', 1);
+	define('QR_ECLEVEL_Q', 2);
+	define('QR_ECLEVEL_H', 3);
+	
+	// Supported output formats
+	
+	define('QR_FORMAT_TEXT', 0);
+	define('QR_FORMAT_PNG',  1);
+	
+	class qrstr {
+		public static function set(&$srctab, $x, $y, $repl, $replLen = false) {
+			$srctab[$y] = substr_replace($srctab[$y], ($replLen !== false)?substr($repl,0,$replLen):$repl, $x, ($replLen !== false)?$replLen:strlen($repl));
+		}
+	}	
+
+
+
+//---- merged_config.php -----------------------------
+
+
+
+
+/*
+ * PHP QR Code encoder
+ *
+ * Config file, tuned-up for merged verion
+ */
+     
+    define('QR_CACHEABLE', false);       // use cache - more disk reads but less CPU power, masks and format templates are stored there
+    define('QR_CACHE_DIR', false);       // used when QR_CACHEABLE === true
+    define('QR_LOG_DIR', false);         // default error logs dir   
+    
+    define('QR_FIND_BEST_MASK', true);                                                          // if true, estimates best mask (spec. default, but extremally slow; set to false to significant performance boost but (propably) worst quality code
+    define('QR_FIND_FROM_RANDOM', 2);                                                       // if false, checks all masks available, otherwise value tells count of masks need to be checked, mask id are got randomly
+    define('QR_DEFAULT_MASK', 2);                                                               // when QR_FIND_BEST_MASK === false
+                                                  
+    define('QR_PNG_MAXIMUM_SIZE',  1024);                                                       // maximum allowed png image width (in pixels), tune to make sure GD and PHP can handle such big images
+                                                  
+
+
+
+//---- qrtools.php -----------------------------
+
+
+
+
+/*
+ * PHP QR Code encoder
+ *
+ * Toolset, handy and debug utilites.
+ *
+ * PHP QR Code is distributed under LGPL 3
+ * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+    class QRtools {
+    
+        //----------------------------------------------------------------------
+        public static function binarize($frame)
+        {
+            $len = count($frame);
+            foreach ($frame as &$frameLine) {
+                
+                for($i=0; $i<$len; $i++) {
+                    $frameLine[$i] = (ord($frameLine[$i])&1)?'1':'0';
+                }
+            }
+            
+            return $frame;
+        }
+        
+        //----------------------------------------------------------------------
+        public static function tcpdfBarcodeArray($code, $mode = 'QR,L', $tcPdfVersion = '4.5.037')
+        {
+            $barcode_array = array();
+            
+            if (!is_array($mode))
+                $mode = explode(',', $mode);
+                
+            $eccLevel = 'L';
+                
+            if (count($mode) > 1) {
+                $eccLevel = $mode[1];
+            }
+                
+            $qrTab = QRcode::text($code, false, $eccLevel);
+            $size = count($qrTab);
+                
+            $barcode_array['num_rows'] = $size;
+            $barcode_array['num_cols'] = $size;
+            $barcode_array['bcode'] = array();
+                
+            foreach ($qrTab as $line) {
+                $arrAdd = array();
+                foreach(str_split($line) as $char)
+                    $arrAdd[] = ($char=='1')?1:0;
+                $barcode_array['bcode'][] = $arrAdd;
+            }
+                    
+            return $barcode_array;
+        }
+        
+        //----------------------------------------------------------------------
+        public static function clearCache()
+        {
+            self::$frames = array();
+        }
+        
+        //----------------------------------------------------------------------
+        public static function buildCache()
+        {
+			QRtools::markTime('before_build_cache');
+			
+			$mask = new QRmask();
+            for ($a=1; $a <= QRSPEC_VERSION_MAX; $a++) {
+                $frame = QRspec::newFrame($a);
+                if (QR_IMAGE) {
+                    $fileName = QR_CACHE_DIR.'frame_'.$a.'.png';
+                    QRimage::png(self::binarize($frame), $fileName, 1, 0);
+                }
+				
+				$width = count($frame);
+				$bitMask = array_fill(0, $width, array_fill(0, $width, 0));
+				for ($maskNo=0; $maskNo<8; $maskNo++)
+					$mask->makeMaskNo($maskNo, $width, $frame, $bitMask, true);
+            }
+			
+			QRtools::markTime('after_build_cache');
+        }
+
+        //----------------------------------------------------------------------
+        public static function log($outfile, $err)
+        {
+            if (QR_LOG_DIR !== false) {
+                if ($err != '') {
+                    if ($outfile !== false) {
+                        file_put_contents(QR_LOG_DIR.basename($outfile).'-errors.txt', date('Y-m-d H:i:s').': '.$err, FILE_APPEND);
+                    } else {
+                        file_put_contents(QR_LOG_DIR.'errors.txt', date('Y-m-d H:i:s').': '.$err, FILE_APPEND);
+                    }
+                }    
+            }
+        }
+        
+        //----------------------------------------------------------------------
+        public static function dumpMask($frame) 
+        {
+            $width = count($frame);
+            for($y=0;$y<$width;$y++) {
+                for($x=0;$x<$width;$x++) {
+                    echo ord($frame[$y][$x]).',';
+                }
+            }
+        }
+        
+        //----------------------------------------------------------------------
+        public static function markTime($markerId)
+        {
+            list($usec, $sec) = explode(" ", microtime());
+            $time = ((float)$usec + (float)$sec);
+            
+            if (!isset($GLOBALS['qr_time_bench']))
+                $GLOBALS['qr_time_bench'] = array();
+            
+            $GLOBALS['qr_time_bench'][$markerId] = $time;
+        }
+        
+        //----------------------------------------------------------------------
+        public static function timeBenchmark()
+        {
+            self::markTime('finish');
+        
+            $lastTime = 0;
+            $startTime = 0;
+            $p = 0;
+
+            echo '<table cellpadding="3" cellspacing="1">
+                    <thead><tr style="border-bottom:1px solid silver"><td colspan="2" style="text-align:center">BENCHMARK</td></tr></thead>
+                    <tbody>';
+
+            foreach($GLOBALS['qr_time_bench'] as $markerId=>$thisTime) {
+                if ($p > 0) {
+                    echo '<tr><th style="text-align:right">till '.$markerId.': </th><td>'.number_format($thisTime-$lastTime, 6).'s</td></tr>';
+                } else {
+                    $startTime = $thisTime;
+                }
+                
+                $p++;
+                $lastTime = $thisTime;
+            }
+            
+            echo '</tbody><tfoot>
+                <tr style="border-top:2px solid black"><th style="text-align:right">TOTAL: </th><td>'.number_format($lastTime-$startTime, 6).'s</td></tr>
+            </tfoot>
+            </table>';
+        }
+        
+    }
+    
+    //##########################################################################
+    
+    QRtools::markTime('start');
+    
+
+
+
+//---- qrspec.php -----------------------------
+
+
+
+
+/*
+ * PHP QR Code encoder
+ *
+ * QR Code specifications
+ *
+ * Based on libqrencode C library distributed under LGPL 2.1
+ * Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>
+ *
+ * PHP QR Code is distributed under LGPL 3
+ * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
+ *
+ * The following data / specifications are taken from
+ * "Two dimensional symbol -- QR-code -- Basic Specification" (JIS X0510:2004)
+ *  or
+ * "Automatic identification and data capture techniques -- 
+ *  QR Code 2005 bar code symbology specification" (ISO/IEC 18004:2006)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+ 
+    define('QRSPEC_VERSION_MAX', 40);
+    define('QRSPEC_WIDTH_MAX',   177);
+
+    define('QRCAP_WIDTH',        0);
+    define('QRCAP_WORDS',        1);
+    define('QRCAP_REMINDER',     2);
+    define('QRCAP_EC',           3);
+
+    class QRspec {
+    
+        public static $capacity = array(
+            array(  0,    0, 0, array(   0,    0,    0,    0)),
+            array( 21,   26, 0, array(   7,   10,   13,   17)), // 1
+            array( 25,   44, 7, array(  10,   16,   22,   28)),
+            array( 29,   70, 7, array(  15,   26,   36,   44)),
+            array( 33,  100, 7, array(  20,   36,   52,   64)),
+            array( 37,  134, 7, array(  26,   48,   72,   88)), // 5
+            array( 41,  172, 7, array(  36,   64,   96,  112)),
+            array( 45,  196, 0, array(  40,   72,  108,  130)),
+            array( 49,  242, 0, array(  48,   88,  132,  156)),
+            array( 53,  292, 0, array(  60,  110,  160,  192)),
+            array( 57,  346, 0, array(  72,  130,  192,  224)), //10
+            array( 61,  404, 0, array(  80,  150,  224,  264)),
+            array( 65,  466, 0, array(  96,  176,  260,  308)),
+            array( 69,  532, 0, array( 104,  198,  288,  352)),
+            array( 73,  581, 3, array( 120,  216,  320,  384)),
+            array( 77,  655, 3, array( 132,  240,  360,  432)), //15
+            array( 81,  733, 3, array( 144,  280,  408,  480)),
+            array( 85,  815, 3, array( 168,  308,  448,  532)),
+            array( 89,  901, 3, array( 180,  338,  504,  588)),
+            array( 93,  991, 3, array( 196,  364,  546,  650)),
+            array( 97, 1085, 3, array( 224,  416,  600,  700)), //20
+            array(101, 1156, 4, array( 224,  442,  644,  750)),
+            array(105, 1258, 4, array( 252,  476,  690,  816)),
+            array(109, 1364, 4, array( 270,  504,  750,  900)),
+            array(113, 1474, 4, array( 300,  560,  810,  960)),
+            array(117, 1588, 4, array( 312,  588,  870, 1050)), //25
+            array(121, 1706, 4, array( 336,  644,  952, 1110)),
+            array(125, 1828, 4, array( 360,  700, 1020, 1200)),
+            array(129, 1921, 3, array( 390,  728, 1050, 1260)),
+            array(133, 2051, 3, array( 420,  784, 1140, 1350)),
+            array(137, 2185, 3, array( 450,  812, 1200, 1440)), //30
+            array(141, 2323, 3, array( 480,  868, 1290, 1530)),
+            array(145, 2465, 3, array( 510,  924, 1350, 1620)),
+            array(149, 2611, 3, array( 540,  980, 1440, 1710)),
+            array(153, 2761, 3, array( 570, 1036, 1530, 1800)),
+            array(157, 2876, 0, array( 570, 1064, 1590, 1890)), //35
+            array(161, 3034, 0, array( 600, 1120, 1680, 1980)),
+            array(165, 3196, 0, array( 630, 1204, 1770, 2100)),
+            array(169, 3362, 0, array( 660, 1260, 1860, 2220)),
+            array(173, 3532, 0, array( 720, 1316, 1950, 2310)),
+            array(177, 3706, 0, array( 750, 1372, 2040, 2430)) //40
+        );
+        
+        //----------------------------------------------------------------------
+        public static function getDataLength($version, $level)
+        {
+            return self::$capacity[$version][QRCAP_WORDS] - self::$capacity[$version][QRCAP_EC][$level];
+        }
+        
+        //----------------------------------------------------------------------
+        public static function getECCLength($version, $level)
+        {
+            return self::$capacity[$version][QRCAP_EC][$level];
+        }
+        
+        //----------------------------------------------------------------------
+        public static function getWidth($version)
+        {
+            return self::$capacity[$version][QRCAP_WIDTH];
+        }
+        
+        //----------------------------------------------------------------------
+        public static function getRemainder($version)
+        {
+            return self::$capacity[$version][QRCAP_REMINDER];
+        }
+        
+        //----------------------------------------------------------------------
+        public static function getMinimumVersion($size, $level)
+        {
+
+            for($i=1; $i<= QRSPEC_VERSION_MAX; $i++) {
+                $words  = self::$capacity[$i][QRCAP_WORDS] - self::$capacity[$i][QRCAP_EC][$level];
+                if($words >= $size) 
+                    return $i;
+            }
+
+            return -1;
+        }
+    
+        //######################################################################
+        
+        public static $lengthTableBits = array(
+            array(10, 12, 14),
+            array( 9, 11, 13),
+            array( 8, 16, 16),
+            array( 8, 10, 12)
+        );
+        
+        //----------------------------------------------------------------------
+        public static function lengthIndicator($mode, $version)
+        {
+            if ($mode == QR_MODE_STRUCTURE)
+                return 0;
+                
+            if ($version <= 9) {
+                $l = 0;
+            } else if ($version <= 26) {
+                $l = 1;
+            } else {
+                $l = 2;
+            }
+
+            return self::$lengthTableBits[$mode][$l];
+        }
+        
+        //----------------------------------------------------------------------
+        public static function maximumWords($mode, $version)
+        {
+            if($mode == QR_MODE_STRUCTURE) 
+                return 3;
+                
+            if($version <= 9) {
+                $l = 0;
+            } else if($version <= 26) {
+                $l = 1;
+            } else {
+                $l = 2;
+            }
+
+            $bits = self::$lengthTableBits[$mode][$l];
+            $words = (1 << $bits) - 1;
+            
+            if($mode == QR_MODE_KANJI) {
+                $words *= 2; // the number of bytes is required
+            }
+
+            return $words;
+        }
+
+        // Error correction code -----------------------------------------------
+        // Table of the error correction code (Reed-Solomon block)
+        // See Table 12-16 (pp.30-36), JIS X0510:2004.
+
+        public static $eccTable = array(
+            array(array( 0,  0), array( 0,  0), array( 0,  0), array( 0,  0)),
+            array(array( 1,  0), array( 1,  0), array( 1,  0), array( 1,  0)), // 1
+            array(array( 1,  0), array( 1,  0), array( 1,  0), array( 1,  0)),
+            array(array( 1,  0), array( 1,  0), array( 2,  0), array( 2,  0)),
+            array(array( 1,  0), array( 2,  0), array( 2,  0), array( 4,  0)),
+            array(array( 1,  0), array( 2,  0), array( 2,  2), array( 2,  2)), // 5
+            array(array( 2,  0), array( 4,  0), array( 4,  0), array( 4,  0)),
+            array(array( 2,  0), array( 4,  0), array( 2,  4), array( 4,  1)),
+            array(array( 2,  0), array( 2,  2), array( 4,  2), array( 4,  2)),
+            array(array( 2,  0), array( 3,  2), array( 4,  4), array( 4,  4)),
+            array(array( 2,  2), array( 4,  1), array( 6,  2), array( 6,  2)), //10
+            array(array( 4,  0), array( 1,  4), array( 4,  4), array( 3,  8)),
+            array(array( 2,  2), array( 6,  2), array( 4,  6), array( 7,  4)),
+            array(array( 4,  0), array( 8,  1), array( 8,  4), array(12,  4)),
+            array(array( 3,  1), array( 4,  5), array(11,  5), array(11,  5)),
+            array(array( 5,  1), array( 5,  5), array( 5,  7), array(11,  7)), //15
+            array(array( 5,  1), array( 7,  3), array(15,  2), array( 3, 13)),
+            array(array( 1,  5), array(10,  1), array( 1, 15), array( 2, 17)),
+            array(array( 5,  1), array( 9,  4), array(17,  1), array( 2, 19)),
+            array(array( 3,  4), array( 3, 11), array(17,  4), array( 9, 16)),
+            array(array( 3,  5), array( 3, 13), array(15,  5), array(15, 10)), //20
+            array(array( 4,  4), array(17,  0), array(17,  6), array(19,  6)),
+            array(array( 2,  7), array(17,  0), array( 7, 16), array(34,  0)),
+            array(array( 4,  5), array( 4, 14), array(11, 14), array(16, 14)),
+            array(array( 6,  4), array( 6, 14), array(11, 16), array(30,  2)),
+            array(array( 8,  4), array( 8, 13), array( 7, 22), array(22, 13)), //25
+            array(array(10,  2), array(19,  4), array(28,  6), array(33,  4)),
+            array(array( 8,  4), array(22,  3), array( 8, 26), array(12, 28)),
+            array(array( 3, 10), array( 3, 23), array( 4, 31), array(11, 31)),
+            array(array( 7,  7), array(21,  7), array( 1, 37), array(19, 26)),
+            array(array( 5, 10), array(19, 10), array(15, 25), array(23, 25)), //30
+            array(array(13,  3), array( 2, 29), array(42,  1), array(23, 28)),
+            array(array(17,  0), array(10, 23), array(10, 35), array(19, 35)),
+            array(array(17,  1), array(14, 21), array(29, 19), array(11, 46)),
+            array(array(13,  6), array(14, 23), array(44,  7), array(59,  1)),
+            array(array(12,  7), array(12, 26), array(39, 14), array(22, 41)), //35
+            array(array( 6, 14), array( 6, 34), array(46, 10), array( 2, 64)),
+            array(array(17,  4), array(29, 14), array(49, 10), array(24, 46)),
+            array(array( 4, 18), array(13, 32), array(48, 14), array(42, 32)),
+            array(array(20,  4), array(40,  7), array(43, 22), array(10, 67)),
+            array(array(19,  6), array(18, 31), array(34, 34), array(20, 61)),//40
+        );                                                                       
+
+        //----------------------------------------------------------------------
+        // CACHEABLE!!!
+        
+        public static function getEccSpec($version, $level, array &$spec)
+        {
+            if (count($spec) < 5) {
+                $spec = array(0,0,0,0,0);
+            }
+
+            $b1   = self::$eccTable[$version][$level][0];
+            $b2   = self::$eccTable[$version][$level][1];
+            $data = self::getDataLength($version, $level);
+            $ecc  = self::getECCLength($version, $level);
+
+            if($b2 == 0) {
+                $spec[0] = $b1;
+                $spec[1] = (int)($data / $b1);
+                $spec[2] = (int)($ecc / $b1);
+                $spec[3] = 0; 
+                $spec[4] = 0;
+            } else {
+                $spec[0] = $b1;
+                $spec[1] = (int)($data / ($b1 + $b2));
+                $spec[2] = (int)($ecc  / ($b1 + $b2));
+                $spec[3] = $b2;
+                $spec[4] = $spec[1] + 1;
+            }
+        }
+
+        // Alignment pattern ---------------------------------------------------
+
+        // Positions of alignment patterns.
+        // This array includes only the second and the third position of the 
+        // alignment patterns. Rest of them can be calculated from the distance 
+        // between them.
+         
+        // See Table 1 in Appendix E (pp.71) of JIS X0510:2004.
+         
+        public static $alignmentPattern = array(      
+            array( 0,  0),
+            array( 0,  0), array(18,  0), array(22,  0), array(26,  0), array(30,  0), // 1- 5
+            array(34,  0), array(22, 38), array(24, 42), array(26, 46), array(28, 50), // 6-10
+            array(30, 54), array(32, 58), array(34, 62), array(26, 46), array(26, 48), //11-15
+            array(26, 50), array(30, 54), array(30, 56), array(30, 58), array(34, 62), //16-20
+            array(28, 50), array(26, 50), array(30, 54), array(28, 54), array(32, 58), //21-25
+            array(30, 58), array(34, 62), array(26, 50), array(30, 54), array(26, 52), //26-30
+            array(30, 56), array(34, 60), array(30, 58), array(34, 62), array(30, 54), //31-35
+            array(24, 50), array(28, 54), array(32, 58), array(26, 54), array(30, 58), //35-40
+        );                                                                                  
+
+        
+        /** --------------------------------------------------------------------
+         * Put an alignment marker.
+         * @param frame
+         * @param width
+         * @param ox,oy center coordinate of the pattern
+         */
+        public static function putAlignmentMarker(array &$frame, $ox, $oy)
+        {
+            $finder = array(
+                "\xa1\xa1\xa1\xa1\xa1",
+                "\xa1\xa0\xa0\xa0\xa1",
+                "\xa1\xa0\xa1\xa0\xa1",
+                "\xa1\xa0\xa0\xa0\xa1",
+                "\xa1\xa1\xa1\xa1\xa1"
+            );                        
+            
+            $yStart = $oy-2;         
+            $xStart = $ox-2;
+            
+            for($y=0; $y<5; $y++) {
+                QRstr::set($frame, $xStart, $yStart+$y, $finder[$y]);
+            }
+        }
+
+        //----------------------------------------------------------------------
+        public static function putAlignmentPattern($version, &$frame, $width)
+        {
+            if($version < 2)
+                return;
+
+            $d = self::$alignmentPattern[$version][1] - self::$alignmentPattern[$version][0];
+            if($d < 0) {
+                $w = 2;
+            } else {
+                $w = (int)(($width - self::$alignmentPattern[$version][0]) / $d + 2);
+            }
+
+            if($w * $w - 3 == 1) {
+                $x = self::$alignmentPattern[$version][0];
+                $y = self::$alignmentPattern[$version][0];
+                self::putAlignmentMarker($frame, $x, $y);
+                return;
+            }
+
+            $cx = self::$alignmentPattern[$version][0];
+            for($x=1; $x<$w - 1; $x++) {
+                self::putAlignmentMarker($frame, 6, $cx);
+                self::putAlignmentMarker($frame, $cx,  6);
+                $cx += $d;
+            }
+
+            $cy = self::$alignmentPattern[$version][0];
+            for($y=0; $y<$w-1; $y++) {
+                $cx = self::$alignmentPattern[$version][0];
+                for($x=0; $x<$w-1; $x++) {
+                    self::putAlignmentMarker($frame, $cx, $cy);
+                    $cx += $d;
+                }
+                $cy += $d;
+            }
+        }
+
+        // Version information pattern -----------------------------------------
+
+		// Version information pattern (BCH coded).
+        // See Table 1 in Appendix D (pp.68) of JIS X0510:2004.
+        
+		// size: [QRSPEC_VERSION_MAX - 6]
+		
+        public static $versionPattern = array(
+            0x07c94, 0x085bc, 0x09a99, 0x0a4d3, 0x0bbf6, 0x0c762, 0x0d847, 0x0e60d,
+            0x0f928, 0x10b78, 0x1145d, 0x12a17, 0x13532, 0x149a6, 0x15683, 0x168c9,
+            0x177ec, 0x18ec4, 0x191e1, 0x1afab, 0x1b08e, 0x1cc1a, 0x1d33f, 0x1ed75,
+            0x1f250, 0x209d5, 0x216f0, 0x228ba, 0x2379f, 0x24b0b, 0x2542e, 0x26a64,
+            0x27541, 0x28c69
+        );
+
+        //----------------------------------------------------------------------
+        public static function getVersionPattern($version)
+        {
+            if($version < 7 || $version > QRSPEC_VERSION_MAX)
+                return 0;
+
+            return self::$versionPattern[$version -7];
+        }
+
+        // Format information --------------------------------------------------
+        // See calcFormatInfo in tests/test_qrspec.c (orginal qrencode c lib)
+        
+        public static $formatInfo = array(
+            array(0x77c4, 0x72f3, 0x7daa, 0x789d, 0x662f, 0x6318, 0x6c41, 0x6976),
+            array(0x5412, 0x5125, 0x5e7c, 0x5b4b, 0x45f9, 0x40ce, 0x4f97, 0x4aa0),
+            array(0x355f, 0x3068, 0x3f31, 0x3a06, 0x24b4, 0x2183, 0x2eda, 0x2bed),
+            array(0x1689, 0x13be, 0x1ce7, 0x19d0, 0x0762, 0x0255, 0x0d0c, 0x083b)
+        );
+
+        public static function getFormatInfo($mask, $level)
+        {
+            if($mask < 0 || $mask > 7)
+                return 0;
+                
+            if($level < 0 || $level > 3)
+                return 0;                
+
+            return self::$formatInfo[$level][$mask];
+        }
+
+        // Frame ---------------------------------------------------------------
+        // Cache of initial frames.
+         
+        public static $frames = array();
+
+        /** --------------------------------------------------------------------
+         * Put a finder pattern.
+         * @param frame
+         * @param width
+         * @param ox,oy upper-left coordinate of the pattern
+         */
+        public static function putFinderPattern(&$frame, $ox, $oy)
+        {
+            $finder = array(
+                "\xc1\xc1\xc1\xc1\xc1\xc1\xc1",
+                "\xc1\xc0\xc0\xc0\xc0\xc0\xc1",
+                "\xc1\xc0\xc1\xc1\xc1\xc0\xc1",
+                "\xc1\xc0\xc1\xc1\xc1\xc0\xc1",
+                "\xc1\xc0\xc1\xc1\xc1\xc0\xc1",
+                "\xc1\xc0\xc0\xc0\xc0\xc0\xc1",
+                "\xc1\xc1\xc1\xc1\xc1\xc1\xc1"
+            );                            
+            
+            for($y=0; $y<7; $y++) {
+                QRstr::set($frame, $ox, $oy+$y, $finder[$y]);
+            }
+        }
+
+        //----------------------------------------------------------------------
+        public static function createFrame($version)
+        {
+            $width = self::$capacity[$version][QRCAP_WIDTH];
+            $frameLine = str_repeat ("\0", $width);
+            $frame = array_fill(0, $width, $frameLine);
+
+            // Finder pattern
+            self::putFinderPattern($frame, 0, 0);
+            self::putFinderPattern($frame, $width - 7, 0);
+            self::putFinderPattern($frame, 0, $width - 7);
+            
+            // Separator
+            $yOffset = $width - 7;
+            
+            for($y=0; $y<7; $y++) {
+                $frame[$y][7] = "\xc0";
+                $frame[$y][$width - 8] = "\xc0";
+                $frame[$yOffset][7] = "\xc0";
+                $yOffset++;
+            }
+            
+            $setPattern = str_repeat("\xc0", 8);
+            
+            QRstr::set($frame, 0, 7, $setPattern);
+            QRstr::set($frame, $width-8, 7, $setPattern);
+            QRstr::set($frame, 0, $width - 8, $setPattern);
+        
+            // Format info
+            $setPattern = str_repeat("\x84", 9);
+            QRstr::set($frame, 0, 8, $setPattern);
+            QRstr::set($frame, $width - 8, 8, $setPattern, 8);
+            
+            $yOffset = $width - 8;
+
+            for($y=0; $y<8; $y++,$yOffset++) {
+                $frame[$y][8] = "\x84";
+                $frame[$yOffset][8] = "\x84";
+            }
+
+            // Timing pattern  
+            
+            for($i=1; $i<$width-15; $i++) {
+                $frame[6][7+$i] = chr(0x90 | ($i & 1));
+                $frame[7+$i][6] = chr(0x90 | ($i & 1));
+            }
+            
+            // Alignment pattern  
+            self::putAlignmentPattern($version, $frame, $width);
+            
+            // Version information 
+            if($version >= 7) {
+                $vinf = self::getVersionPattern($version);
+
+                $v = $vinf;
+                
+                for($x=0; $x<6; $x++) {
+                    for($y=0; $y<3; $y++) {
+                        $frame[($width - 11)+$y][$x] = chr(0x88 | ($v & 1));
+                        $v = $v >> 1;
+                    }
+                }
+
+                $v = $vinf;
+                for($y=0; $y<6; $y++) {
+                    for($x=0; $x<3; $x++) {
+                        $frame[$y][$x+($width - 11)] = chr(0x88 | ($v & 1));
+                        $v = $v >> 1;
+                    }
+                }
+            }
+    
+            // and a little bit...  
+            $frame[$width - 8][8] = "\x81";
+            
+            return $frame;
+        }
+
+        //----------------------------------------------------------------------
+        public static function debug($frame, $binary_mode = false)
+        {
+            if ($binary_mode) {
+            
+                    foreach ($frame as &$frameLine) {
+                        $frameLine = join('<span class="m">&nbsp;&nbsp;</span>', explode('0', $frameLine));
+                        $frameLine = join('&#9608;&#9608;', explode('1', $frameLine));
+                    }
+                    
+                    ?>
+                <style>
+                    .m { background-color: white; }
+                </style>
+                <?php
+                    echo '<pre><tt><br/ ><br/ ><br/ >&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;';
+                    echo join("<br/ >&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;", $frame);
+                    echo '</tt></pre><br/ ><br/ ><br/ ><br/ ><br/ ><br/ >';
+            
+            } else {
+            
+                foreach ($frame as &$frameLine) {
+                    $frameLine = join('<span class="m">&nbsp;</span>',  explode("\xc0", $frameLine));
+                    $frameLine = join('<span class="m">&#9618;</span>', explode("\xc1", $frameLine));
+                    $frameLine = join('<span class="p">&nbsp;</span>',  explode("\xa0", $frameLine));
+                    $frameLine = join('<span class="p">&#9618;</span>', explode("\xa1", $frameLine));
+                    $frameLine = join('<span class="s">&#9671;</span>', explode("\x84", $frameLine)); //format 0
+                    $frameLine = join('<span class="s">&#9670;</span>', explode("\x85", $frameLine)); //format 1
+                    $frameLine = join('<span class="x">&#9762;</span>', explode("\x81", $frameLine)); //special bit
+                    $frameLine = join('<span class="c">&nbsp;</span>',  explode("\x90", $frameLine)); //clock 0
+                    $frameLine = join('<span class="c">&#9719;</span>', explode("\x91", $frameLine)); //clock 1
+                    $frameLine = join('<span class="f">&nbsp;</span>',  explode("\x88", $frameLine)); //version
+                    $frameLine = join('<span class="f">&#9618;</span>', explode("\x89", $frameLine)); //version
+                    $frameLine = join('&#9830;', explode("\x01", $frameLine));
+                    $frameLine = join('&#8901;', explode("\0", $frameLine));
+                }
+                
+                ?>
+                <style>
+                    .p { background-color: yellow; }
+                    .m { background-color: #00FF00; }
+                    .s { background-color: #FF0000; }
+                    .c { background-color: aqua; }
+                    .x { background-color: pink; }
+                    .f { background-color: gold; }
+                </style>
+                <?php
+                echo "<pre><tt>";
+                echo join("<br/ >", $frame);
+                echo "</tt></pre>";
+            
+            }
+        }
+
+        //----------------------------------------------------------------------
+        public static function serial($frame)
+        {
+            return gzcompress(join("\n", $frame), 9);
+        }
+        
+        //----------------------------------------------------------------------
+        public static function unserial($code)
+        {
+            return explode("\n", gzuncompress($code));
+        }
+        
+        //----------------------------------------------------------------------
+        public static function newFrame($version)
+        {
+            if($version < 1 || $version > QRSPEC_VERSION_MAX) 
+                return null;
+
+            if(!isset(self::$frames[$version])) {
+                
+                $fileName = QR_CACHE_DIR.'frame_'.$version.'.dat';
+                
+                if (QR_CACHEABLE) {
+                    if (file_exists($fileName)) {
+                        self::$frames[$version] = self::unserial(file_get_contents($fileName));
+                    } else {
+                        self::$frames[$version] = self::createFrame($version);
+                        file_put_contents($fileName, self::serial(self::$frames[$version]));
+                    }
+                } else {
+                    self::$frames[$version] = self::createFrame($version);
+                }
+            }
+            
+            if(is_null(self::$frames[$version]))
+                return null;
+
+            return self::$frames[$version];
+        }
+
+        //----------------------------------------------------------------------
+        public static function rsBlockNum($spec)     { return $spec[0] + $spec[3]; }
+        public static function rsBlockNum1($spec)    { return $spec[0]; }
+        public static function rsDataCodes1($spec)   { return $spec[1]; }
+        public static function rsEccCodes1($spec)    { return $spec[2]; }
+        public static function rsBlockNum2($spec)    { return $spec[3]; }
+        public static function rsDataCodes2($spec)   { return $spec[4]; }
+        public static function rsEccCodes2($spec)    { return $spec[2]; }
+        public static function rsDataLength($spec)   { return ($spec[0] * $spec[1]) + ($spec[3] * $spec[4]);    }
+        public static function rsEccLength($spec)    { return ($spec[0] + $spec[3]) * $spec[2]; }
+        
+    }
+
+
+
+//---- qrimage.php -----------------------------
+
+
+
+
+/*
+ * PHP QR Code encoder
+ *
+ * Image output of code using GD2
+ *
+ * PHP QR Code is distributed under LGPL 3
+ * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+ 
+    define('QR_IMAGE', true);
+
+    class QRimage {
+    
+        //----------------------------------------------------------------------
+        public static function png($frame, $filename = false, $pixelPerPoint = 4, $outerFrame = 4,$saveandprint=FALSE) 
+        {
+            $image = self::image($frame, $pixelPerPoint, $outerFrame);
+            
+            if ($filename === false) {
+                Header("Content-type: image/png");
+                ImagePng($image);
+            } else {
+                if($saveandprint===TRUE){
+                    ImagePng($image, $filename);
+                    header("Content-type: image/png");
+                    ImagePng($image);
+                }else{
+                    ImagePng($image, $filename);
+                }
+            }
+            
+            ImageDestroy($image);
+        }
+    
+        //----------------------------------------------------------------------
+        public static function jpg($frame, $filename = false, $pixelPerPoint = 8, $outerFrame = 4, $q = 85) 
+        {
+            $image = self::image($frame, $pixelPerPoint, $outerFrame);
+            
+            if ($filename === false) {
+                Header("Content-type: image/jpeg");
+                ImageJpeg($image, null, $q);
+            } else {
+                ImageJpeg($image, $filename, $q);            
+            }
+            
+            ImageDestroy($image);
+        }
+    
+        //----------------------------------------------------------------------
+        private static function image($frame, $pixelPerPoint = 4, $outerFrame = 4) 
+        {
+            $h = count($frame);
+            $w = strlen($frame[0]);
+            
+            $imgW = $w + 2*$outerFrame;
+            $imgH = $h + 2*$outerFrame;
+            
+            $base_image =ImageCreate($imgW, $imgH);
+            
+            $col[0] = ImageColorAllocate($base_image,255,255,255);
+            $col[1] = ImageColorAllocate($base_image,0,0,0);
+
+            imagefill($base_image, 0, 0, $col[0]);
+
+            for($y=0; $y<$h; $y++) {
+                for($x=0; $x<$w; $x++) {
+                    if ($frame[$y][$x] == '1') {
+                        ImageSetPixel($base_image,$x+$outerFrame,$y+$outerFrame,$col[1]); 
+                    }
+                }
+            }
+            
+            $target_image =ImageCreate($imgW * $pixelPerPoint, $imgH * $pixelPerPoint);
+            ImageCopyResized($target_image, $base_image, 0, 0, 0, 0, $imgW * $pixelPerPoint, $imgH * $pixelPerPoint, $imgW, $imgH);
+            ImageDestroy($base_image);
+            
+            return $target_image;
+        }
+    }
+
+
+
+//---- qrinput.php -----------------------------
+
+
+
+
+/*
+ * PHP QR Code encoder
+ *
+ * Input encoding class
+ *
+ * Based on libqrencode C library distributed under LGPL 2.1
+ * Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>
+ *
+ * PHP QR Code is distributed under LGPL 3
+ * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+ 
+    define('STRUCTURE_HEADER_BITS',  20);
+    define('MAX_STRUCTURED_SYMBOLS', 16);
+
+    class QRinputItem {
+    
+        public $mode;
+        public $size;
+        public $data;
+        public $bstream;
+
+        public function __construct($mode, $size, $data, $bstream = null) 
+        {
+            $setData = array_slice($data, 0, $size);
+            
+            if (count($setData) < $size) {
+                $setData = array_merge($setData, array_fill(0,$size-count($setData),0));
+            }
+        
+            if(!QRinput::check($mode, $size, $setData)) {
+                throw new Exception('Error m:'.$mode.',s:'.$size.',d:'.join(',',$setData));
+                return null;
+            }
+            
+            $this->mode = $mode;
+            $this->size = $size;
+            $this->data = $setData;
+            $this->bstream = $bstream;
+        }
+        
+        //----------------------------------------------------------------------
+        public function encodeModeNum($version)
+        {
+            try {
+            
+                $words = (int)($this->size / 3);
+                $bs = new QRbitstream();
+                
+                $val = 0x1;
+                $bs->appendNum(4, $val);
+                $bs->appendNum(QRspec::lengthIndicator(QR_MODE_NUM, $version), $this->size);
+
+                for($i=0; $i<$words; $i++) {
+                    $val  = (ord($this->data[$i*3  ]) - ord('0')) * 100;
+                    $val += (ord($this->data[$i*3+1]) - ord('0')) * 10;
+                    $val += (ord($this->data[$i*3+2]) - ord('0'));
+                    $bs->appendNum(10, $val);
+                }
+
+                if($this->size - $words * 3 == 1) {
+                    $val = ord($this->data[$words*3]) - ord('0');
+                    $bs->appendNum(4, $val);
+                } else if($this->size - $words * 3 == 2) {
+                    $val  = (ord($this->data[$words*3  ]) - ord('0')) * 10;
+                    $val += (ord($this->data[$words*3+1]) - ord('0'));
+                    $bs->appendNum(7, $val);
+                }
+
+                $this->bstream = $bs;
+                return 0;
+                
+            } catch (Exception $e) {
+                return -1;
+            }
+        }
+        
+        //----------------------------------------------------------------------
+        public function encodeModeAn($version)
+        {
+            try {
+                $words = (int)($this->size / 2);
+                $bs = new QRbitstream();
+                
+                $bs->appendNum(4, 0x02);
+                $bs->appendNum(QRspec::lengthIndicator(QR_MODE_AN, $version), $this->size);
+
+                for($i=0; $i<$words; $i++) {
+                    $val  = (int)QRinput::lookAnTable(ord($this->data[$i*2  ])) * 45;
+                    $val += (int)QRinput::lookAnTable(ord($this->data[$i*2+1]));
+
+                    $bs->appendNum(11, $val);
+                }
+
+                if($this->size & 1) {
+                    $val = QRinput::lookAnTable(ord($this->data[$words * 2]));
+                    $bs->appendNum(6, $val);
+                }
+        
+                $this->bstream = $bs;
+                return 0;
+            
+            } catch (Exception $e) {
+                return -1;
+            }
+        }
+        
+        //----------------------------------------------------------------------
+        public function encodeMode8($version)
+        {
+            try {
+                $bs = new QRbitstream();
+
+                $bs->appendNum(4, 0x4);
+                $bs->appendNum(QRspec::lengthIndicator(QR_MODE_8, $version), $this->size);
+
+                for($i=0; $i<$this->size; $i++) {
+                    $bs->appendNum(8, ord($this->data[$i]));
+                }
+
+                $this->bstream = $bs;
+                return 0;
+            
+            } catch (Exception $e) {
+                return -1;
+            }
+        }
+        
+        //----------------------------------------------------------------------
+        public function encodeModeKanji($version)
+        {
+            try {
+
+                $bs = new QRbitrtream();
+                
+                $bs->appendNum(4, 0x8);
+                $bs->appendNum(QRspec::lengthIndicator(QR_MODE_KANJI, $version), (int)($this->size / 2));
+
+                for($i=0; $i<$this->size; $i+=2) {
+                    $val = (ord($this->data[$i]) << 8) | ord($this->data[$i+1]);
+                    if($val <= 0x9ffc) {
+                        $val -= 0x8140;
+                    } else {
+                        $val -= 0xc140;
+                    }
+                    
+                    $h = ($val >> 8) * 0xc0;
+                    $val = ($val & 0xff) + $h;
+
+                    $bs->appendNum(13, $val);
+                }
+
+                $this->bstream = $bs;
+                return 0;
+            
+            } catch (Exception $e) {
+                return -1;
+            }
+        }
+
+        //----------------------------------------------------------------------
+        public function encodeModeStructure()
+        {
+            try {
+                $bs =  new QRbitstream();
+                
+                $bs->appendNum(4, 0x03);
+                $bs->appendNum(4, ord($this->data[1]) - 1);
+                $bs->appendNum(4, ord($this->data[0]) - 1);
+                $bs->appendNum(8, ord($this->data[2]));
+
+                $this->bstream = $bs;
+                return 0;
+            
+            } catch (Exception $e) {
+                return -1;
+            }
+        }
+        
+        //----------------------------------------------------------------------
+        public function estimateBitStreamSizeOfEntry($version)
+        {
+            $bits = 0;
+
+            if($version == 0) 
+                $version = 1;
+
+            switch($this->mode) {
+                case QR_MODE_NUM:        $bits = QRinput::estimateBitsModeNum($this->size);    break;
+                case QR_MODE_AN:        $bits = QRinput::estimateBitsModeAn($this->size);    break;
+                case QR_MODE_8:            $bits = QRinput::estimateBitsMode8($this->size);    break;
+                case QR_MODE_KANJI:        $bits = QRinput::estimateBitsModeKanji($this->size);break;
+                case QR_MODE_STRUCTURE:    return STRUCTURE_HEADER_BITS;            
+                default:
+                    return 0;
+            }
+
+            $l = QRspec::lengthIndicator($this->mode, $version);
+            $m = 1 << $l;
+            $num = (int)(($this->size + $m - 1) / $m);
+
+            $bits += $num * (4 + $l);
+
+            return $bits;
+        }
+        
+        //----------------------------------------------------------------------
+        public function encodeBitStream($version)
+        {
+            try {
+            
+                unset($this->bstream);
+                $words = QRspec::maximumWords($this->mode, $version);
+                
+                if($this->size > $words) {
+                
+                    $st1 = new QRinputItem($this->mode, $words, $this->data);
+                    $st2 = new QRinputItem($this->mode, $this->size - $words, array_slice($this->data, $words));
+
+                    $st1->encodeBitStream($version);
+                    $st2->encodeBitStream($version);
+                    
+                    $this->bstream = new QRbitstream();
+                    $this->bstream->append($st1->bstream);
+                    $this->bstream->append($st2->bstream);
+                    
+                    unset($st1);
+                    unset($st2);
+                    
+                } else {
+                    
+                    $ret = 0;
+                    
+                    switch($this->mode) {
+                        case QR_MODE_NUM:        $ret = $this->encodeModeNum($version);    break;
+                        case QR_MODE_AN:        $ret = $this->encodeModeAn($version);    break;
+                        case QR_MODE_8:            $ret = $this->encodeMode8($version);    break;
+                        case QR_MODE_KANJI:        $ret = $this->encodeModeKanji($version);break;
+                        case QR_MODE_STRUCTURE:    $ret = $this->encodeModeStructure();    break;
+                        
+                        default:
+                            break;
+                    }
+                    
+                    if($ret < 0)
+                        return -1;
+                }
+
+                return $this->bstream->size();
+            
+            } catch (Exception $e) {
+                return -1;
+            }
+        }
+    };
+    
+    //##########################################################################
+
+    class QRinput {
+
+        public $items;
+        
+        private $version;
+        private $level;
+        
+        //----------------------------------------------------------------------
+        public function __construct($version = 0, $level = QR_ECLEVEL_L)
+        {
+            if ($version < 0 || $version > QRSPEC_VERSION_MAX || $level > QR_ECLEVEL_H) {
+                throw new Exception('Invalid version no');
+                return NULL;
+            }
+            
+            $this->version = $version;
+            $this->level = $level;
+        }
+        
+        //----------------------------------------------------------------------
+        public function getVersion()
+        {
+            return $this->version;
+        }
+        
+        //----------------------------------------------------------------------
+        public function setVersion($version)
+        {
+            if($version < 0 || $version > QRSPEC_VERSION_MAX) {
+                throw new Exception('Invalid version no');
+                return -1;
+            }
+
+            $this->version = $version;
+
+            return 0;
+        }
+        
+        //----------------------------------------------------------------------
+        public function getErrorCorrectionLevel()
+        {
+            return $this->level;
+        }
+
+        //----------------------------------------------------------------------
+        public function setErrorCorrectionLevel($level)
+        {
+            if($level > QR_ECLEVEL_H) {
+                throw new Exception('Invalid ECLEVEL');
+                return -1;
+            }
+
+            $this->level = $level;
+
+            return 0;
+        }
+        
+        //----------------------------------------------------------------------
+        public function appendEntry(QRinputItem $entry)
+        {
+            $this->items[] = $entry;
+        }
+        
+        //----------------------------------------------------------------------
+        public function append($mode, $size, $data)
+        {
+            try {
+                $entry = new QRinputItem($mode, $size, $data);
+                $this->items[] = $entry;
+                return 0;
+            } catch (Exception $e) {
+                return -1;
+            }
+        }
+        
+        //----------------------------------------------------------------------
+        
+        public function insertStructuredAppendHeader($size, $index, $parity)
+        {
+            if( $size > MAX_STRUCTURED_SYMBOLS ) {
+                throw new Exception('insertStructuredAppendHeader wrong size');
+            }
+            
+            if( $index <= 0 || $index > MAX_STRUCTURED_SYMBOLS ) {
+                throw new Exception('insertStructuredAppendHeader wrong index');
+            }
+
+            $buf = array($size, $index, $parity);
+            
+            try {
+                $entry = new QRinputItem(QR_MODE_STRUCTURE, 3, buf);
+                array_unshift($this->items, $entry);
+                return 0;
+            } catch (Exception $e) {
+                return -1;
+            }
+        }
+
+        //----------------------------------------------------------------------
+        public function calcParity()
+        {
+            $parity = 0;
+            
+            foreach($this->items as $item) {
+                if($item->mode != QR_MODE_STRUCTURE) {
+                    for($i=$item->size-1; $i>=0; $i--) {
+                        $parity ^= $item->data[$i];
+                    }
+                }
+            }
+
+            return $parity;
+        }
+        
+        //----------------------------------------------------------------------
+        public static function checkModeNum($size, $data)
+        {
+            for($i=0; $i<$size; $i++) {
+                if((ord($data[$i]) < ord('0')) || (ord($data[$i]) > ord('9'))){
+                    return false;
+                }
+            }
+
+            return true;
+        }
+
+        //----------------------------------------------------------------------
+        public static function estimateBitsModeNum($size)
+        {
+            $w = (int)$size / 3;
+            $bits = $w * 10;
+            
+            switch($size - $w * 3) {
+                case 1:
+                    $bits += 4;
+                    break;
+                case 2:
+                    $bits += 7;
+                    break;
+                default:
+                    break;
+            }
+
+            return $bits;
+        }
+        
+        //----------------------------------------------------------------------
+        public static $anTable = array(
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            36, -1, -1, -1, 37, 38, -1, -1, -1, -1, 39, 40, -1, 41, 42, 43,
+             0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 44, -1, -1, -1, -1, -1,
+            -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+            25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
+        );
+        
+        //----------------------------------------------------------------------
+        public static function lookAnTable($c)
+        {
+            return (($c > 127)?-1:self::$anTable[$c]);
+        }
+        
+        //----------------------------------------------------------------------
+        public static function checkModeAn($size, $data)
+        {
+            for($i=0; $i<$size; $i++) {
+                if (self::lookAnTable(ord($data[$i])) == -1) {
+                    return false;
+                }
+            }
+
+            return true;
+        }
+        
+        //----------------------------------------------------------------------
+        public static function estimateBitsModeAn($size)
+        {
+            $w = (int)($size / 2);
+            $bits = $w * 11;
+            
+            if($size & 1) {
+                $bits += 6;
+            }
+
+            return $bits;
+        }
+    
+        //----------------------------------------------------------------------
+        public static function estimateBitsMode8($size)
+        {
+            return $size * 8;
+        }
+        
+        //----------------------------------------------------------------------
+        public function estimateBitsModeKanji($size)
+        {
+            return (int)(($size / 2) * 13);
+        }
+        
+        //----------------------------------------------------------------------
+        public static function checkModeKanji($size, $data)
+        {
+            if($size & 1)
+                return false;
+
+            for($i=0; $i<$size; $i+=2) {
+                $val = (ord($data[$i]) << 8) | ord($data[$i+1]);
+                if( $val < 0x8140 
+                || ($val > 0x9ffc && $val < 0xe040) 
+                || $val > 0xebbf) {
+                    return false;
+                }
+            }
+
+            return true;
+        }
+
+        /***********************************************************************
+         * Validation
+         **********************************************************************/
+
+        public static function check($mode, $size, $data)
+        {
+            if($size <= 0) 
+                return false;
+
+            switch($mode) {
+                case QR_MODE_NUM:       return self::checkModeNum($size, $data);   break;
+                case QR_MODE_AN:        return self::checkModeAn($size, $data);    break;
+                case QR_MODE_KANJI:     return self::checkModeKanji($size, $data); break;
+                case QR_MODE_8:         return true; break;
+                case QR_MODE_STRUCTURE: return true; break;
+                
+                default:
+                    break;
+            }
+
+            return false;
+        }
+        
+        
+        //----------------------------------------------------------------------
+        public function estimateBitStreamSize($version)
+        {
+            $bits = 0;
+
+            foreach($this->items as $item) {
+                $bits += $item->estimateBitStreamSizeOfEntry($version);
+            }
+
+            return $bits;
+        }
+        
+        //----------------------------------------------------------------------
+        public function estimateVersion()
+        {
+            $version = 0;
+            $prev = 0;
+            do {
+                $prev = $version;
+                $bits = $this->estimateBitStreamSize($prev);
+                $version = QRspec::getMinimumVersion((int)(($bits + 7) / 8), $this->level);
+                if ($version < 0) {
+                    return -1;
+                }
+            } while ($version > $prev);
+
+            return $version;
+        }
+        
+        //----------------------------------------------------------------------
+        public static function lengthOfCode($mode, $version, $bits)
+        {
+            $payload = $bits - 4 - QRspec::lengthIndicator($mode, $version);
+            switch($mode) {
+                case QR_MODE_NUM:
+                    $chunks = (int)($payload / 10);
+                    $remain = $payload - $chunks * 10;
+                    $size = $chunks * 3;
+                    if($remain >= 7) {
+                        $size += 2;
+                    } else if($remain >= 4) {
+                        $size += 1;
+                    }
+                    break;
+                case QR_MODE_AN:
+                    $chunks = (int)($payload / 11);
+                    $remain = $payload - $chunks * 11;
+                    $size = $chunks * 2;
+                    if($remain >= 6) 
+                        $size++;
+                    break;
+                case QR_MODE_8:
+                    $size = (int)($payload / 8);
+                    break;
+                case QR_MODE_KANJI:
+                    $size = (int)(($payload / 13) * 2);
+                    break;
+                case QR_MODE_STRUCTURE:
+                    $size = (int)($payload / 8);
+                    break;
+                default:
+                    $size = 0;
+                    break;
+            }
+            
+            $maxsize = QRspec::maximumWords($mode, $version);
+            if($size < 0) $size = 0;
+            if($size > $maxsize) $size = $maxsize;
+
+            return $size;
+        }
+        
+        //----------------------------------------------------------------------
+        public function createBitStream()
+        {
+            $total = 0;
+
+            foreach($this->items as $item) {
+                $bits = $item->encodeBitStream($this->version);
+                
+                if($bits < 0) 
+                    return -1;
+                    
+                $total += $bits;
+            }
+
+            return $total;
+        }
+        
+        //----------------------------------------------------------------------
+        public function convertData()
+        {
+            $ver = $this->estimateVersion();
+            if($ver > $this->getVersion()) {
+                $this->setVersion($ver);
+            }
+
+            for(;;) {
+                $bits = $this->createBitStream();
+                
+                if($bits < 0) 
+                    return -1;
+                    
+                $ver = QRspec::getMinimumVersion((int)(($bits + 7) / 8), $this->level);
+                if($ver < 0) {
+                    throw new Exception('WRONG VERSION');
+                    return -1;
+                } else if($ver > $this->getVersion()) {
+                    $this->setVersion($ver);
+                } else {
+                    break;
+                }
+            }
+
+            return 0;
+        }
+        
+        //----------------------------------------------------------------------
+        public function appendPaddingBit(&$bstream)
+        {
+            $bits = $bstream->size();
+            $maxwords = QRspec::getDataLength($this->version, $this->level);
+            $maxbits = $maxwords * 8;
+
+            if ($maxbits == $bits) {
+                return 0;
+            }
+
+            if ($maxbits - $bits < 5) {
+                return $bstream->appendNum($maxbits - $bits, 0);
+            }
+
+            $bits += 4;
+            $words = (int)(($bits + 7) / 8);
+
+            $padding = new QRbitstream();
+            $ret = $padding->appendNum($words * 8 - $bits + 4, 0);
+            
+            if($ret < 0) 
+                return $ret;
+
+            $padlen = $maxwords - $words;
+            
+            if($padlen > 0) {
+                
+                $padbuf = array();
+                for($i=0; $i<$padlen; $i++) {
+                    $padbuf[$i] = ($i&1)?0x11:0xec;
+                }
+                
+                $ret = $padding->appendBytes($padlen, $padbuf);
+                
+                if($ret < 0)
+                    return $ret;
+                
+            }
+
+            $ret = $bstream->append($padding);
+            
+            return $ret;
+        }
+
+        //----------------------------------------------------------------------
+        public function mergeBitStream()
+        {
+            if($this->convertData() < 0) {
+                return null;
+            }
+
+            $bstream = new QRbitstream();
+            
+            foreach($this->items as $item) {
+                $ret = $bstream->append($item->bstream);
+                if($ret < 0) {
+                    return null;
+                }
+            }
+
+            return $bstream;
+        }
+
+        //----------------------------------------------------------------------
+        public function getBitStream()
+        {
+
+            $bstream = $this->mergeBitStream();
+            
+            if($bstream == null) {
+                return null;
+            }
+            
+            $ret = $this->appendPaddingBit($bstream);
+            if($ret < 0) {
+                return null;
+            }
+
+            return $bstream;
+        }
+        
+        //----------------------------------------------------------------------
+        public function getByteStream()
+        {
+            $bstream = $this->getBitStream();
+            if($bstream == null) {
+                return null;
+            }
+            
+            return $bstream->toByte();
+        }
+    }
+        
+        
+    
+
+
+
+//---- qrbitstream.php -----------------------------
+
+
+
+
+/*
+ * PHP QR Code encoder
+ *
+ * Bitstream class
+ *
+ * Based on libqrencode C library distributed under LGPL 2.1
+ * Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>
+ *
+ * PHP QR Code is distributed under LGPL 3
+ * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+     
+    class QRbitstream {
+    
+        public $data = array();
+        
+        //----------------------------------------------------------------------
+        public function size()
+        {
+            return count($this->data);
+        }
+        
+        //----------------------------------------------------------------------
+        public function allocate($setLength)
+        {
+            $this->data = array_fill(0, $setLength, 0);
+            return 0;
+        }
+    
+        //----------------------------------------------------------------------
+        public static function newFromNum($bits, $num)
+        {
+            $bstream = new QRbitstream();
+            $bstream->allocate($bits);
+            
+            $mask = 1 << ($bits - 1);
+            for($i=0; $i<$bits; $i++) {
+                if($num & $mask) {
+                    $bstream->data[$i] = 1;
+                } else {
+                    $bstream->data[$i] = 0;
+                }
+                $mask = $mask >> 1;
+            }
+
+            return $bstream;
+        }
+        
+        //----------------------------------------------------------------------
+        public static function newFromBytes($size, $data)
+        {
+            $bstream = new QRbitstream();
+            $bstream->allocate($size * 8);
+            $p=0;
+
+            for($i=0; $i<$size; $i++) {
+                $mask = 0x80;
+                for($j=0; $j<8; $j++) {
+                    if($data[$i] & $mask) {
+                        $bstream->data[$p] = 1;
+                    } else {
+                        $bstream->data[$p] = 0;
+                    }
+                    $p++;
+                    $mask = $mask >> 1;
+                }
+            }
+
+            return $bstream;
+        }
+        
+        //----------------------------------------------------------------------
+        public function append(QRbitstream $arg)
+        {
+            if (is_null($arg)) {
+                return -1;
+            }
+            
+            if($arg->size() == 0) {
+                return 0;
+            }
+            
+            if($this->size() == 0) {
+                $this->data = $arg->data;
+                return 0;
+            }
+            
+            $this->data = array_values(array_merge($this->data, $arg->data));
+
+            return 0;
+        }
+        
+        //----------------------------------------------------------------------
+        public function appendNum($bits, $num)
+        {
+            if ($bits == 0) 
+                return 0;
+
+            $b = QRbitstream::newFromNum($bits, $num);
+            
+            if(is_null($b))
+                return -1;
+
+            $ret = $this->append($b);
+            unset($b);
+
+            return $ret;
+        }
+
+        //----------------------------------------------------------------------
+        public function appendBytes($size, $data)
+        {
+            if ($size == 0) 
+                return 0;
+
+            $b = QRbitstream::newFromBytes($size, $data);
+            
+            if(is_null($b))
+                return -1;
+
+            $ret = $this->append($b);
+            unset($b);
+
+            return $ret;
+        }
+        
+        //----------------------------------------------------------------------
+        public function toByte()
+        {
+        
+            $size = $this->size();
+
+            if($size == 0) {
+                return array();
+            }
+            
+            $data = array_fill(0, (int)(($size + 7) / 8), 0);
+            $bytes = (int)($size / 8);
+
+            $p = 0;
+            
+            for($i=0; $i<$bytes; $i++) {
+                $v = 0;
+                for($j=0; $j<8; $j++) {
+                    $v = $v << 1;
+                    $v |= $this->data[$p];
+                    $p++;
+                }
+                $data[$i] = $v;
+            }
+            
+            if($size & 7) {
+                $v = 0;
+                for($j=0; $j<($size & 7); $j++) {
+                    $v = $v << 1;
+                    $v |= $this->data[$p];
+                    $p++;
+                }
+                $data[$bytes] = $v;
+            }
+
+            return $data;
+        }
+
+    }
+
+
+
+
+//---- qrsplit.php -----------------------------
+
+
+
+
+/*
+ * PHP QR Code encoder
+ *
+ * Input splitting classes
+ *
+ * Based on libqrencode C library distributed under LGPL 2.1
+ * Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>
+ *
+ * PHP QR Code is distributed under LGPL 3
+ * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
+ *
+ * The following data / specifications are taken from
+ * "Two dimensional symbol -- QR-code -- Basic Specification" (JIS X0510:2004)
+ *  or
+ * "Automatic identification and data capture techniques -- 
+ *  QR Code 2005 bar code symbology specification" (ISO/IEC 18004:2006)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+    class QRsplit {
+
+        public $dataStr = '';
+        public $input;
+        public $modeHint;
+
+        //----------------------------------------------------------------------
+        public function __construct($dataStr, $input, $modeHint) 
+        {
+            $this->dataStr  = $dataStr;
+            $this->input    = $input;
+            $this->modeHint = $modeHint;
+        }
+        
+        //----------------------------------------------------------------------
+        public static function isdigitat($str, $pos)
+        {    
+            if ($pos >= strlen($str))
+                return false;
+            
+            return ((ord($str[$pos]) >= ord('0'))&&(ord($str[$pos]) <= ord('9')));
+        }
+        
+        //----------------------------------------------------------------------
+        public static function isalnumat($str, $pos)
+        {
+            if ($pos >= strlen($str))
+                return false;
+                
+            return (QRinput::lookAnTable(ord($str[$pos])) >= 0);
+        }
+
+        //----------------------------------------------------------------------
+        public function identifyMode($pos)
+        {
+            if ($pos >= strlen($this->dataStr)) 
+                return QR_MODE_NUL;
+                
+            $c = $this->dataStr[$pos];
+            
+            if(self::isdigitat($this->dataStr, $pos)) {
+                return QR_MODE_NUM;
+            } else if(self::isalnumat($this->dataStr, $pos)) {
+                return QR_MODE_AN;
+            } else if($this->modeHint == QR_MODE_KANJI) {
+            
+                if ($pos+1 < strlen($this->dataStr)) 
+                {
+                    $d = $this->dataStr[$pos+1];
+                    $word = (ord($c) << 8) | ord($d);
+                    if(($word >= 0x8140 && $word <= 0x9ffc) || ($word >= 0xe040 && $word <= 0xebbf)) {
+                        return QR_MODE_KANJI;
+                    }
+                }
+            }
+
+            return QR_MODE_8;
+        } 
+        
+        //----------------------------------------------------------------------
+        public function eatNum()
+        {
+            $ln = QRspec::lengthIndicator(QR_MODE_NUM, $this->input->getVersion());
+
+            $p = 0;
+            while(self::isdigitat($this->dataStr, $p)) {
+                $p++;
+            }
+            
+            $run = $p;
+            $mode = $this->identifyMode($p);
+            
+            if($mode == QR_MODE_8) {
+                $dif = QRinput::estimateBitsModeNum($run) + 4 + $ln
+                     + QRinput::estimateBitsMode8(1)         // + 4 + l8
+                     - QRinput::estimateBitsMode8($run + 1); // - 4 - l8
+                if($dif > 0) {
+                    return $this->eat8();
+                }
+            }
+            if($mode == QR_MODE_AN) {
+                $dif = QRinput::estimateBitsModeNum($run) + 4 + $ln
+                     + QRinput::estimateBitsModeAn(1)        // + 4 + la
+                     - QRinput::estimateBitsModeAn($run + 1);// - 4 - la
+                if($dif > 0) {
+                    return $this->eatAn();
+                }
+            }
+            
+            $ret = $this->input->append(QR_MODE_NUM, $run, str_split($this->dataStr));
+            if($ret < 0)
+                return -1;
+
+            return $run;
+        }
+        
+        //----------------------------------------------------------------------
+        public function eatAn()
+        {
+            $la = QRspec::lengthIndicator(QR_MODE_AN,  $this->input->getVersion());
+            $ln = QRspec::lengthIndicator(QR_MODE_NUM, $this->input->getVersion());
+
+            $p = 0;
+            
+            while(self::isalnumat($this->dataStr, $p)) {
+                if(self::isdigitat($this->dataStr, $p)) {
+                    $q = $p;
+                    while(self::isdigitat($this->dataStr, $q)) {
+                        $q++;
+                    }
+                    
+                    $dif = QRinput::estimateBitsModeAn($p) // + 4 + la
+                         + QRinput::estimateBitsModeNum($q - $p) + 4 + $ln
+                         - QRinput::estimateBitsModeAn($q); // - 4 - la
+                         
+                    if($dif < 0) {
+                        break;
+                    } else {
+                        $p = $q;
+                    }
+                } else {
+                    $p++;
+                }
+            }
+
+            $run = $p;
+
+            if(!self::isalnumat($this->dataStr, $p)) {
+                $dif = QRinput::estimateBitsModeAn($run) + 4 + $la
+                     + QRinput::estimateBitsMode8(1) // + 4 + l8
+                      - QRinput::estimateBitsMode8($run + 1); // - 4 - l8
+                if($dif > 0) {
+                    return $this->eat8();
+                }
+            }
+
+            $ret = $this->input->append(QR_MODE_AN, $run, str_split($this->dataStr));
+            if($ret < 0)
+                return -1;
+
+            return $run;
+        }
+        
+        //----------------------------------------------------------------------
+        public function eatKanji()
+        {
+            $p = 0;
+            
+            while($this->identifyMode($p) == QR_MODE_KANJI) {
+                $p += 2;
+            }
+            
+            $ret = $this->input->append(QR_MODE_KANJI, $p, str_split($this->dataStr));
+            if($ret < 0)
+                return -1;
+
+            return $run;
+        }
+
+        //----------------------------------------------------------------------
+        public function eat8()
+        {
+            $la = QRspec::lengthIndicator(QR_MODE_AN, $this->input->getVersion());
+            $ln = QRspec::lengthIndicator(QR_MODE_NUM, $this->input->getVersion());
+
+            $p = 1;
+            $dataStrLen = strlen($this->dataStr);
+            
+            while($p < $dataStrLen) {
+                
+                $mode = $this->identifyMode($p);
+                if($mode == QR_MODE_KANJI) {
+                    break;
+                }
+                if($mode == QR_MODE_NUM) {
+                    $q = $p;
+                    while(self::isdigitat($this->dataStr, $q)) {
+                        $q++;
+                    }
+                    $dif = QRinput::estimateBitsMode8($p) // + 4 + l8
+                         + QRinput::estimateBitsModeNum($q - $p) + 4 + $ln
+                         - QRinput::estimateBitsMode8($q); // - 4 - l8
+                    if($dif < 0) {
+                        break;
+                    } else {
+                        $p = $q;
+                    }
+                } else if($mode == QR_MODE_AN) {
+                    $q = $p;
+                    while(self::isalnumat($this->dataStr, $q)) {
+                        $q++;
+                    }
+                    $dif = QRinput::estimateBitsMode8($p)  // + 4 + l8
+                         + QRinput::estimateBitsModeAn($q - $p) + 4 + $la
+                         - QRinput::estimateBitsMode8($q); // - 4 - l8
+                    if($dif < 0) {
+                        break;
+                    } else {
+                        $p = $q;
+                    }
+                } else {
+                    $p++;
+                }
+            }
+
+            $run = $p;
+            $ret = $this->input->append(QR_MODE_8, $run, str_split($this->dataStr));
+            
+            if($ret < 0)
+                return -1;
+
+            return $run;
+        }
+
+        //----------------------------------------------------------------------
+        public function splitString()
+        {
+            while (strlen($this->dataStr) > 0)
+            {
+                if($this->dataStr == '')
+                    return 0;
+
+                $mode = $this->identifyMode(0);
+                
+                switch ($mode) {
+                    case QR_MODE_NUM: $length = $this->eatNum(); break;
+                    case QR_MODE_AN:  $length = $this->eatAn(); break;
+                    case QR_MODE_KANJI:
+                        if ($hint == QR_MODE_KANJI)
+                                $length = $this->eatKanji();
+                        else    $length = $this->eat8();
+                        break;
+                    default: $length = $this->eat8(); break;
+                
+                }
+
+                if($length == 0) return 0;
+                if($length < 0)  return -1;
+                
+                $this->dataStr = substr($this->dataStr, $length);
+            }
+        }
+
+        //----------------------------------------------------------------------
+        public function toUpper()
+        {
+            $stringLen = strlen($this->dataStr);
+            $p = 0;
+            
+            while ($p<$stringLen) {
+                $mode = self::identifyMode(substr($this->dataStr, $p), $this->modeHint);
+                if($mode == QR_MODE_KANJI) {
+                    $p += 2;
+                } else {
+                    if (ord($this->dataStr[$p]) >= ord('a') && ord($this->dataStr[$p]) <= ord('z')) {
+                        $this->dataStr[$p] = chr(ord($this->dataStr[$p]) - 32);
+                    }
+                    $p++;
+                }
+            }
+
+            return $this->dataStr;
+        }
+
+        //----------------------------------------------------------------------
+        public static function splitStringToQRinput($string, QRinput $input, $modeHint, $casesensitive = true)
+        {
+            if(is_null($string) || $string == '\0' || $string == '') {
+                throw new Exception('empty string!!!');
+            }
+
+            $split = new QRsplit($string, $input, $modeHint);
+            
+            if(!$casesensitive)
+                $split->toUpper();
+                
+            return $split->splitString();
+        }
+    }
+
+
+
+//---- qrrscode.php -----------------------------
+
+
+
+
+/*
+ * PHP QR Code encoder
+ *
+ * Reed-Solomon error correction support
+ * 
+ * Copyright (C) 2002, 2003, 2004, 2006 Phil Karn, KA9Q
+ * (libfec is released under the GNU Lesser General Public License.)
+ *
+ * Based on libqrencode C library distributed under LGPL 2.1
+ * Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>
+ *
+ * PHP QR Code is distributed under LGPL 3
+ * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+ 
+    class QRrsItem {
+    
+        public $mm;                  // Bits per symbol 
+        public $nn;                  // Symbols per block (= (1<<mm)-1) 
+        public $alpha_to = array();  // log lookup table 
+        public $index_of = array();  // Antilog lookup table 
+        public $genpoly = array();   // Generator polynomial 
+        public $nroots;              // Number of generator roots = number of parity symbols 
+        public $fcr;                 // First consecutive root, index form 
+        public $prim;                // Primitive element, index form 
+        public $iprim;               // prim-th root of 1, index form 
+        public $pad;                 // Padding bytes in shortened block 
+        public $gfpoly;
+    
+        //----------------------------------------------------------------------
+        public function modnn($x)
+        {
+            while ($x >= $this->nn) {
+                $x -= $this->nn;
+                $x = ($x >> $this->mm) + ($x & $this->nn);
+            }
+            
+            return $x;
+        }
+        
+        //----------------------------------------------------------------------
+        public static function init_rs_char($symsize, $gfpoly, $fcr, $prim, $nroots, $pad)
+        {
+            // Common code for intializing a Reed-Solomon control block (char or int symbols)
+            // Copyright 2004 Phil Karn, KA9Q
+            // May be used under the terms of the GNU Lesser General Public License (LGPL)
+
+            $rs = null;
+            
+            // Check parameter ranges
+            if($symsize < 0 || $symsize > 8)                     return $rs;
+            if($fcr < 0 || $fcr >= (1<<$symsize))                return $rs;
+            if($prim <= 0 || $prim >= (1<<$symsize))             return $rs;
+            if($nroots < 0 || $nroots >= (1<<$symsize))          return $rs; // Can't have more roots than symbol values!
+            if($pad < 0 || $pad >= ((1<<$symsize) -1 - $nroots)) return $rs; // Too much padding
+
+            $rs = new QRrsItem();
+            $rs->mm = $symsize;
+            $rs->nn = (1<<$symsize)-1;
+            $rs->pad = $pad;
+
+            $rs->alpha_to = array_fill(0, $rs->nn+1, 0);
+            $rs->index_of = array_fill(0, $rs->nn+1, 0);
+          
+            // PHP style macro replacement ;)
+            $NN =& $rs->nn;
+            $A0 =& $NN;
+            
+            // Generate Galois field lookup tables
+            $rs->index_of[0] = $A0; // log(zero) = -inf
+            $rs->alpha_to[$A0] = 0; // alpha**-inf = 0
+            $sr = 1;
+          
+            for($i=0; $i<$rs->nn; $i++) {
+                $rs->index_of[$sr] = $i;
+                $rs->alpha_to[$i] = $sr;
+                $sr <<= 1;
+                if($sr & (1<<$symsize)) {
+                    $sr ^= $gfpoly;
+                }
+                $sr &= $rs->nn;
+            }
+            
+            if($sr != 1){
+                // field generator polynomial is not primitive!
+                $rs = NULL;
+                return $rs;
+            }
+
+            /* Form RS code generator polynomial from its roots */
+            $rs->genpoly = array_fill(0, $nroots+1, 0);
+        
+            $rs->fcr = $fcr;
+            $rs->prim = $prim;
+            $rs->nroots = $nroots;
+            $rs->gfpoly = $gfpoly;
+
+            /* Find prim-th root of 1, used in decoding */
+            for($iprim=1;($iprim % $prim) != 0;$iprim += $rs->nn)
+            ; // intentional empty-body loop!
+            
+            $rs->iprim = (int)($iprim / $prim);
+            $rs->genpoly[0] = 1;
+            
+            for ($i = 0,$root=$fcr*$prim; $i < $nroots; $i++, $root += $prim) {
+                $rs->genpoly[$i+1] = 1;
+
+                // Multiply rs->genpoly[] by  @**(root + x)
+                for ($j = $i; $j > 0; $j--) {
+                    if ($rs->genpoly[$j] != 0) {
+                        $rs->genpoly[$j] = $rs->genpoly[$j-1] ^ $rs->alpha_to[$rs->modnn($rs->index_of[$rs->genpoly[$j]] + $root)];
+                    } else {
+                        $rs->genpoly[$j] = $rs->genpoly[$j-1];
+                    }
+                }
+                // rs->genpoly[0] can never be zero
+                $rs->genpoly[0] = $rs->alpha_to[$rs->modnn($rs->index_of[$rs->genpoly[0]] + $root)];
+            }
+            
+            // convert rs->genpoly[] to index form for quicker encoding
+            for ($i = 0; $i <= $nroots; $i++)
+                $rs->genpoly[$i] = $rs->index_of[$rs->genpoly[$i]];
+
+            return $rs;
+        }
+        
+        //----------------------------------------------------------------------
+        public function encode_rs_char($data, &$parity)
+        {
+            $MM       =& $this->mm;
+            $NN       =& $this->nn;
+            $ALPHA_TO =& $this->alpha_to;
+            $INDEX_OF =& $this->index_of;
+            $GENPOLY  =& $this->genpoly;
+            $NROOTS   =& $this->nroots;
+            $FCR      =& $this->fcr;
+            $PRIM     =& $this->prim;
+            $IPRIM    =& $this->iprim;
+            $PAD      =& $this->pad;
+            $A0       =& $NN;
+
+            $parity = array_fill(0, $NROOTS, 0);
+
+            for($i=0; $i< ($NN-$NROOTS-$PAD); $i++) {
+                
+                $feedback = $INDEX_OF[$data[$i] ^ $parity[0]];
+                if($feedback != $A0) {      
+                    // feedback term is non-zero
+            
+                    // This line is unnecessary when GENPOLY[NROOTS] is unity, as it must
+                    // always be for the polynomials constructed by init_rs()
+                    $feedback = $this->modnn($NN - $GENPOLY[$NROOTS] + $feedback);
+            
+                    for($j=1;$j<$NROOTS;$j++) {
+                        $parity[$j] ^= $ALPHA_TO[$this->modnn($feedback + $GENPOLY[$NROOTS-$j])];
+                    }
+                }
+                
+                // Shift 
+                array_shift($parity);
+                if($feedback != $A0) {
+                    array_push($parity, $ALPHA_TO[$this->modnn($feedback + $GENPOLY[0])]);
+                } else {
+                    array_push($parity, 0);
+                }
+            }
+        }
+    }
+    
+    //##########################################################################
+    
+    class QRrs {
+    
+        public static $items = array();
+        
+        //----------------------------------------------------------------------
+        public static function init_rs($symsize, $gfpoly, $fcr, $prim, $nroots, $pad)
+        {
+            foreach(self::$items as $rs) {
+                if($rs->pad != $pad)       continue;
+                if($rs->nroots != $nroots) continue;
+                if($rs->mm != $symsize)    continue;
+                if($rs->gfpoly != $gfpoly) continue;
+                if($rs->fcr != $fcr)       continue;
+                if($rs->prim != $prim)     continue;
+
+                return $rs;
+            }
+
+            $rs = QRrsItem::init_rs_char($symsize, $gfpoly, $fcr, $prim, $nroots, $pad);
+            array_unshift(self::$items, $rs);
+
+            return $rs;
+        }
+    }
+
+
+
+//---- qrmask.php -----------------------------
+
+
+
+
+/*
+ * PHP QR Code encoder
+ *
+ * Masking
+ *
+ * Based on libqrencode C library distributed under LGPL 2.1
+ * Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>
+ *
+ * PHP QR Code is distributed under LGPL 3
+ * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+ 
+	define('N1', 3);
+	define('N2', 3);
+	define('N3', 40);
+	define('N4', 10);
+
+	class QRmask {
+	
+		public $runLength = array();
+		
+		//----------------------------------------------------------------------
+		public function __construct() 
+        {
+            $this->runLength = array_fill(0, QRSPEC_WIDTH_MAX + 1, 0);
+        }
+        
+        //----------------------------------------------------------------------
+        public function writeFormatInformation($width, &$frame, $mask, $level)
+        {
+            $blacks = 0;
+            $format =  QRspec::getFormatInfo($mask, $level);
+
+            for($i=0; $i<8; $i++) {
+                if($format & 1) {
+                    $blacks += 2;
+                    $v = 0x85;
+                } else {
+                    $v = 0x84;
+                }
+                
+                $frame[8][$width - 1 - $i] = chr($v);
+                if($i < 6) {
+                    $frame[$i][8] = chr($v);
+                } else {
+                    $frame[$i + 1][8] = chr($v);
+                }
+                $format = $format >> 1;
+            }
+            
+            for($i=0; $i<7; $i++) {
+                if($format & 1) {
+                    $blacks += 2;
+                    $v = 0x85;
+                } else {
+                    $v = 0x84;
+                }
+                
+                $frame[$width - 7 + $i][8] = chr($v);
+                if($i == 0) {
+                    $frame[8][7] = chr($v);
+                } else {
+                    $frame[8][6 - $i] = chr($v);
+                }
+                
+                $format = $format >> 1;
+            }
+
+            return $blacks;
+        }
+        
+        //----------------------------------------------------------------------
+        public function mask0($x, $y) { return ($x+$y)&1;                       }
+        public function mask1($x, $y) { return ($y&1);                          }
+        public function mask2($x, $y) { return ($x%3);                          }
+        public function mask3($x, $y) { return ($x+$y)%3;                       }
+        public function mask4($x, $y) { return (((int)($y/2))+((int)($x/3)))&1; }
+        public function mask5($x, $y) { return (($x*$y)&1)+($x*$y)%3;           }
+        public function mask6($x, $y) { return ((($x*$y)&1)+($x*$y)%3)&1;       }
+        public function mask7($x, $y) { return ((($x*$y)%3)+(($x+$y)&1))&1;     }
+        
+        //----------------------------------------------------------------------
+        private function generateMaskNo($maskNo, $width, $frame)
+        {
+            $bitMask = array_fill(0, $width, array_fill(0, $width, 0));
+            
+            for($y=0; $y<$width; $y++) {
+                for($x=0; $x<$width; $x++) {
+                    if(ord($frame[$y][$x]) & 0x80) {
+                        $bitMask[$y][$x] = 0;
+                    } else {
+                        $maskFunc = call_user_func(array($this, 'mask'.$maskNo), $x, $y);
+                        $bitMask[$y][$x] = ($maskFunc == 0)?1:0;
+                    }
+                    
+                }
+            }
+            
+            return $bitMask;
+        }
+        
+        //----------------------------------------------------------------------
+        public static function serial($bitFrame)
+        {
+            $codeArr = array();
+            
+            foreach ($bitFrame as $line)
+                $codeArr[] = join('', $line);
+                
+            return gzcompress(join("\n", $codeArr), 9);
+        }
+        
+        //----------------------------------------------------------------------
+        public static function unserial($code)
+        {
+            $codeArr = array();
+            
+            $codeLines = explode("\n", gzuncompress($code));
+            foreach ($codeLines as $line)
+                $codeArr[] = str_split($line);
+            
+            return $codeArr;
+        }
+        
+        //----------------------------------------------------------------------
+        public function makeMaskNo($maskNo, $width, $s, &$d, $maskGenOnly = false) 
+        {
+            $b = 0;
+            $bitMask = array();
+            
+            $fileName = QR_CACHE_DIR.'mask_'.$maskNo.DIRECTORY_SEPARATOR.'mask_'.$width.'_'.$maskNo.'.dat';
+
+            if (QR_CACHEABLE) {
+                if (file_exists($fileName)) {
+                    $bitMask = self::unserial(file_get_contents($fileName));
+                } else {
+                    $bitMask = $this->generateMaskNo($maskNo, $width, $s, $d);
+                    if (!file_exists(QR_CACHE_DIR.'mask_'.$maskNo))
+                        mkdir(QR_CACHE_DIR.'mask_'.$maskNo);
+                    file_put_contents($fileName, self::serial($bitMask));
+                }
+            } else {
+                $bitMask = $this->generateMaskNo($maskNo, $width, $s, $d);
+            }
+
+            if ($maskGenOnly)
+                return;
+                
+            $d = $s;
+
+            for($y=0; $y<$width; $y++) {
+                for($x=0; $x<$width; $x++) {
+                    if($bitMask[$y][$x] == 1) {
+                        $d[$y][$x] = chr(ord($s[$y][$x]) ^ (int)$bitMask[$y][$x]);
+                    }
+                    $b += (int)(ord($d[$y][$x]) & 1);
+                }
+            }
+
+            return $b;
+        }
+        
+        //----------------------------------------------------------------------
+        public function makeMask($width, $frame, $maskNo, $level)
+        {
+            $masked = array_fill(0, $width, str_repeat("\0", $width));
+            $this->makeMaskNo($maskNo, $width, $frame, $masked);
+            $this->writeFormatInformation($width, $masked, $maskNo, $level);
+       
+            return $masked;
+        }
+        
+        //----------------------------------------------------------------------
+        public function calcN1N3($length)
+        {
+            $demerit = 0;
+
+            for($i=0; $i<$length; $i++) {
+                
+                if($this->runLength[$i] >= 5) {
+                    $demerit += (N1 + ($this->runLength[$i] - 5));
+                }
+                if($i & 1) {
+                    if(($i >= 3) && ($i < ($length-2)) && ($this->runLength[$i] % 3 == 0)) {
+                        $fact = (int)($this->runLength[$i] / 3);
+                        if(($this->runLength[$i-2] == $fact) &&
+                           ($this->runLength[$i-1] == $fact) &&
+                           ($this->runLength[$i+1] == $fact) &&
+                           ($this->runLength[$i+2] == $fact)) {
+                            if(($this->runLength[$i-3] < 0) || ($this->runLength[$i-3] >= (4 * $fact))) {
+                                $demerit += N3;
+                            } else if((($i+3) >= $length) || ($this->runLength[$i+3] >= (4 * $fact))) {
+                                $demerit += N3;
+                            }
+                        }
+                    }
+                }
+            }
+            return $demerit;
+        }
+        
+        //----------------------------------------------------------------------
+        public function evaluateSymbol($width, $frame)
+        {
+            $head = 0;
+            $demerit = 0;
+
+            for($y=0; $y<$width; $y++) {
+                $head = 0;
+                $this->runLength[0] = 1;
+                
+                $frameY = $frame[$y];
+                
+                if ($y>0)
+                    $frameYM = $frame[$y-1];
+                
+                for($x=0; $x<$width; $x++) {
+                    if(($x > 0) && ($y > 0)) {
+                        $b22 = ord($frameY[$x]) & ord($frameY[$x-1]) & ord($frameYM[$x]) & ord($frameYM[$x-1]);
+                        $w22 = ord($frameY[$x]) | ord($frameY[$x-1]) | ord($frameYM[$x]) | ord($frameYM[$x-1]);
+                        
+                        if(($b22 | ($w22 ^ 1))&1) {                                                                     
+                            $demerit += N2;
+                        }
+                    }
+                    if(($x == 0) && (ord($frameY[$x]) & 1)) {
+                        $this->runLength[0] = -1;
+                        $head = 1;
+                        $this->runLength[$head] = 1;
+                    } else if($x > 0) {
+                        if((ord($frameY[$x]) ^ ord($frameY[$x-1])) & 1) {
+                            $head++;
+                            $this->runLength[$head] = 1;
+                        } else {
+                            $this->runLength[$head]++;
+                        }
+                    }
+                }
+    
+                $demerit += $this->calcN1N3($head+1);
+            }
+
+            for($x=0; $x<$width; $x++) {
+                $head = 0;
+                $this->runLength[0] = 1;
+                
+                for($y=0; $y<$width; $y++) {
+                    if($y == 0 && (ord($frame[$y][$x]) & 1)) {
+                        $this->runLength[0] = -1;
+                        $head = 1;
+                        $this->runLength[$head] = 1;
+                    } else if($y > 0) {
+                        if((ord($frame[$y][$x]) ^ ord($frame[$y-1][$x])) & 1) {
+                            $head++;
+                            $this->runLength[$head] = 1;
+                        } else {
+                            $this->runLength[$head]++;
+                        }
+                    }
+                }
+            
+                $demerit += $this->calcN1N3($head+1);
+            }
+
+            return $demerit;
+        }
+        
+        
+        //----------------------------------------------------------------------
+        public function mask($width, $frame, $level)
+        {
+            $minDemerit = PHP_INT_MAX;
+            $bestMaskNum = 0;
+            $bestMask = array();
+            
+            $checked_masks = array(0,1,2,3,4,5,6,7);
+            
+            if (QR_FIND_FROM_RANDOM !== false) {
+            
+                $howManuOut = 8-(QR_FIND_FROM_RANDOM % 9);
+                for ($i = 0; $i <  $howManuOut; $i++) {
+                    $remPos = rand (0, count($checked_masks)-1);
+                    unset($checked_masks[$remPos]);
+                    $checked_masks = array_values($checked_masks);
+                }
+            
+            }
+            
+            $bestMask = $frame;
+             
+            foreach($checked_masks as $i) {
+                $mask = array_fill(0, $width, str_repeat("\0", $width));
+
+                $demerit = 0;
+                $blacks = 0;
+                $blacks  = $this->makeMaskNo($i, $width, $frame, $mask);
+                $blacks += $this->writeFormatInformation($width, $mask, $i, $level);
+                $blacks  = (int)(100 * $blacks / ($width * $width));
+                $demerit = (int)((int)(abs($blacks - 50) / 5) * N4);
+                $demerit += $this->evaluateSymbol($width, $mask);
+                
+                if($demerit < $minDemerit) {
+                    $minDemerit = $demerit;
+                    $bestMask = $mask;
+                    $bestMaskNum = $i;
+                }
+            }
+            
+            return $bestMask;
+        }
+        
+        //----------------------------------------------------------------------
+    }
+
+
+
+
+//---- qrencode.php -----------------------------
+
+
+
+
+/*
+ * PHP QR Code encoder
+ *
+ * Main encoder classes.
+ *
+ * Based on libqrencode C library distributed under LGPL 2.1
+ * Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>
+ *
+ * PHP QR Code is distributed under LGPL 3
+ * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+ 
+    class QRrsblock {
+        public $dataLength;
+        public $data = array();
+        public $eccLength;
+        public $ecc = array();
+        
+        public function __construct($dl, $data, $el, &$ecc, QRrsItem $rs)
+        {
+            $rs->encode_rs_char($data, $ecc);
+        
+            $this->dataLength = $dl;
+            $this->data = $data;
+            $this->eccLength = $el;
+            $this->ecc = $ecc;
+        }
+    };
+    
+    //##########################################################################
+
+    class QRrawcode {
+        public $version;
+        public $datacode = array();
+        public $ecccode = array();
+        public $blocks;
+        public $rsblocks = array(); //of RSblock
+        public $count;
+        public $dataLength;
+        public $eccLength;
+        public $b1;
+        
+        //----------------------------------------------------------------------
+        public function __construct(QRinput $input)
+        {
+            $spec = array(0,0,0,0,0);
+            
+            $this->datacode = $input->getByteStream();
+            if(is_null($this->datacode)) {
+                throw new Exception('null imput string');
+            }
+
+            QRspec::getEccSpec($input->getVersion(), $input->getErrorCorrectionLevel(), $spec);
+
+            $this->version = $input->getVersion();
+            $this->b1 = QRspec::rsBlockNum1($spec);
+            $this->dataLength = QRspec::rsDataLength($spec);
+            $this->eccLength = QRspec::rsEccLength($spec);
+            $this->ecccode = array_fill(0, $this->eccLength, 0);
+            $this->blocks = QRspec::rsBlockNum($spec);
+            
+            $ret = $this->init($spec);
+            if($ret < 0) {
+                throw new Exception('block alloc error');
+                return null;
+            }
+
+            $this->count = 0;
+        }
+        
+        //----------------------------------------------------------------------
+        public function init(array $spec)
+        {
+            $dl = QRspec::rsDataCodes1($spec);
+            $el = QRspec::rsEccCodes1($spec);
+            $rs = QRrs::init_rs(8, 0x11d, 0, 1, $el, 255 - $dl - $el);
+            
+
+            $blockNo = 0;
+            $dataPos = 0;
+            $eccPos = 0;
+            for($i=0; $i<QRspec::rsBlockNum1($spec); $i++) {
+                $ecc = array_slice($this->ecccode,$eccPos);
+                $this->rsblocks[$blockNo] = new QRrsblock($dl, array_slice($this->datacode, $dataPos), $el,  $ecc, $rs);
+                $this->ecccode = array_merge(array_slice($this->ecccode,0, $eccPos), $ecc);
+                
+                $dataPos += $dl;
+                $eccPos += $el;
+                $blockNo++;
+            }
+
+            if(QRspec::rsBlockNum2($spec) == 0)
+                return 0;
+
+            $dl = QRspec::rsDataCodes2($spec);
+            $el = QRspec::rsEccCodes2($spec);
+            $rs = QRrs::init_rs(8, 0x11d, 0, 1, $el, 255 - $dl - $el);
+            
+            if($rs == NULL) return -1;
+            
+            for($i=0; $i<QRspec::rsBlockNum2($spec); $i++) {
+                $ecc = array_slice($this->ecccode,$eccPos);
+                $this->rsblocks[$blockNo] = new QRrsblock($dl, array_slice($this->datacode, $dataPos), $el, $ecc, $rs);
+                $this->ecccode = array_merge(array_slice($this->ecccode,0, $eccPos), $ecc);
+                
+                $dataPos += $dl;
+                $eccPos += $el;
+                $blockNo++;
+            }
+
+            return 0;
+        }
+        
+        //----------------------------------------------------------------------
+        public function getCode()
+        {
+            $ret;
+
+            if($this->count < $this->dataLength) {
+                $row = $this->count % $this->blocks;
+                $col = $this->count / $this->blocks;
+                if($col >= $this->rsblocks[0]->dataLength) {
+                    $row += $this->b1;
+                }
+                $ret = $this->rsblocks[$row]->data[$col];
+            } else if($this->count < $this->dataLength + $this->eccLength) {
+                $row = ($this->count - $this->dataLength) % $this->blocks;
+                $col = ($this->count - $this->dataLength) / $this->blocks;
+                $ret = $this->rsblocks[$row]->ecc[$col];
+            } else {
+                return 0;
+            }
+            $this->count++;
+            
+            return $ret;
+        }
+    }
+
+    //##########################################################################
+    
+    class QRcode {
+    
+        public $version;
+        public $width;
+        public $data; 
+        
+        //----------------------------------------------------------------------
+        public function encodeMask(QRinput $input, $mask)
+        {
+            if($input->getVersion() < 0 || $input->getVersion() > QRSPEC_VERSION_MAX) {
+                throw new Exception('wrong version');
+            }
+            if($input->getErrorCorrectionLevel() > QR_ECLEVEL_H) {
+                throw new Exception('wrong level');
+            }
+
+            $raw = new QRrawcode($input);
+            
+            QRtools::markTime('after_raw');
+            
+            $version = $raw->version;
+            $width = QRspec::getWidth($version);
+            $frame = QRspec::newFrame($version);
+            
+            $filler = new FrameFiller($width, $frame);
+            if(is_null($filler)) {
+                return NULL;
+            }
+
+            // inteleaved data and ecc codes
+            for($i=0; $i<$raw->dataLength + $raw->eccLength; $i++) {
+                $code = $raw->getCode();
+                $bit = 0x80;
+                for($j=0; $j<8; $j++) {
+                    $addr = $filler->next();
+                    $filler->setFrameAt($addr, 0x02 | (($bit & $code) != 0));
+                    $bit = $bit >> 1;
+                }
+            }
+            
+            QRtools::markTime('after_filler');
+            
+            unset($raw);
+            
+            // remainder bits
+            $j = QRspec::getRemainder($version);
+            for($i=0; $i<$j; $i++) {
+                $addr = $filler->next();
+                $filler->setFrameAt($addr, 0x02);
+            }
+            
+            $frame = $filler->frame;
+            unset($filler);
+            
+            
+            // masking
+            $maskObj = new QRmask();
+            if($mask < 0) {
+            
+                if (QR_FIND_BEST_MASK) {
+                    $masked = $maskObj->mask($width, $frame, $input->getErrorCorrectionLevel());
+                } else {
+                    $masked = $maskObj->makeMask($width, $frame, (intval(QR_DEFAULT_MASK) % 8), $input->getErrorCorrectionLevel());
+                }
+            } else {
+                $masked = $maskObj->makeMask($width, $frame, $mask, $input->getErrorCorrectionLevel());
+            }
+            
+            if($masked == NULL) {
+                return NULL;
+            }
+            
+            QRtools::markTime('after_mask');
+            
+            $this->version = $version;
+            $this->width = $width;
+            $this->data = $masked;
+            
+            return $this;
+        }
+    
+        //----------------------------------------------------------------------
+        public function encodeInput(QRinput $input)
+        {
+            return $this->encodeMask($input, -1);
+        }
+        
+        //----------------------------------------------------------------------
+        public function encodeString8bit($string, $version, $level)
+        {
+            if(string == NULL) {
+                throw new Exception('empty string!');
+                return NULL;
+            }
+
+            $input = new QRinput($version, $level);
+            if($input == NULL) return NULL;
+
+            $ret = $input->append($input, QR_MODE_8, strlen($string), str_split($string));
+            if($ret < 0) {
+                unset($input);
+                return NULL;
+            }
+            return $this->encodeInput($input);
+        }
+
+        //----------------------------------------------------------------------
+        public function encodeString($string, $version, $level, $hint, $casesensitive)
+        {
+
+            if($hint != QR_MODE_8 && $hint != QR_MODE_KANJI) {
+                throw new Exception('bad hint');
+                return NULL;
+            }
+
+            $input = new QRinput($version, $level);
+            if($input == NULL) return NULL;
+
+            $ret = QRsplit::splitStringToQRinput($string, $input, $hint, $casesensitive);
+            if($ret < 0) {
+                return NULL;
+            }
+
+            return $this->encodeInput($input);
+        }
+        
+        //----------------------------------------------------------------------
+        public static function png($text, $outfile = false, $level = QR_ECLEVEL_L, $size = 3, $margin = 4, $saveandprint=false) 
+        {
+            $enc = QRencode::factory($level, $size, $margin);
+            return $enc->encodePNG($text, $outfile, $saveandprint=false);
+        }
+
+        //----------------------------------------------------------------------
+        public static function text($text, $outfile = false, $level = QR_ECLEVEL_L, $size = 3, $margin = 4) 
+        {
+            $enc = QRencode::factory($level, $size, $margin);
+            return $enc->encode($text, $outfile);
+        }
+
+        //----------------------------------------------------------------------
+        public static function raw($text, $outfile = false, $level = QR_ECLEVEL_L, $size = 3, $margin = 4) 
+        {
+            $enc = QRencode::factory($level, $size, $margin);
+            return $enc->encodeRAW($text, $outfile);
+        }
+    }
+    
+    //##########################################################################
+    
+    class FrameFiller {
+    
+        public $width;
+        public $frame;
+        public $x;
+        public $y;
+        public $dir;
+        public $bit;
+        
+        //----------------------------------------------------------------------
+        public function __construct($width, &$frame)
+        {
+            $this->width = $width;
+            $this->frame = $frame;
+            $this->x = $width - 1;
+            $this->y = $width - 1;
+            $this->dir = -1;
+            $this->bit = -1;
+        }
+        
+        //----------------------------------------------------------------------
+        public function setFrameAt($at, $val)
+        {
+            $this->frame[$at['y']][$at['x']] = chr($val);
+        }
+        
+        //----------------------------------------------------------------------
+        public function getFrameAt($at)
+        {
+            return ord($this->frame[$at['y']][$at['x']]);
+        }
+        
+        //----------------------------------------------------------------------
+        public function next()
+        {
+            do {
+            
+                if($this->bit == -1) {
+                    $this->bit = 0;
+                    return array('x'=>$this->x, 'y'=>$this->y);
+                }
+
+                $x = $this->x;
+                $y = $this->y;
+                $w = $this->width;
+
+                if($this->bit == 0) {
+                    $x--;
+                    $this->bit++;
+                } else {
+                    $x++;
+                    $y += $this->dir;
+                    $this->bit--;
+                }
+
+                if($this->dir < 0) {
+                    if($y < 0) {
+                        $y = 0;
+                        $x -= 2;
+                        $this->dir = 1;
+                        if($x == 6) {
+                            $x--;
+                            $y = 9;
+                        }
+                    }
+                } else {
+                    if($y == $w) {
+                        $y = $w - 1;
+                        $x -= 2;
+                        $this->dir = -1;
+                        if($x == 6) {
+                            $x--;
+                            $y -= 8;
+                        }
+                    }
+                }
+                if($x < 0 || $y < 0) return null;
+
+                $this->x = $x;
+                $this->y = $y;
+
+            } while(ord($this->frame[$y][$x]) & 0x80);
+                        
+            return array('x'=>$x, 'y'=>$y);
+        }
+        
+    } ;
+    
+    //##########################################################################    
+    
+    class QRencode {
+    
+        public $casesensitive = true;
+        public $eightbit = false;
+        
+        public $version = 0;
+        public $size = 3;
+        public $margin = 4;
+        
+        public $structured = 0; // not supported yet
+        
+        public $level = QR_ECLEVEL_L;
+        public $hint = QR_MODE_8;
+        
+        //----------------------------------------------------------------------
+        public static function factory($level = QR_ECLEVEL_L, $size = 3, $margin = 4)
+        {
+            $enc = new QRencode();
+            $enc->size = $size;
+            $enc->margin = $margin;
+            
+            switch ($level.'') {
+                case '0':
+                case '1':
+                case '2':
+                case '3':
+                        $enc->level = $level;
+                    break;
+                case 'l':
+                case 'L':
+                        $enc->level = QR_ECLEVEL_L;
+                    break;
+                case 'm':
+                case 'M':
+                        $enc->level = QR_ECLEVEL_M;
+                    break;
+                case 'q':
+                case 'Q':
+                        $enc->level = QR_ECLEVEL_Q;
+                    break;
+                case 'h':
+                case 'H':
+                        $enc->level = QR_ECLEVEL_H;
+                    break;
+            }
+            
+            return $enc;
+        }
+        
+        //----------------------------------------------------------------------
+        public function encodeRAW($intext, $outfile = false) 
+        {
+            $code = new QRcode();
+
+            if($this->eightbit) {
+                $code->encodeString8bit($intext, $this->version, $this->level);
+            } else {
+                $code->encodeString($intext, $this->version, $this->level, $this->hint, $this->casesensitive);
+            }
+            
+            return $code->data;
+        }
+
+        //----------------------------------------------------------------------
+        public function encode($intext, $outfile = false) 
+        {
+            $code = new QRcode();
+
+            if($this->eightbit) {
+                $code->encodeString8bit($intext, $this->version, $this->level);
+            } else {
+                $code->encodeString($intext, $this->version, $this->level, $this->hint, $this->casesensitive);
+            }
+            
+            QRtools::markTime('after_encode');
+            
+            if ($outfile!== false) {
+                file_put_contents($outfile, join("\n", QRtools::binarize($code->data)));
+            } else {
+                return QRtools::binarize($code->data);
+            }
+        }
+        
+        //----------------------------------------------------------------------
+        public function encodePNG($intext, $outfile = false,$saveandprint=false) 
+        {
+            try {
+            
+                ob_start();
+                $tab = $this->encode($intext);
+                $err = ob_get_contents();
+                ob_end_clean();
+                
+                if ($err != '')
+                    QRtools::log($outfile, $err);
+                
+                $maxSize = (int)(QR_PNG_MAXIMUM_SIZE / (count($tab)+2*$this->margin));
+                
+                QRimage::png($tab, $outfile, min(max(1, $this->size), $maxSize), $this->margin,$saveandprint);
+            
+            } catch (Exception $e) {
+            
+                QRtools::log($outfile, $e->getMessage());
+            
+            }
+        }
+    }
+
+

+ 6 - 0
sdk/wechat.php

@@ -0,0 +1,6 @@
+<?php
+
+Dever::apply('sdk/wechat/WxPay.Api', 'pay');
+Dever::apply('sdk/wechat/WxPay.JsApiPay', 'pay');
+Dever::apply('sdk/wechat/WxPay.Config', 'pay');
+Dever::apply('sdk/wechat/WxPay.Notify', 'pay');

+ 609 - 0
sdk/wechat/WxPay.Api.php

@@ -0,0 +1,609 @@
+<?php
+require_once "WxPay.Exception.php";
+require_once "WxPay.Data.php";
+
+/**
+ * 
+ * 接口访问类,包含所有微信支付API列表的封装,类中方法为static方法,
+ * 每个接口有默认超时时间(除提交被扫支付为10s,上报超时时间为1s外,其他均为6s)
+ * @author widyhu
+ *
+ */
+class WxPayApi
+{
+	/**
+	 * 
+	 * 统一下单,WxPayUnifiedOrder中out_trade_no、body、total_fee、trade_type必填
+	 * appid、mchid、spbill_create_ip、nonce_str不需要填入
+	 * @param WxPayConfig $config  配置对象
+	 * @param WxPayUnifiedOrder $inputObj
+	 * @param int $timeOut
+	 * @throws WxPayException
+	 * @return 成功时返回,其他抛异常
+	 */
+	public static function unifiedOrder($config, $inputObj, $timeOut = 6)
+	{
+		$url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
+		//检测必填参数
+		if(!$inputObj->IsOut_trade_noSet()) {
+			throw new WxPayException("缺少统一支付接口必填参数out_trade_no!");
+		}else if(!$inputObj->IsBodySet()){
+			throw new WxPayException("缺少统一支付接口必填参数body!");
+		}else if(!$inputObj->IsTotal_feeSet()) {
+			throw new WxPayException("缺少统一支付接口必填参数total_fee!");
+		}else if(!$inputObj->IsTrade_typeSet()) {
+			throw new WxPayException("缺少统一支付接口必填参数trade_type!");
+		}
+		
+		//关联参数
+		if($inputObj->GetTrade_type() == "JSAPI" && !$inputObj->IsOpenidSet()){
+			throw new WxPayException("统一支付接口中,缺少必填参数openid!trade_type为JSAPI时,openid为必填参数!");
+		}
+		if($inputObj->GetTrade_type() == "NATIVE" && !$inputObj->IsProduct_idSet()){
+			throw new WxPayException("统一支付接口中,缺少必填参数product_id!trade_type为JSAPI时,product_id为必填参数!");
+		}
+		
+		//异步通知url未设置,则使用配置文件中的url
+		if(!$inputObj->IsNotify_urlSet() && $config->GetNotifyUrl() != ""){
+			$inputObj->SetNotify_url($config->GetNotifyUrl());//异步通知url
+		}
+		
+		$inputObj->SetAppid($config->GetAppId());//公众账号ID
+		$inputObj->SetMch_id($config->GetMerchantId());//商户号
+		$inputObj->SetSpbill_create_ip($_SERVER['REMOTE_ADDR']);//终端ip	   	    
+		$inputObj->SetNonce_str(self::getNonceStr());//随机字符串
+		
+		//签名
+		$inputObj->SetSign($config);
+		$xml = $inputObj->ToXml();
+		
+		$startTimeStamp = self::getMillisecond();//请求开始时间
+		$response = self::postXmlCurl($config, $xml, $url, false, $timeOut);
+		$result = WxPayResults::Init($config, $response);
+		self::reportCostTime($config, $url, $startTimeStamp, $result);//上报请求花费时间
+		
+		return $result;
+	}
+	
+	/**
+	 * 
+	 * 查询订单,WxPayOrderQuery中out_trade_no、transaction_id至少填一个
+	 * appid、mchid、spbill_create_ip、nonce_str不需要填入
+	 * @param WxPayConfig $config  配置对象
+	 * @param WxPayOrderQuery $inputObj
+	 * @param int $timeOut
+	 * @throws WxPayException
+	 * @return 成功时返回,其他抛异常
+	 */
+	public static function orderQuery($config, $inputObj, $timeOut = 6)
+	{
+		$url = "https://api.mch.weixin.qq.com/pay/orderquery";
+		//检测必填参数
+		if(!$inputObj->IsOut_trade_noSet() && !$inputObj->IsTransaction_idSet()) {
+			throw new WxPayException("订单查询接口中,out_trade_no、transaction_id至少填一个!");
+		}
+		$inputObj->SetAppid($config->GetAppId());//公众账号ID
+		$inputObj->SetMch_id($config->GetMerchantId());//商户号
+		$inputObj->SetNonce_str(self::getNonceStr());//随机字符串
+		
+		$inputObj->SetSign($config);//签名
+		$xml = $inputObj->ToXml();
+		
+		$startTimeStamp = self::getMillisecond();//请求开始时间
+		$response = self::postXmlCurl($config, $xml, $url, false, $timeOut);
+		$result = WxPayResults::Init($config, $response);
+		self::reportCostTime($config, $url, $startTimeStamp, $result);//上报请求花费时间
+		
+		return $result;
+	}
+	
+	/**
+	 * 
+	 * 关闭订单,WxPayCloseOrder中out_trade_no必填
+	 * appid、mchid、spbill_create_ip、nonce_str不需要填入
+	 * @param WxPayConfig $config  配置对象
+	 * @param WxPayCloseOrder $inputObj
+	 * @param int $timeOut
+	 * @throws WxPayException
+	 * @return 成功时返回,其他抛异常
+	 */
+	public static function closeOrder($config, $inputObj, $timeOut = 6)
+	{
+		$url = "https://api.mch.weixin.qq.com/pay/closeorder";
+		//检测必填参数
+		if(!$inputObj->IsOut_trade_noSet()) {
+			throw new WxPayException("订单查询接口中,out_trade_no必填!");
+		}
+		$inputObj->SetAppid($config->GetAppId());//公众账号ID
+		$inputObj->SetMch_id($config->GetMerchantId());//商户号
+		$inputObj->SetNonce_str(self::getNonceStr());//随机字符串
+		
+		$inputObj->SetSign($config);//签名
+		$xml = $inputObj->ToXml();
+		
+		$startTimeStamp = self::getMillisecond();//请求开始时间
+		$response = self::postXmlCurl($config, $xml, $url, false, $timeOut);
+		$result = WxPayResults::Init($config, $response);
+		self::reportCostTime($config, $url, $startTimeStamp, $result);//上报请求花费时间
+		
+		return $result;
+	}
+
+	/**
+	 * 
+	 * 申请退款,WxPayRefund中out_trade_no、transaction_id至少填一个且
+	 * out_refund_no、total_fee、refund_fee、op_user_id为必填参数
+	 * appid、mchid、spbill_create_ip、nonce_str不需要填入
+	 * @param WxPayConfig $config  配置对象
+	 * @param WxPayRefund $inputObj
+	 * @param int $timeOut
+	 * @throws WxPayException
+	 * @return 成功时返回,其他抛异常
+	 */
+	public static function refund($config, $inputObj, $timeOut = 6)
+	{
+		$url = "https://api.mch.weixin.qq.com/secapi/pay/refund";
+		//检测必填参数
+		if(!$inputObj->IsOut_trade_noSet() && !$inputObj->IsTransaction_idSet()) {
+			throw new WxPayException("退款申请接口中,out_trade_no、transaction_id至少填一个!");
+		}else if(!$inputObj->IsOut_refund_noSet()){
+			throw new WxPayException("退款申请接口中,缺少必填参数out_refund_no!");
+		}else if(!$inputObj->IsTotal_feeSet()){
+			throw new WxPayException("退款申请接口中,缺少必填参数total_fee!");
+		}else if(!$inputObj->IsRefund_feeSet()){
+			throw new WxPayException("退款申请接口中,缺少必填参数refund_fee!");
+		}else if(!$inputObj->IsOp_user_idSet()){
+			throw new WxPayException("退款申请接口中,缺少必填参数op_user_id!");
+		}
+		$inputObj->SetAppid($config->GetAppId());//公众账号ID
+		$inputObj->SetMch_id($config->GetMerchantId());//商户号
+		$inputObj->SetNonce_str(self::getNonceStr());//随机字符串
+		
+		$inputObj->SetSign($config);//签名
+		$xml = $inputObj->ToXml();
+		$startTimeStamp = self::getMillisecond();//请求开始时间
+		$response = self::postXmlCurl($config, $xml, $url, true, $timeOut);
+		$result = WxPayResults::Init($config, $response);
+		self::reportCostTime($config, $url, $startTimeStamp, $result);//上报请求花费时间
+		
+		return $result;
+	}
+	
+	/**
+	 * 
+	 * 查询退款
+	 * 提交退款申请后,通过调用该接口查询退款状态。退款有一定延时,
+	 * 用零钱支付的退款20分钟内到账,银行卡支付的退款3个工作日后重新查询退款状态。
+	 * WxPayRefundQuery中out_refund_no、out_trade_no、transaction_id、refund_id四个参数必填一个
+	 * appid、mchid、spbill_create_ip、nonce_str不需要填入
+	 * @param WxPayConfig $config  配置对象
+	 * @param WxPayRefundQuery $inputObj
+	 * @param int $timeOut
+	 * @throws WxPayException
+	 * @return 成功时返回,其他抛异常
+	 */
+	public static function refundQuery($config, $inputObj, $timeOut = 6)
+	{
+		$url = "https://api.mch.weixin.qq.com/pay/refundquery";
+		//检测必填参数
+		if(!$inputObj->IsOut_refund_noSet() &&
+			!$inputObj->IsOut_trade_noSet() &&
+			!$inputObj->IsTransaction_idSet() &&
+			!$inputObj->IsRefund_idSet()) {
+			throw new WxPayException("退款查询接口中,out_refund_no、out_trade_no、transaction_id、refund_id四个参数必填一个!");
+		}
+		$inputObj->SetAppid($config->GetAppId());//公众账号ID
+		$inputObj->SetMch_id($config->GetMerchantId());//商户号
+		$inputObj->SetNonce_str(self::getNonceStr());//随机字符串
+		
+		$inputObj->SetSign($config);//签名
+		$xml = $inputObj->ToXml();
+		
+		$startTimeStamp = self::getMillisecond();//请求开始时间
+		$response = self::postXmlCurl($config, $xml, $url, false, $timeOut);
+		$result = WxPayResults::Init($config, $response);
+		self::reportCostTime($config, $url, $startTimeStamp, $result);//上报请求花费时间
+		
+		return $result;
+	}
+	
+	/**
+	 * 下载对账单,WxPayDownloadBill中bill_date为必填参数
+	 * appid、mchid、spbill_create_ip、nonce_str不需要填入
+	 * @param WxPayConfig $config  配置对象
+	 * @param WxPayDownloadBill $inputObj
+	 * @param int $timeOut
+	 * @throws WxPayException
+	 * @return 成功时返回,其他抛异常
+	 */
+	public static function downloadBill($config, $inputObj, $timeOut = 6)
+	{
+		$url = "https://api.mch.weixin.qq.com/pay/downloadbill";
+		//检测必填参数
+		if(!$inputObj->IsBill_dateSet()) {
+			throw new WxPayException("对账单接口中,缺少必填参数bill_date!");
+		}
+		$inputObj->SetAppid($config->GetAppId());//公众账号ID
+		$inputObj->SetMch_id($config->GetMerchantId());//商户号
+		$inputObj->SetNonce_str(self::getNonceStr());//随机字符串
+		
+		$inputObj->SetSign($config);//签名
+		$xml = $inputObj->ToXml();
+		
+		$response = self::postXmlCurl($config, $xml, $url, false, $timeOut);
+		if(substr($response, 0 , 5) == "<xml>"){
+			return "";
+		}
+		return $response;
+	}
+	
+	/**
+	 * 提交被扫支付API
+	 * 收银员使用扫码设备读取微信用户刷卡授权码以后,二维码或条码信息传送至商户收银台,
+	 * 由商户收银台或者商户后台调用该接口发起支付。
+	 * WxPayWxPayMicroPay中body、out_trade_no、total_fee、auth_code参数必填
+	 * appid、mchid、spbill_create_ip、nonce_str不需要填入
+	 * @param WxPayConfig $config  配置对象
+	 * @param WxPayWxPayMicroPay $inputObj
+	 * @param int $timeOut
+	 */
+	public static function micropay($config, $inputObj, $timeOut = 10)
+	{
+		$url = "https://api.mch.weixin.qq.com/pay/micropay";
+		//检测必填参数
+		if(!$inputObj->IsBodySet()) {
+			throw new WxPayException("提交被扫支付API接口中,缺少必填参数body!");
+		} else if(!$inputObj->IsOut_trade_noSet()) {
+			throw new WxPayException("提交被扫支付API接口中,缺少必填参数out_trade_no!");
+		} else if(!$inputObj->IsTotal_feeSet()) {
+			throw new WxPayException("提交被扫支付API接口中,缺少必填参数total_fee!");
+		} else if(!$inputObj->IsAuth_codeSet()) {
+			throw new WxPayException("提交被扫支付API接口中,缺少必填参数auth_code!");
+		}
+		
+		$inputObj->SetSpbill_create_ip($_SERVER['REMOTE_ADDR']);//终端ip
+		$inputObj->SetAppid($config->GetAppId());//公众账号ID
+		$inputObj->SetMch_id($config->GetMerchantId());//商户号
+		$inputObj->SetNonce_str(self::getNonceStr());//随机字符串
+		
+		$inputObj->SetSign($config);//签名
+		$xml = $inputObj->ToXml();
+		
+		$startTimeStamp = self::getMillisecond();//请求开始时间
+		$response = self::postXmlCurl($config, $xml, $url, false, $timeOut);
+		$result = WxPayResults::Init($config, $response);
+		self::reportCostTime($config, $url, $startTimeStamp, $result);//上报请求花费时间
+		
+		return $result;
+	}
+	
+	/**
+	 * 
+	 * 撤销订单API接口,WxPayReverse中参数out_trade_no和transaction_id必须填写一个
+	 * appid、mchid、spbill_create_ip、nonce_str不需要填入
+	 * @param WxPayConfig $config  配置对象
+	 * @param WxPayReverse $inputObj
+	 * @param int $timeOut
+	 * @throws WxPayException
+	 */
+	public static function reverse($config, $inputObj, $timeOut = 6)
+	{
+		$url = "https://api.mch.weixin.qq.com/secapi/pay/reverse";
+		//检测必填参数
+		if(!$inputObj->IsOut_trade_noSet() && !$inputObj->IsTransaction_idSet()) {
+			throw new WxPayException("撤销订单API接口中,参数out_trade_no和transaction_id必须填写一个!");
+		}
+		
+		$inputObj->SetAppid($config->GetAppId());//公众账号ID
+		$inputObj->SetMch_id($config->GetMerchantId());//商户号
+		$inputObj->SetNonce_str(self::getNonceStr());//随机字符串
+		
+		$inputObj->SetSign($config);//签名
+		$xml = $inputObj->ToXml();
+		
+		$startTimeStamp = self::getMillisecond();//请求开始时间
+		$response = self::postXmlCurl($config, $xml, $url, true, $timeOut);
+		$result = WxPayResults::Init($config, $response);
+		self::reportCostTime($config, $url, $startTimeStamp, $result);//上报请求花费时间
+		
+		return $result;
+	}
+	
+	/**
+	 * 
+	 * 测速上报,该方法内部封装在report中,使用时请注意异常流程
+	 * WxPayReport中interface_url、return_code、result_code、user_ip、execute_time_必填
+	 * appid、mchid、spbill_create_ip、nonce_str不需要填入
+	 * @param WxPayConfig $config  配置对象
+	 * @param WxPayReport $inputObj
+	 * @param int $timeOut
+	 * @throws WxPayException
+	 * @return 成功时返回,其他抛异常
+	 */
+	public static function report($config, $inputObj, $timeOut = 1)
+	{
+		$url = "https://api.mch.weixin.qq.com/payitil/report";
+		//检测必填参数
+		if(!$inputObj->IsInterface_urlSet()) {
+			throw new WxPayException("接口URL,缺少必填参数interface_url!");
+		} if(!$inputObj->IsReturn_codeSet()) {
+			throw new WxPayException("返回状态码,缺少必填参数return_code!");
+		} if(!$inputObj->IsResult_codeSet()) {
+			throw new WxPayException("业务结果,缺少必填参数result_code!");
+		} if(!$inputObj->IsUser_ipSet()) {
+			throw new WxPayException("访问接口IP,缺少必填参数user_ip!");
+		} if(!$inputObj->IsExecute_time_Set()) {
+			throw new WxPayException("接口耗时,缺少必填参数execute_time_!");
+		}
+		$inputObj->SetAppid($config->GetAppId());//公众账号ID
+		$inputObj->SetMch_id($config->GetMerchantId());//商户号
+		$inputObj->SetUser_ip($_SERVER['REMOTE_ADDR']);//终端ip
+		$inputObj->SetTime(date("YmdHis"));//商户上报时间	 
+		$inputObj->SetNonce_str(self::getNonceStr());//随机字符串
+		
+		$inputObj->SetSign($config);//签名
+		$xml = $inputObj->ToXml();
+		
+		$startTimeStamp = self::getMillisecond();//请求开始时间
+		$response = self::postXmlCurl($config, $xml, $url, false, $timeOut);
+		return $response;
+	}
+	
+	/**
+	 * 
+	 * 生成二维码规则,模式一生成支付二维码
+	 * appid、mchid、spbill_create_ip、nonce_str不需要填入
+	 * @param WxPayConfig $config  配置对象
+	 * @param WxPayBizPayUrl $inputObj
+	 * @param int $timeOut
+	 * @throws WxPayException
+	 * @return 成功时返回,其他抛异常
+	 */
+	public static function bizpayurl($config, $inputObj, $timeOut = 6)
+	{
+		if(!$inputObj->IsProduct_idSet()){
+			throw new WxPayException("生成二维码,缺少必填参数product_id!");
+		}
+
+		$inputObj->SetAppid($config->GetAppId());//公众账号ID
+		$inputObj->SetMch_id($config->GetMerchantId());//商户号
+		$inputObj->SetTime_stamp(time());//时间戳	 
+		$inputObj->SetNonce_str(self::getNonceStr());//随机字符串
+		
+		$inputObj->SetSign($config);//签名
+		
+		return $inputObj->GetValues();
+	}
+	
+	/**
+	 * 
+	 * 转换短链接
+	 * 该接口主要用于扫码原生支付模式一中的二维码链接转成短链接(weixin://wxpay/s/XXXXXX),
+	 * 减小二维码数据量,提升扫描速度和精确度。
+	 * appid、mchid、spbill_create_ip、nonce_str不需要填入
+	 * @param WxPayConfig $config  配置对象
+	 * @param WxPayShortUrl $inputObj
+	 * @param int $timeOut
+	 * @throws WxPayException
+	 * @return 成功时返回,其他抛异常
+	 */
+	public static function shorturl($config, $inputObj, $timeOut = 6)
+	{
+		$url = "https://api.mch.weixin.qq.com/tools/shorturl";
+		//检测必填参数
+		if(!$inputObj->IsLong_urlSet()) {
+			throw new WxPayException("需要转换的URL,签名用原串,传输需URL encode!");
+		}
+		$inputObj->SetAppid($config->GetAppId());//公众账号ID
+		$inputObj->SetMch_id($config->GetMerchantId());//商户号
+		$inputObj->SetNonce_str(self::getNonceStr());//随机字符串
+		
+		$inputObj->SetSign($config);//签名
+		$xml = $inputObj->ToXml();
+		
+		$startTimeStamp = self::getMillisecond();//请求开始时间
+		$response = self::postXmlCurl($config, $xml, $url, false, $timeOut);
+		$result = WxPayResults::Init($config, $response);
+		self::reportCostTime($config, $url, $startTimeStamp, $result);//上报请求花费时间
+		
+		return $result;
+	}
+	
+ 	/**
+ 	 * 
+ 	 * 支付结果通用通知
+ 	 * @param function $callback
+ 	 * 直接回调函数使用方法: notify(you_function);
+ 	 * 回调类成员函数方法:notify(array($this, you_function));
+ 	 * $callback  原型为:function function_name($data){}
+ 	 */
+	public static function notify($config, $callback, &$msg)
+	{
+		if (!isset($GLOBALS['HTTP_RAW_POST_DATA'])) {
+			# 如果没有数据,直接返回失败
+			return false;
+		}
+
+		//如果返回成功则验证签名
+		try {
+			//获取通知的数据
+			$xml = $GLOBALS['HTTP_RAW_POST_DATA'];
+			$result = WxPayNotifyResults::Init($config, $xml);
+		} catch (WxPayException $e){
+			$msg = $e->errorMessage();
+			return false;
+		}
+		
+		return call_user_func($callback, $result);
+	}
+	
+	/**
+	 * 
+	 * 产生随机字符串,不长于32位
+	 * @param int $length
+	 * @return 产生的随机字符串
+	 */
+	public static function getNonceStr($length = 32) 
+	{
+		$chars = "abcdefghijklmnopqrstuvwxyz0123456789";  
+		$str ="";
+		for ( $i = 0; $i < $length; $i++ )  {  
+			$str .= substr($chars, mt_rand(0, strlen($chars)-1), 1);  
+		} 
+		return $str;
+	}
+	
+	/**
+	 * 直接输出xml
+	 * @param string $xml
+	 */
+	public static function replyNotify($xml)
+	{
+		echo $xml;
+	}
+	
+	/**
+	 * 
+	 * 上报数据, 上报的时候将屏蔽所有异常流程
+	 * @param WxPayConfig $config  配置对象
+	 * @param string $usrl
+	 * @param int $startTimeStamp
+	 * @param array $data
+	 */
+	private static function reportCostTime($config, $url, $startTimeStamp, $data)
+	{
+		//如果不需要上报数据
+		$reportLevenl = $config->GetReportLevenl();
+		if($reportLevenl == 0){
+			return;
+		} 
+		//如果仅失败上报
+		if($reportLevenl == 1 &&
+			 array_key_exists("return_code", $data) &&
+			 $data["return_code"] == "SUCCESS" &&
+			 array_key_exists("result_code", $data) &&
+			 $data["result_code"] == "SUCCESS")
+		 {
+		 	return;
+		 }
+		 
+		//上报逻辑
+		$endTimeStamp = self::getMillisecond();
+		$objInput = new WxPayReport();
+		$objInput->SetInterface_url($url);
+		$objInput->SetExecute_time_($endTimeStamp - $startTimeStamp);
+		//返回状态码
+		if(array_key_exists("return_code", $data)){
+			$objInput->SetReturn_code($data["return_code"]);
+		}
+		//返回信息
+		if(array_key_exists("return_msg", $data)){
+			$objInput->SetReturn_msg($data["return_msg"]);
+		}
+		//业务结果
+		if(array_key_exists("result_code", $data)){
+			$objInput->SetResult_code($data["result_code"]);
+		}
+		//错误代码
+		if(array_key_exists("err_code", $data)){
+			$objInput->SetErr_code($data["err_code"]);
+		}
+		//错误代码描述
+		if(array_key_exists("err_code_des", $data)){
+			$objInput->SetErr_code_des($data["err_code_des"]);
+		}
+		//商户订单号
+		if(array_key_exists("out_trade_no", $data)){
+			$objInput->SetOut_trade_no($data["out_trade_no"]);
+		}
+		//设备号
+		if(array_key_exists("device_info", $data)){
+			$objInput->SetDevice_info($data["device_info"]);
+		}
+		
+		try{
+			self::report($config, $objInput);
+		} catch (WxPayException $e){
+			//不做任何处理
+		}
+	}
+
+	/**
+	 * 以post方式提交xml到对应的接口url
+	 * 
+	 * @param WxPayConfig $config  配置对象
+	 * @param string $xml  需要post的xml数据
+	 * @param string $url  url
+	 * @param bool $useCert 是否需要证书,默认不需要
+	 * @param int $second   url执行超时时间,默认30s
+	 * @throws WxPayException
+	 */
+	private static function postXmlCurl($config, $xml, $url, $useCert = false, $second = 30)
+	{		
+		$ch = curl_init();
+		$curlVersion = curl_version();
+		$ua = "WXPaySDK/3.0.9 (".PHP_OS.") PHP/".PHP_VERSION." CURL/".$curlVersion['version']." "
+		.$config->GetMerchantId();
+
+		//设置超时
+		curl_setopt($ch, CURLOPT_TIMEOUT, $second);
+
+		$proxyHost = "0.0.0.0";
+		$proxyPort = 0;
+		$config->GetProxy($proxyHost, $proxyPort);
+		//如果有配置代理这里就设置代理
+		if($proxyHost != "0.0.0.0" && $proxyPort != 0){
+			curl_setopt($ch,CURLOPT_PROXY, $proxyHost);
+			curl_setopt($ch,CURLOPT_PROXYPORT, $proxyPort);
+		}
+		curl_setopt($ch,CURLOPT_URL, $url);
+		curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,TRUE);
+		curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,2);//严格校验
+		curl_setopt($ch,CURLOPT_USERAGENT, $ua); 
+		//设置header
+		curl_setopt($ch, CURLOPT_HEADER, FALSE);
+		//要求结果为字符串且输出到屏幕上
+		curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
+	
+		if($useCert == true){
+			//设置证书
+			//使用证书:cert 与 key 分别属于两个.pem文件
+			//证书文件请放入服务器的非web目录下
+			$sslCertPath = "";
+			$sslKeyPath = "";
+			$config->GetSSLCertPath($sslCertPath, $sslKeyPath);
+			curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM');
+			curl_setopt($ch,CURLOPT_SSLCERT, $sslCertPath);
+			curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM');
+			curl_setopt($ch,CURLOPT_SSLKEY, $sslKeyPath);
+		}
+		//post提交方式
+		curl_setopt($ch, CURLOPT_POST, TRUE);
+		curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
+		//运行curl
+		$data = curl_exec($ch);
+		//返回结果
+		if($data){
+			curl_close($ch);
+			return $data;
+		} else { 
+			$error = curl_errno($ch);
+			curl_close($ch);
+			throw new WxPayException("curl出错,错误码:$error");
+		}
+	}
+	
+	/**
+	 * 获取毫秒级别的时间戳
+	 */
+	private static function getMillisecond()
+	{
+		//获取毫秒的时间戳
+		$time = explode ( " ", microtime () );
+		$time = $time[1] . ($time[0] * 1000);
+		$time2 = explode( ".", $time );
+		$time = $time2[0];
+		return $time;
+	}
+}
+

+ 63 - 0
sdk/wechat/WxPay.Config.php

@@ -0,0 +1,63 @@
+<?php
+
+class WxPayConfig
+{
+	public function set($appid, $appsecret, $merchantid, $notify, $key, $ssl, $type, $timeout = 600)
+	{
+		$this->appid = $appid;
+		$this->appsecret = $appsecret;
+		$this->merchantid = $merchantid;
+		$this->notify = $notify;
+		$this->key = $key;
+		$this->ssl = $ssl;
+		$this->type = $type;
+		$this->timeout = $timeout;
+		return $this;
+	}
+	public function GetAppId()
+	{
+		return $this->appid;
+	}
+	public function GetMerchantId()
+	{
+		return $this->merchantid;
+	}
+	public function GetNotifyUrl()
+	{
+		return $this->notify;
+	}
+	public function GetSignType()
+	{
+		return "HMAC-SHA256";
+	}
+	public function GetProxy(&$proxyHost, &$proxyPort)
+	{
+		$proxyHost = "0.0.0.0";
+		$proxyPort = 0;
+	}
+	public function GetReportLevenl()
+	{
+		return 1;
+	}
+	public function GetKey()
+	{
+		return $this->key;
+	}
+	public function GetAppSecret()
+	{
+		return $this->appsecret;
+	}
+	public function GetSSLCertPath(&$sslCertPath, &$sslKeyPath)
+	{
+		$sslCertPath = $this->ssl['cert'];
+		$sslKeyPath = $this->ssl['key'];
+	}
+	public function GetTimeOut()
+	{
+		return $this->timeout;
+	}
+	public function GetType()
+	{
+		return $this->type;
+	}
+}

+ 3093 - 0
sdk/wechat/WxPay.Data.php

@@ -0,0 +1,3093 @@
+<?php
+/**
+* 2015-06-29 修复签名问题
+**/
+require_once "WxPay.Exception.php";
+
+/**
+ * 
+ * 数据对象基础类,该类中定义数据类最基本的行为,包括:
+ * 计算/设置/获取签名、输出xml格式的参数、从xml读取数据对象等
+ * @author widyhu
+ *
+ */
+class WxPayDataBase
+{
+	protected $values = array();
+
+	/**
+	* 设置签名,详见签名生成算法类型
+	* @param string $value 
+	**/
+	public function SetSignType($sign_type)
+	{
+		$this->values['sign_type'] = $sign_type;
+		return $sign_type;
+	}
+
+	/**
+	* 设置签名,详见签名生成算法
+	* @param string $value 
+	**/
+	public function SetSign($config)
+	{
+		$sign = $this->MakeSign($config);
+		$this->values['sign'] = $sign;
+		return $sign;
+	}
+	
+	/**
+	* 获取签名,详见签名生成算法的值
+	* @return 值
+	**/
+	public function GetSign()
+	{
+		return $this->values['sign'];
+	}
+	
+	/**
+	* 判断签名,详见签名生成算法是否存在
+	* @return true 或 false
+	**/
+	public function IsSignSet()
+	{
+		return array_key_exists('sign', $this->values);
+	}
+
+	/**
+	 * 输出xml字符
+	 * @throws WxPayException
+	**/
+	public function ToXml()
+	{
+		if(!is_array($this->values) || count($this->values) <= 0)
+		{
+    		throw new WxPayException("数组数据异常!");
+    	}
+    	
+    	$xml = "<xml>";
+    	foreach ($this->values as $key=>$val)
+    	{
+    		if (is_numeric($val)){
+    			$xml.="<".$key.">".$val."</".$key.">";
+    		}else{
+    			$xml.="<".$key."><![CDATA[".$val."]]></".$key.">";
+    		}
+        }
+        $xml.="</xml>";
+        return $xml; 
+	}
+
+    /**
+     * 将xml转为array
+     * @param string $xml
+     * @throws WxPayException
+     */
+	public function FromXml($xml)
+	{	
+		if(!$xml){
+			throw new WxPayException("xml数据异常!");
+		}
+        //将XML转为array
+        //禁止引用外部xml实体
+        libxml_disable_entity_loader(true);
+        $this->values = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
+		return $this->values;
+	}
+	
+	/**
+	 * 格式化参数格式化成url参数
+	 */
+	public function ToUrlParams()
+	{
+		$buff = "";
+		foreach ($this->values as $k => $v)
+		{
+			if($k != "sign" && $v != "" && !is_array($v)){
+				$buff .= $k . "=" . $v . "&";
+			}
+		}
+		
+		$buff = trim($buff, "&");
+		return $buff;
+	}
+	
+	/**
+	 * 生成签名
+	 * @param WxPayConfig $config  配置对象
+	 * @param bool $needSignType  是否需要补signtype
+	 * @return 签名,本函数不覆盖sign成员变量,如要设置签名需要调用SetSign方法赋值
+	 */
+	public function MakeSign($config, $needSignType = true)
+	{
+		if($needSignType) {
+			$this->SetSignType($config->GetSignType());
+		}
+		//签名步骤一:按字典序排序参数
+		ksort($this->values);
+		$string = $this->ToUrlParams();
+		//签名步骤二:在string后加入KEY
+		$string = $string . "&key=".$config->GetKey();
+		//签名步骤三:MD5加密或者HMAC-SHA256
+		if($config->GetSignType() == "MD5"){
+			$string = md5($string);
+		} else if($config->GetSignType() == "HMAC-SHA256") {
+			$string = hash_hmac("sha256",$string ,$config->GetKey());
+		} else {
+			throw new WxPayException("签名类型不支持!");
+		}
+		
+		//签名步骤四:所有字符转为大写
+		$result = strtoupper($string);
+		return $result;
+	}
+	
+	/**
+	 * 获取设置的值
+	 */
+	public function GetValues()
+	{
+		return $this->values;
+	}
+}
+
+/**
+ *
+ * 只使用md5算法进行签名, 不管配置的是什么签名方式,都只支持md5签名方式
+ *
+**/
+class WxPayDataBaseSignMd5 extends WxPayDataBase
+{
+	/**
+	 * 生成签名 - 重写该方法
+	 * @param WxPayConfig $config  配置对象
+	 * @param bool $needSignType  是否需要补signtype
+	 * @return 签名,本函数不覆盖sign成员变量,如要设置签名需要调用SetSign方法赋值
+	 */
+	public function MakeSign($config, $needSignType = false)
+	{
+		if($needSignType) {
+			$this->SetSignType($config->GetSignType());
+		}
+		//签名步骤一:按字典序排序参数
+		ksort($this->values);
+		$string = $this->ToUrlParams();
+		//签名步骤二:在string后加入KEY
+		$string = $string . "&key=".$config->GetKey();
+		//签名步骤三:MD5加密
+		$string = md5($string);
+		//签名步骤四:所有字符转为大写
+		$result = strtoupper($string);
+		return $result;
+	}
+}
+
+/**
+ * 
+ * 接口调用结果类
+ * @author widyhu
+ *
+ */
+class WxPayResults extends WxPayDataBase
+{
+	/**
+	 * 生成签名 - 重写该方法
+	 * @param WxPayConfig $config  配置对象
+	 * @param bool $needSignType  是否需要补signtype
+	 * @return 签名,本函数不覆盖sign成员变量,如要设置签名需要调用SetSign方法赋值
+	 */
+	public function MakeSign($config, $needSignType = false)
+	{
+		//签名步骤一:按字典序排序参数
+		ksort($this->values);
+		$string = $this->ToUrlParams();
+		//签名步骤二:在string后加入KEY
+		$string = $string . "&key=".$config->GetKey();
+		//签名步骤三:MD5加密或者HMAC-SHA256
+		if(strlen($this->GetSign()) <= 32){
+			//如果签名小于等于32个,则使用md5验证
+			$string = md5($string);
+		} else {
+			//是用sha256校验
+			$string = hash_hmac("sha256",$string ,$config->GetKey());
+		}
+		//签名步骤四:所有字符转为大写
+		$result = strtoupper($string);
+		return $result;
+	}
+
+	/**
+	 * @param WxPayConfig $config  配置对象
+	 * 检测签名
+	 */
+	public function CheckSign($config)
+	{
+		if(!$this->IsSignSet()){
+			throw new WxPayException("签名错误!");
+		}
+		
+		$sign = $this->MakeSign($config, false);
+		if($this->GetSign() == $sign){
+			//签名正确
+			return true;
+		}
+		throw new WxPayException("签名错误!");
+	}
+	
+	/**
+	 * 
+	 * 使用数组初始化
+	 * @param array $array
+	 */
+	public function FromArray($array)
+	{
+		$this->values = $array;
+	}
+	
+	/**
+	 * 
+	 * 使用数组初始化对象
+	 * @param array $array
+	 * @param 是否检测签名 $noCheckSign
+	 */
+	public static function InitFromArray($config, $array, $noCheckSign = false)
+	{
+		$obj = new self();
+		$obj->FromArray($array);
+		if($noCheckSign == false){
+			$obj->CheckSign($config);
+		}
+        return $obj;
+	}
+	
+	/**
+	 * 
+	 * 设置参数
+	 * @param string $key
+	 * @param string $value
+	 */
+	public function SetData($key, $value)
+	{
+		$this->values[$key] = $value;
+	}
+	
+    /**
+     * 将xml转为array
+     * @param WxPayConfig $config  配置对象
+     * @param string $xml
+     * @throws WxPayException
+     */
+	public static function Init($config, $xml)
+	{	
+		$obj = new self();
+		$obj->FromXml($xml);
+		//失败则直接返回失败
+		if($obj->values['return_code'] != 'SUCCESS') {
+			foreach ($obj->values as $key => $value) {
+				#除了return_code和return_msg之外其他的参数存在,则报错
+				if($key != "return_code" && $key != "return_msg"){
+					throw new WxPayException("输入数据存在异常!");
+					return false;
+				}
+			}
+			return $obj->GetValues();
+		}
+		$obj->CheckSign($config);
+        return $obj->GetValues();
+	}
+}
+
+/**
+ *
+ * 回调回包数据基类
+ *
+ **/
+class WxPayNotifyResults extends WxPayResults
+{
+	/**
+     * 将xml转为array
+     * @param WxPayConfig $config
+     * @param string $xml
+     * @return WxPayNotifyResults
+     * @throws WxPayException
+     */
+	public static function Init($config, $xml)
+	{	
+		$obj = new self();
+		$obj->FromXml($xml);
+		//失败则直接返回失败
+		$obj->CheckSign($config);
+        return $obj;
+	}
+}
+
+/**
+ * 
+ * 回调基础类
+ * @author widyhu
+ *
+ */
+class WxPayNotifyReply extends  WxPayDataBaseSignMd5
+{
+	/**
+	 * 
+	 * 设置错误码 FAIL 或者 SUCCESS
+	 * @param string
+	 */
+	public function SetReturn_code($return_code)
+	{
+		$this->values['return_code'] = $return_code;
+	}
+	
+	/**
+	 * 
+	 * 获取错误码 FAIL 或者 SUCCESS
+	 * @return string $return_code
+	 */
+	public function GetReturn_code()
+	{
+		return $this->values['return_code'];
+	}
+
+	/**
+	 * 
+	 * 设置错误信息
+	 * @param string $return_code
+	 */
+	public function SetReturn_msg($return_msg)
+	{
+		$this->values['return_msg'] = $return_msg;
+	}
+	
+	/**
+	 * 
+	 * 获取错误信息
+	 * @return string
+	 */
+	public function GetReturn_msg()
+	{
+		return $this->values['return_msg'];
+	}
+	
+	/**
+	 * 
+	 * 设置返回参数
+	 * @param string $key
+	 * @param string $value
+	 */
+	public function SetData($key, $value)
+	{
+		$this->values[$key] = $value;
+	}
+}
+
+/**
+ * 
+ * 统一下单输入对象
+ * @author widyhu
+ *
+ */
+class WxPayUnifiedOrder extends WxPayDataBase
+{	
+	/**
+	* 设置微信分配的公众账号ID
+	* @param string $value 
+	**/
+	public function SetAppid($value)
+	{
+		$this->values['appid'] = $value;
+	}
+	/**
+	* 获取微信分配的公众账号ID的值
+	* @return 值
+	**/
+	public function GetAppid()
+	{
+		return $this->values['appid'];
+	}
+	/**
+	* 判断微信分配的公众账号ID是否存在
+	* @return true 或 false
+	**/
+	public function IsAppidSet()
+	{
+		return array_key_exists('appid', $this->values);
+	}
+
+
+	/**
+	* 设置微信支付分配的商户号
+	* @param string $value 
+	**/
+	public function SetMch_id($value)
+	{
+		$this->values['mch_id'] = $value;
+	}
+	/**
+	* 获取微信支付分配的商户号的值
+	* @return 值
+	**/
+	public function GetMch_id()
+	{
+		return $this->values['mch_id'];
+	}
+	/**
+	* 判断微信支付分配的商户号是否存在
+	* @return true 或 false
+	**/
+	public function IsMch_idSet()
+	{
+		return array_key_exists('mch_id', $this->values);
+	}
+
+
+	/**
+	* 设置微信支付分配的终端设备号,商户自定义
+	* @param string $value 
+	**/
+	public function SetDevice_info($value)
+	{
+		$this->values['device_info'] = $value;
+	}
+	/**
+	* 获取微信支付分配的终端设备号,商户自定义的值
+	* @return 值
+	**/
+	public function GetDevice_info()
+	{
+		return $this->values['device_info'];
+	}
+	/**
+	* 判断微信支付分配的终端设备号,商户自定义是否存在
+	* @return true 或 false
+	**/
+	public function IsDevice_infoSet()
+	{
+		return array_key_exists('device_info', $this->values);
+	}
+
+
+	/**
+	* 设置随机字符串,不长于32位。推荐随机数生成算法
+	* @param string $value 
+	**/
+	public function SetNonce_str($value)
+	{
+		$this->values['nonce_str'] = $value;
+	}
+	/**
+	* 获取随机字符串,不长于32位。推荐随机数生成算法的值
+	* @return 值
+	**/
+	public function GetNonce_str()
+	{
+		return $this->values['nonce_str'];
+	}
+	/**
+	* 判断随机字符串,不长于32位。推荐随机数生成算法是否存在
+	* @return true 或 false
+	**/
+	public function IsNonce_strSet()
+	{
+		return array_key_exists('nonce_str', $this->values);
+	}
+
+	/**
+	* 设置商品或支付单简要描述
+	* @param string $value 
+	**/
+	public function SetBody($value)
+	{
+		$this->values['body'] = $value;
+	}
+	/**
+	* 获取商品或支付单简要描述的值
+	* @return 值
+	**/
+	public function GetBody()
+	{
+		return $this->values['body'];
+	}
+	/**
+	* 判断商品或支付单简要描述是否存在
+	* @return true 或 false
+	**/
+	public function IsBodySet()
+	{
+		return array_key_exists('body', $this->values);
+	}
+
+
+	/**
+	* 设置商品名称明细列表
+	* @param string $value 
+	**/
+	public function SetDetail($value)
+	{
+		$this->values['detail'] = $value;
+	}
+	/**
+	* 获取商品名称明细列表的值
+	* @return 值
+	**/
+	public function GetDetail()
+	{
+		return $this->values['detail'];
+	}
+	/**
+	* 判断商品名称明细列表是否存在
+	* @return true 或 false
+	**/
+	public function IsDetailSet()
+	{
+		return array_key_exists('detail', $this->values);
+	}
+
+
+	/**
+	* 设置附加数据,在查询API和支付通知中原样返回,该字段主要用于商户携带订单的自定义数据
+	* @param string $value 
+	**/
+	public function SetAttach($value)
+	{
+		$this->values['attach'] = $value;
+	}
+	/**
+	* 获取附加数据,在查询API和支付通知中原样返回,该字段主要用于商户携带订单的自定义数据的值
+	* @return 值
+	**/
+	public function GetAttach()
+	{
+		return $this->values['attach'];
+	}
+	/**
+	* 判断附加数据,在查询API和支付通知中原样返回,该字段主要用于商户携带订单的自定义数据是否存在
+	* @return true 或 false
+	**/
+	public function IsAttachSet()
+	{
+		return array_key_exists('attach', $this->values);
+	}
+
+
+	/**
+	* 设置商户系统内部的订单号,32个字符内、可包含字母, 其他说明见商户订单号
+	* @param string $value 
+	**/
+	public function SetOut_trade_no($value)
+	{
+		$this->values['out_trade_no'] = $value;
+	}
+	/**
+	* 获取商户系统内部的订单号,32个字符内、可包含字母, 其他说明见商户订单号的值
+	* @return 值
+	**/
+	public function GetOut_trade_no()
+	{
+		return $this->values['out_trade_no'];
+	}
+	/**
+	* 判断商户系统内部的订单号,32个字符内、可包含字母, 其他说明见商户订单号是否存在
+	* @return true 或 false
+	**/
+	public function IsOut_trade_noSet()
+	{
+		return array_key_exists('out_trade_no', $this->values);
+	}
+
+
+	/**
+	* 设置符合ISO 4217标准的三位字母代码,默认人民币:CNY,其他值列表详见货币类型
+	* @param string $value 
+	**/
+	public function SetFee_type($value)
+	{
+		$this->values['fee_type'] = $value;
+	}
+	/**
+	* 获取符合ISO 4217标准的三位字母代码,默认人民币:CNY,其他值列表详见货币类型的值
+	* @return 值
+	**/
+	public function GetFee_type()
+	{
+		return $this->values['fee_type'];
+	}
+	/**
+	* 判断符合ISO 4217标准的三位字母代码,默认人民币:CNY,其他值列表详见货币类型是否存在
+	* @return true 或 false
+	**/
+	public function IsFee_typeSet()
+	{
+		return array_key_exists('fee_type', $this->values);
+	}
+
+
+	/**
+	* 设置订单总金额,只能为整数,详见支付金额
+	* @param string $value 
+	**/
+	public function SetTotal_fee($value)
+	{
+		$this->values['total_fee'] = $value;
+	}
+	/**
+	* 获取订单总金额,只能为整数,详见支付金额的值
+	* @return 值
+	**/
+	public function GetTotal_fee()
+	{
+		return $this->values['total_fee'];
+	}
+	/**
+	* 判断订单总金额,只能为整数,详见支付金额是否存在
+	* @return true 或 false
+	**/
+	public function IsTotal_feeSet()
+	{
+		return array_key_exists('total_fee', $this->values);
+	}
+
+
+	/**
+	* 设置APP和网页支付提交用户端ip,Native支付填调用微信支付API的机器IP。
+	* @param string $value 
+	**/
+	public function SetSpbill_create_ip($value)
+	{
+		$this->values['spbill_create_ip'] = $value;
+	}
+	/**
+	* 获取APP和网页支付提交用户端ip,Native支付填调用微信支付API的机器IP。的值
+	* @return 值
+	**/
+	public function GetSpbill_create_ip()
+	{
+		return $this->values['spbill_create_ip'];
+	}
+	/**
+	* 判断APP和网页支付提交用户端ip,Native支付填调用微信支付API的机器IP。是否存在
+	* @return true 或 false
+	**/
+	public function IsSpbill_create_ipSet()
+	{
+		return array_key_exists('spbill_create_ip', $this->values);
+	}
+
+
+	/**
+	* 设置订单生成时间,格式为yyyyMMddHHmmss,如2009年12月25日9点10分10秒表示为20091225091010。其他详见时间规则
+	* @param string $value 
+	**/
+	public function SetTime_start($value)
+	{
+		$this->values['time_start'] = $value;
+	}
+	/**
+	* 获取订单生成时间,格式为yyyyMMddHHmmss,如2009年12月25日9点10分10秒表示为20091225091010。其他详见时间规则的值
+	* @return 值
+	**/
+	public function GetTime_start()
+	{
+		return $this->values['time_start'];
+	}
+	/**
+	* 判断订单生成时间,格式为yyyyMMddHHmmss,如2009年12月25日9点10分10秒表示为20091225091010。其他详见时间规则是否存在
+	* @return true 或 false
+	**/
+	public function IsTime_startSet()
+	{
+		return array_key_exists('time_start', $this->values);
+	}
+
+
+	/**
+	* 设置订单失效时间,格式为yyyyMMddHHmmss,如2009年12月27日9点10分10秒表示为20091227091010。其他详见时间规则
+	* @param string $value 
+	**/
+	public function SetTime_expire($value)
+	{
+		$this->values['time_expire'] = $value;
+	}
+	/**
+	* 获取订单失效时间,格式为yyyyMMddHHmmss,如2009年12月27日9点10分10秒表示为20091227091010。其他详见时间规则的值
+	* @return 值
+	**/
+	public function GetTime_expire()
+	{
+		return $this->values['time_expire'];
+	}
+	/**
+	* 判断订单失效时间,格式为yyyyMMddHHmmss,如2009年12月27日9点10分10秒表示为20091227091010。其他详见时间规则是否存在
+	* @return true 或 false
+	**/
+	public function IsTime_expireSet()
+	{
+		return array_key_exists('time_expire', $this->values);
+	}
+
+
+	/**
+	* 设置商品标记,代金券或立减优惠功能的参数,说明详见代金券或立减优惠
+	* @param string $value 
+	**/
+	public function SetGoods_tag($value)
+	{
+		$this->values['goods_tag'] = $value;
+	}
+	/**
+	* 获取商品标记,代金券或立减优惠功能的参数,说明详见代金券或立减优惠的值
+	* @return 值
+	**/
+	public function GetGoods_tag()
+	{
+		return $this->values['goods_tag'];
+	}
+	/**
+	* 判断商品标记,代金券或立减优惠功能的参数,说明详见代金券或立减优惠是否存在
+	* @return true 或 false
+	**/
+	public function IsGoods_tagSet()
+	{
+		return array_key_exists('goods_tag', $this->values);
+	}
+
+
+	/**
+	* 设置接收微信支付异步通知回调地址
+	* @param string $value 
+	**/
+	public function SetNotify_url($value)
+	{
+		$this->values['notify_url'] = $value;
+	}
+	/**
+	* 获取接收微信支付异步通知回调地址的值
+	* @return 值
+	**/
+	public function GetNotify_url()
+	{
+		return $this->values['notify_url'];
+	}
+	/**
+	* 判断接收微信支付异步通知回调地址是否存在
+	* @return true 或 false
+	**/
+	public function IsNotify_urlSet()
+	{
+		return array_key_exists('notify_url', $this->values);
+	}
+
+
+	/**
+	* 设置取值如下:JSAPI,NATIVE,APP,详细说明见参数规定
+	* @param string $value 
+	**/
+	public function SetTrade_type($value)
+	{
+		$this->values['trade_type'] = $value;
+	}
+	/**
+	* 获取取值如下:JSAPI,NATIVE,APP,详细说明见参数规定的值
+	* @return 值
+	**/
+	public function GetTrade_type()
+	{
+		return $this->values['trade_type'];
+	}
+	/**
+	* 判断取值如下:JSAPI,NATIVE,APP,详细说明见参数规定是否存在
+	* @return true 或 false
+	**/
+	public function IsTrade_typeSet()
+	{
+		return array_key_exists('trade_type', $this->values);
+	}
+
+
+	/**
+	* 设置trade_type=NATIVE,此参数必传。此id为二维码中包含的商品ID,商户自行定义。
+	* @param string $value 
+	**/
+	public function SetProduct_id($value)
+	{
+		$this->values['product_id'] = $value;
+	}
+	/**
+	* 获取trade_type=NATIVE,此参数必传。此id为二维码中包含的商品ID,商户自行定义。的值
+	* @return 值
+	**/
+	public function GetProduct_id()
+	{
+		return $this->values['product_id'];
+	}
+	/**
+	* 判断trade_type=NATIVE,此参数必传。此id为二维码中包含的商品ID,商户自行定义。是否存在
+	* @return true 或 false
+	**/
+	public function IsProduct_idSet()
+	{
+		return array_key_exists('product_id', $this->values);
+	}
+
+
+	/**
+	* 设置trade_type=JSAPI,此参数必传,用户在商户appid下的唯一标识。下单前需要调用【网页授权获取用户信息】接口获取到用户的Openid。 
+	* @param string $value 
+	**/
+	public function SetOpenid($value)
+	{
+		$this->values['openid'] = $value;
+	}
+	/**
+	* 获取trade_type=JSAPI,此参数必传,用户在商户appid下的唯一标识。下单前需要调用【网页授权获取用户信息】接口获取到用户的Openid。 的值
+	* @return 值
+	**/
+	public function GetOpenid()
+	{
+		return $this->values['openid'];
+	}
+	/**
+	* 判断trade_type=JSAPI,此参数必传,用户在商户appid下的唯一标识。下单前需要调用【网页授权获取用户信息】接口获取到用户的Openid。 是否存在
+	* @return true 或 false
+	**/
+	public function IsOpenidSet()
+	{
+		return array_key_exists('openid', $this->values);
+	}
+}
+
+/**
+ * 
+ * 订单查询输入对象
+ * @author widyhu
+ *
+ */
+class WxPayOrderQuery extends WxPayDataBase
+{
+	/**
+	* 设置微信分配的公众账号ID
+	* @param string $value 
+	**/
+	public function SetAppid($value)
+	{
+		$this->values['appid'] = $value;
+	}
+	/**
+	* 获取微信分配的公众账号ID的值
+	* @return 值
+	**/
+	public function GetAppid()
+	{
+		return $this->values['appid'];
+	}
+	/**
+	* 判断微信分配的公众账号ID是否存在
+	* @return true 或 false
+	**/
+	public function IsAppidSet()
+	{
+		return array_key_exists('appid', $this->values);
+	}
+
+
+	/**
+	* 设置微信支付分配的商户号
+	* @param string $value 
+	**/
+	public function SetMch_id($value)
+	{
+		$this->values['mch_id'] = $value;
+	}
+	/**
+	* 获取微信支付分配的商户号的值
+	* @return 值
+	**/
+	public function GetMch_id()
+	{
+		return $this->values['mch_id'];
+	}
+	/**
+	* 判断微信支付分配的商户号是否存在
+	* @return true 或 false
+	**/
+	public function IsMch_idSet()
+	{
+		return array_key_exists('mch_id', $this->values);
+	}
+
+
+	/**
+	* 设置微信的订单号,优先使用
+	* @param string $value 
+	**/
+	public function SetTransaction_id($value)
+	{
+		$this->values['transaction_id'] = $value;
+	}
+	/**
+	* 获取微信的订单号,优先使用的值
+	* @return 值
+	**/
+	public function GetTransaction_id()
+	{
+		return $this->values['transaction_id'];
+	}
+	/**
+	* 判断微信的订单号,优先使用是否存在
+	* @return true 或 false
+	**/
+	public function IsTransaction_idSet()
+	{
+		return array_key_exists('transaction_id', $this->values);
+	}
+
+
+	/**
+	* 设置商户系统内部的订单号,当没提供transaction_id时需要传这个。
+	* @param string $value 
+	**/
+	public function SetOut_trade_no($value)
+	{
+		$this->values['out_trade_no'] = $value;
+	}
+	/**
+	* 获取商户系统内部的订单号,当没提供transaction_id时需要传这个。的值
+	* @return 值
+	**/
+	public function GetOut_trade_no()
+	{
+		return $this->values['out_trade_no'];
+	}
+	/**
+	* 判断商户系统内部的订单号,当没提供transaction_id时需要传这个。是否存在
+	* @return true 或 false
+	**/
+	public function IsOut_trade_noSet()
+	{
+		return array_key_exists('out_trade_no', $this->values);
+	}
+
+
+	/**
+	* 设置随机字符串,不长于32位。推荐随机数生成算法
+	* @param string $value 
+	**/
+	public function SetNonce_str($value)
+	{
+		$this->values['nonce_str'] = $value;
+	}
+	/**
+	* 获取随机字符串,不长于32位。推荐随机数生成算法的值
+	* @return 值
+	**/
+	public function GetNonce_str()
+	{
+		return $this->values['nonce_str'];
+	}
+	/**
+	* 判断随机字符串,不长于32位。推荐随机数生成算法是否存在
+	* @return true 或 false
+	**/
+	public function IsNonce_strSet()
+	{
+		return array_key_exists('nonce_str', $this->values);
+	}
+}
+
+/**
+ * 
+ * 关闭订单输入对象
+ * @author widyhu
+ *
+ */
+class WxPayCloseOrder extends WxPayDataBase
+{
+	/**
+	* 设置微信分配的公众账号ID
+	* @param string $value 
+	**/
+	public function SetAppid($value)
+	{
+		$this->values['appid'] = $value;
+	}
+	/**
+	* 获取微信分配的公众账号ID的值
+	* @return 值
+	**/
+	public function GetAppid()
+	{
+		return $this->values['appid'];
+	}
+	/**
+	* 判断微信分配的公众账号ID是否存在
+	* @return true 或 false
+	**/
+	public function IsAppidSet()
+	{
+		return array_key_exists('appid', $this->values);
+	}
+
+
+	/**
+	* 设置微信支付分配的商户号
+	* @param string $value 
+	**/
+	public function SetMch_id($value)
+	{
+		$this->values['mch_id'] = $value;
+	}
+	/**
+	* 获取微信支付分配的商户号的值
+	* @return 值
+	**/
+	public function GetMch_id()
+	{
+		return $this->values['mch_id'];
+	}
+	/**
+	* 判断微信支付分配的商户号是否存在
+	* @return true 或 false
+	**/
+	public function IsMch_idSet()
+	{
+		return array_key_exists('mch_id', $this->values);
+	}
+
+
+	/**
+	* 设置商户系统内部的订单号
+	* @param string $value 
+	**/
+	public function SetOut_trade_no($value)
+	{
+		$this->values['out_trade_no'] = $value;
+	}
+	/**
+	* 获取商户系统内部的订单号的值
+	* @return 值
+	**/
+	public function GetOut_trade_no()
+	{
+		return $this->values['out_trade_no'];
+	}
+	/**
+	* 判断商户系统内部的订单号是否存在
+	* @return true 或 false
+	**/
+	public function IsOut_trade_noSet()
+	{
+		return array_key_exists('out_trade_no', $this->values);
+	}
+
+
+	/**
+	* 设置商户系统内部的订单号,32个字符内、可包含字母, 其他说明见商户订单号
+	* @param string $value 
+	**/
+	public function SetNonce_str($value)
+	{
+		$this->values['nonce_str'] = $value;
+	}
+	/**
+	* 获取商户系统内部的订单号,32个字符内、可包含字母, 其他说明见商户订单号的值
+	* @return 值
+	**/
+	public function GetNonce_str()
+	{
+		return $this->values['nonce_str'];
+	}
+	/**
+	* 判断商户系统内部的订单号,32个字符内、可包含字母, 其他说明见商户订单号是否存在
+	* @return true 或 false
+	**/
+	public function IsNonce_strSet()
+	{
+		return array_key_exists('nonce_str', $this->values);
+	}
+}
+
+/**
+ * 
+ * 提交退款输入对象
+ * @author widyhu
+ *
+ */
+class WxPayRefund extends WxPayDataBase
+{
+	/**
+	* 设置微信分配的公众账号ID
+	* @param string $value 
+	**/
+	public function SetAppid($value)
+	{
+		$this->values['appid'] = $value;
+	}
+	/**
+	* 获取微信分配的公众账号ID的值
+	* @return 值
+	**/
+	public function GetAppid()
+	{
+		return $this->values['appid'];
+	}
+	/**
+	* 判断微信分配的公众账号ID是否存在
+	* @return true 或 false
+	**/
+	public function IsAppidSet()
+	{
+		return array_key_exists('appid', $this->values);
+	}
+
+
+	/**
+	* 设置微信支付分配的商户号
+	* @param string $value 
+	**/
+	public function SetMch_id($value)
+	{
+		$this->values['mch_id'] = $value;
+	}
+	/**
+	* 获取微信支付分配的商户号的值
+	* @return 值
+	**/
+	public function GetMch_id()
+	{
+		return $this->values['mch_id'];
+	}
+	/**
+	* 判断微信支付分配的商户号是否存在
+	* @return true 或 false
+	**/
+	public function IsMch_idSet()
+	{
+		return array_key_exists('mch_id', $this->values);
+	}
+
+
+	/**
+	* 设置微信支付分配的终端设备号,与下单一致
+	* @param string $value 
+	**/
+	public function SetDevice_info($value)
+	{
+		$this->values['device_info'] = $value;
+	}
+	/**
+	* 获取微信支付分配的终端设备号,与下单一致的值
+	* @return 值
+	**/
+	public function GetDevice_info()
+	{
+		return $this->values['device_info'];
+	}
+	/**
+	* 判断微信支付分配的终端设备号,与下单一致是否存在
+	* @return true 或 false
+	**/
+	public function IsDevice_infoSet()
+	{
+		return array_key_exists('device_info', $this->values);
+	}
+
+
+	/**
+	* 设置随机字符串,不长于32位。推荐随机数生成算法
+	* @param string $value 
+	**/
+	public function SetNonce_str($value)
+	{
+		$this->values['nonce_str'] = $value;
+	}
+	/**
+	* 获取随机字符串,不长于32位。推荐随机数生成算法的值
+	* @return 值
+	**/
+	public function GetNonce_str()
+	{
+		return $this->values['nonce_str'];
+	}
+	/**
+	* 判断随机字符串,不长于32位。推荐随机数生成算法是否存在
+	* @return true 或 false
+	**/
+	public function IsNonce_strSet()
+	{
+		return array_key_exists('nonce_str', $this->values);
+	}
+
+	/**
+	* 设置微信订单号
+	* @param string $value 
+	**/
+	public function SetTransaction_id($value)
+	{
+		$this->values['transaction_id'] = $value;
+	}
+	/**
+	* 获取微信订单号的值
+	* @return 值
+	**/
+	public function GetTransaction_id()
+	{
+		return $this->values['transaction_id'];
+	}
+	/**
+	* 判断微信订单号是否存在
+	* @return true 或 false
+	**/
+	public function IsTransaction_idSet()
+	{
+		return array_key_exists('transaction_id', $this->values);
+	}
+
+
+	/**
+	* 设置商户系统内部的订单号,transaction_id、out_trade_no二选一,如果同时存在优先级:transaction_id> out_trade_no
+	* @param string $value 
+	**/
+	public function SetOut_trade_no($value)
+	{
+		$this->values['out_trade_no'] = $value;
+	}
+	/**
+	* 获取商户系统内部的订单号,transaction_id、out_trade_no二选一,如果同时存在优先级:transaction_id> out_trade_no的值
+	* @return 值
+	**/
+	public function GetOut_trade_no()
+	{
+		return $this->values['out_trade_no'];
+	}
+	/**
+	* 判断商户系统内部的订单号,transaction_id、out_trade_no二选一,如果同时存在优先级:transaction_id> out_trade_no是否存在
+	* @return true 或 false
+	**/
+	public function IsOut_trade_noSet()
+	{
+		return array_key_exists('out_trade_no', $this->values);
+	}
+
+
+	/**
+	* 设置商户系统内部的退款单号,商户系统内部唯一,同一退款单号多次请求只退一笔
+	* @param string $value 
+	**/
+	public function SetOut_refund_no($value)
+	{
+		$this->values['out_refund_no'] = $value;
+	}
+	/**
+	* 获取商户系统内部的退款单号,商户系统内部唯一,同一退款单号多次请求只退一笔的值
+	* @return 值
+	**/
+	public function GetOut_refund_no()
+	{
+		return $this->values['out_refund_no'];
+	}
+	/**
+	* 判断商户系统内部的退款单号,商户系统内部唯一,同一退款单号多次请求只退一笔是否存在
+	* @return true 或 false
+	**/
+	public function IsOut_refund_noSet()
+	{
+		return array_key_exists('out_refund_no', $this->values);
+	}
+
+
+	/**
+	* 设置订单总金额,单位为分,只能为整数,详见支付金额
+	* @param string $value 
+	**/
+	public function SetTotal_fee($value)
+	{
+		$this->values['total_fee'] = $value;
+	}
+	/**
+	* 获取订单总金额,单位为分,只能为整数,详见支付金额的值
+	* @return 值
+	**/
+	public function GetTotal_fee()
+	{
+		return $this->values['total_fee'];
+	}
+	/**
+	* 判断订单总金额,单位为分,只能为整数,详见支付金额是否存在
+	* @return true 或 false
+	**/
+	public function IsTotal_feeSet()
+	{
+		return array_key_exists('total_fee', $this->values);
+	}
+
+
+	/**
+	* 设置退款总金额,订单总金额,单位为分,只能为整数,详见支付金额
+	* @param string $value 
+	**/
+	public function SetRefund_fee($value)
+	{
+		$this->values['refund_fee'] = $value;
+	}
+	/**
+	* 获取退款总金额,订单总金额,单位为分,只能为整数,详见支付金额的值
+	* @return 值
+	**/
+	public function GetRefund_fee()
+	{
+		return $this->values['refund_fee'];
+	}
+	/**
+	* 判断退款总金额,订单总金额,单位为分,只能为整数,详见支付金额是否存在
+	* @return true 或 false
+	**/
+	public function IsRefund_feeSet()
+	{
+		return array_key_exists('refund_fee', $this->values);
+	}
+
+
+	/**
+	* 设置货币类型,符合ISO 4217标准的三位字母代码,默认人民币:CNY,其他值列表详见货币类型
+	* @param string $value 
+	**/
+	public function SetRefund_fee_type($value)
+	{
+		$this->values['refund_fee_type'] = $value;
+	}
+	/**
+	* 获取货币类型,符合ISO 4217标准的三位字母代码,默认人民币:CNY,其他值列表详见货币类型的值
+	* @return 值
+	**/
+	public function GetRefund_fee_type()
+	{
+		return $this->values['refund_fee_type'];
+	}
+	/**
+	* 判断货币类型,符合ISO 4217标准的三位字母代码,默认人民币:CNY,其他值列表详见货币类型是否存在
+	* @return true 或 false
+	**/
+	public function IsRefund_fee_typeSet()
+	{
+		return array_key_exists('refund_fee_type', $this->values);
+	}
+
+
+	/**
+	* 设置操作员帐号, 默认为商户号
+	* @param string $value 
+	**/
+	public function SetOp_user_id($value)
+	{
+		$this->values['op_user_id'] = $value;
+	}
+	/**
+	* 获取操作员帐号, 默认为商户号的值
+	* @return 值
+	**/
+	public function GetOp_user_id()
+	{
+		return $this->values['op_user_id'];
+	}
+	/**
+	* 判断操作员帐号, 默认为商户号是否存在
+	* @return true 或 false
+	**/
+	public function IsOp_user_idSet()
+	{
+		return array_key_exists('op_user_id', $this->values);
+	}
+}
+
+/**
+ * 
+ * 退款查询输入对象
+ * @author widyhu
+ *
+ */
+class WxPayRefundQuery extends WxPayDataBase
+{
+	/**
+	* 设置微信分配的公众账号ID
+	* @param string $value 
+	**/
+	public function SetAppid($value)
+	{
+		$this->values['appid'] = $value;
+	}
+	/**
+	* 获取微信分配的公众账号ID的值
+	* @return 值
+	**/
+	public function GetAppid()
+	{
+		return $this->values['appid'];
+	}
+	/**
+	* 判断微信分配的公众账号ID是否存在
+	* @return true 或 false
+	**/
+	public function IsAppidSet()
+	{
+		return array_key_exists('appid', $this->values);
+	}
+
+
+	/**
+	* 设置微信支付分配的商户号
+	* @param string $value 
+	**/
+	public function SetMch_id($value)
+	{
+		$this->values['mch_id'] = $value;
+	}
+	/**
+	* 获取微信支付分配的商户号的值
+	* @return 值
+	**/
+	public function GetMch_id()
+	{
+		return $this->values['mch_id'];
+	}
+	/**
+	* 判断微信支付分配的商户号是否存在
+	* @return true 或 false
+	**/
+	public function IsMch_idSet()
+	{
+		return array_key_exists('mch_id', $this->values);
+	}
+
+
+	/**
+	* 设置微信支付分配的终端设备号
+	* @param string $value 
+	**/
+	public function SetDevice_info($value)
+	{
+		$this->values['device_info'] = $value;
+	}
+	/**
+	* 获取微信支付分配的终端设备号的值
+	* @return 值
+	**/
+	public function GetDevice_info()
+	{
+		return $this->values['device_info'];
+	}
+	/**
+	* 判断微信支付分配的终端设备号是否存在
+	* @return true 或 false
+	**/
+	public function IsDevice_infoSet()
+	{
+		return array_key_exists('device_info', $this->values);
+	}
+
+
+	/**
+	* 设置随机字符串,不长于32位。推荐随机数生成算法
+	* @param string $value 
+	**/
+	public function SetNonce_str($value)
+	{
+		$this->values['nonce_str'] = $value;
+	}
+	/**
+	* 获取随机字符串,不长于32位。推荐随机数生成算法的值
+	* @return 值
+	**/
+	public function GetNonce_str()
+	{
+		return $this->values['nonce_str'];
+	}
+	/**
+	* 判断随机字符串,不长于32位。推荐随机数生成算法是否存在
+	* @return true 或 false
+	**/
+	public function IsNonce_strSet()
+	{
+		return array_key_exists('nonce_str', $this->values);
+	}
+
+	/**
+	* 设置微信订单号
+	* @param string $value 
+	**/
+	public function SetTransaction_id($value)
+	{
+		$this->values['transaction_id'] = $value;
+	}
+	/**
+	* 获取微信订单号的值
+	* @return 值
+	**/
+	public function GetTransaction_id()
+	{
+		return $this->values['transaction_id'];
+	}
+	/**
+	* 判断微信订单号是否存在
+	* @return true 或 false
+	**/
+	public function IsTransaction_idSet()
+	{
+		return array_key_exists('transaction_id', $this->values);
+	}
+
+
+	/**
+	* 设置商户系统内部的订单号
+	* @param string $value 
+	**/
+	public function SetOut_trade_no($value)
+	{
+		$this->values['out_trade_no'] = $value;
+	}
+	/**
+	* 获取商户系统内部的订单号的值
+	* @return 值
+	**/
+	public function GetOut_trade_no()
+	{
+		return $this->values['out_trade_no'];
+	}
+	/**
+	* 判断商户系统内部的订单号是否存在
+	* @return true 或 false
+	**/
+	public function IsOut_trade_noSet()
+	{
+		return array_key_exists('out_trade_no', $this->values);
+	}
+
+
+	/**
+	* 设置商户退款单号
+	* @param string $value 
+	**/
+	public function SetOut_refund_no($value)
+	{
+		$this->values['out_refund_no'] = $value;
+	}
+	/**
+	* 获取商户退款单号的值
+	* @return 值
+	**/
+	public function GetOut_refund_no()
+	{
+		return $this->values['out_refund_no'];
+	}
+	/**
+	* 判断商户退款单号是否存在
+	* @return true 或 false
+	**/
+	public function IsOut_refund_noSet()
+	{
+		return array_key_exists('out_refund_no', $this->values);
+	}
+
+
+	/**
+	* 设置微信退款单号refund_id、out_refund_no、out_trade_no、transaction_id四个参数必填一个,如果同时存在优先级为:refund_id>out_refund_no>transaction_id>out_trade_no
+	* @param string $value 
+	**/
+	public function SetRefund_id($value)
+	{
+		$this->values['refund_id'] = $value;
+	}
+	/**
+	* 获取微信退款单号refund_id、out_refund_no、out_trade_no、transaction_id四个参数必填一个,如果同时存在优先级为:refund_id>out_refund_no>transaction_id>out_trade_no的值
+	* @return 值
+	**/
+	public function GetRefund_id()
+	{
+		return $this->values['refund_id'];
+	}
+	/**
+	* 判断微信退款单号refund_id、out_refund_no、out_trade_no、transaction_id四个参数必填一个,如果同时存在优先级为:refund_id>out_refund_no>transaction_id>out_trade_no是否存在
+	* @return true 或 false
+	**/
+	public function IsRefund_idSet()
+	{
+		return array_key_exists('refund_id', $this->values);
+	}
+}
+
+/**
+ * 
+ * 下载对账单输入对象
+ * @author widyhu
+ *
+ */
+class WxPayDownloadBill extends WxPayDataBase
+{
+	/**
+	* 设置微信分配的公众账号ID
+	* @param string $value 
+	**/
+	public function SetAppid($value)
+	{
+		$this->values['appid'] = $value;
+	}
+	/**
+	* 获取微信分配的公众账号ID的值
+	* @return 值
+	**/
+	public function GetAppid()
+	{
+		return $this->values['appid'];
+	}
+	/**
+	* 判断微信分配的公众账号ID是否存在
+	* @return true 或 false
+	**/
+	public function IsAppidSet()
+	{
+		return array_key_exists('appid', $this->values);
+	}
+
+
+	/**
+	* 设置微信支付分配的商户号
+	* @param string $value 
+	**/
+	public function SetMch_id($value)
+	{
+		$this->values['mch_id'] = $value;
+	}
+	/**
+	* 获取微信支付分配的商户号的值
+	* @return 值
+	**/
+	public function GetMch_id()
+	{
+		return $this->values['mch_id'];
+	}
+	/**
+	* 判断微信支付分配的商户号是否存在
+	* @return true 或 false
+	**/
+	public function IsMch_idSet()
+	{
+		return array_key_exists('mch_id', $this->values);
+	}
+
+
+	/**
+	* 设置微信支付分配的终端设备号,填写此字段,只下载该设备号的对账单
+	* @param string $value 
+	**/
+	public function SetDevice_info($value)
+	{
+		$this->values['device_info'] = $value;
+	}
+	/**
+	* 获取微信支付分配的终端设备号,填写此字段,只下载该设备号的对账单的值
+	* @return 值
+	**/
+	public function GetDevice_info()
+	{
+		return $this->values['device_info'];
+	}
+	/**
+	* 判断微信支付分配的终端设备号,填写此字段,只下载该设备号的对账单是否存在
+	* @return true 或 false
+	**/
+	public function IsDevice_infoSet()
+	{
+		return array_key_exists('device_info', $this->values);
+	}
+
+
+	/**
+	* 设置随机字符串,不长于32位。推荐随机数生成算法
+	* @param string $value 
+	**/
+	public function SetNonce_str($value)
+	{
+		$this->values['nonce_str'] = $value;
+	}
+	/**
+	* 获取随机字符串,不长于32位。推荐随机数生成算法的值
+	* @return 值
+	**/
+	public function GetNonce_str()
+	{
+		return $this->values['nonce_str'];
+	}
+	/**
+	* 判断随机字符串,不长于32位。推荐随机数生成算法是否存在
+	* @return true 或 false
+	**/
+	public function IsNonce_strSet()
+	{
+		return array_key_exists('nonce_str', $this->values);
+	}
+
+	/**
+	* 设置下载对账单的日期,格式:20140603
+	* @param string $value 
+	**/
+	public function SetBill_date($value)
+	{
+		$this->values['bill_date'] = $value;
+	}
+	/**
+	* 获取下载对账单的日期,格式:20140603的值
+	* @return 值
+	**/
+	public function GetBill_date()
+	{
+		return $this->values['bill_date'];
+	}
+	/**
+	* 判断下载对账单的日期,格式:20140603是否存在
+	* @return true 或 false
+	**/
+	public function IsBill_dateSet()
+	{
+		return array_key_exists('bill_date', $this->values);
+	}
+
+
+	/**
+	* 设置ALL,返回当日所有订单信息,默认值SUCCESS,返回当日成功支付的订单REFUND,返回当日退款订单REVOKED,已撤销的订单
+	* @param string $value 
+	**/
+	public function SetBill_type($value)
+	{
+		$this->values['bill_type'] = $value;
+	}
+	/**
+	* 获取ALL,返回当日所有订单信息,默认值SUCCESS,返回当日成功支付的订单REFUND,返回当日退款订单REVOKED,已撤销的订单的值
+	* @return 值
+	**/
+	public function GetBill_type()
+	{
+		return $this->values['bill_type'];
+	}
+	/**
+	* 判断ALL,返回当日所有订单信息,默认值SUCCESS,返回当日成功支付的订单REFUND,返回当日退款订单REVOKED,已撤销的订单是否存在
+	* @return true 或 false
+	**/
+	public function IsBill_typeSet()
+	{
+		return array_key_exists('bill_type', $this->values);
+	}
+}
+
+/**
+ * 
+ * 测速上报输入对象
+ * @author widyhu
+ *
+ */
+class WxPayReport extends WxPayDataBase
+{
+	/**
+	* 设置微信分配的公众账号ID
+	* @param string $value 
+	**/
+	public function SetAppid($value)
+	{
+		$this->values['appid'] = $value;
+	}
+	/**
+	* 获取微信分配的公众账号ID的值
+	* @return 值
+	**/
+	public function GetAppid()
+	{
+		return $this->values['appid'];
+	}
+	/**
+	* 判断微信分配的公众账号ID是否存在
+	* @return true 或 false
+	**/
+	public function IsAppidSet()
+	{
+		return array_key_exists('appid', $this->values);
+	}
+
+
+	/**
+	* 设置微信支付分配的商户号
+	* @param string $value 
+	**/
+	public function SetMch_id($value)
+	{
+		$this->values['mch_id'] = $value;
+	}
+	/**
+	* 获取微信支付分配的商户号的值
+	* @return 值
+	**/
+	public function GetMch_id()
+	{
+		return $this->values['mch_id'];
+	}
+	/**
+	* 判断微信支付分配的商户号是否存在
+	* @return true 或 false
+	**/
+	public function IsMch_idSet()
+	{
+		return array_key_exists('mch_id', $this->values);
+	}
+
+
+	/**
+	* 设置微信支付分配的终端设备号,商户自定义
+	* @param string $value 
+	**/
+	public function SetDevice_info($value)
+	{
+		$this->values['device_info'] = $value;
+	}
+	/**
+	* 获取微信支付分配的终端设备号,商户自定义的值
+	* @return 值
+	**/
+	public function GetDevice_info()
+	{
+		return $this->values['device_info'];
+	}
+	/**
+	* 判断微信支付分配的终端设备号,商户自定义是否存在
+	* @return true 或 false
+	**/
+	public function IsDevice_infoSet()
+	{
+		return array_key_exists('device_info', $this->values);
+	}
+
+
+	/**
+	* 设置随机字符串,不长于32位。推荐随机数生成算法
+	* @param string $value 
+	**/
+	public function SetNonce_str($value)
+	{
+		$this->values['nonce_str'] = $value;
+	}
+	/**
+	* 获取随机字符串,不长于32位。推荐随机数生成算法的值
+	* @return 值
+	**/
+	public function GetNonce_str()
+	{
+		return $this->values['nonce_str'];
+	}
+	/**
+	* 判断随机字符串,不长于32位。推荐随机数生成算法是否存在
+	* @return true 或 false
+	**/
+	public function IsNonce_strSet()
+	{
+		return array_key_exists('nonce_str', $this->values);
+	}
+
+
+	/**
+	* 设置上报对应的接口的完整URL,类似:https://api.mch.weixin.qq.com/pay/unifiedorder对于被扫支付,为更好的和商户共同分析一次业务行为的整体耗时情况,对于两种接入模式,请都在门店侧对一次被扫行为进行一次单独的整体上报,上报URL指定为:https://api.mch.weixin.qq.com/pay/micropay/total关于两种接入模式具体可参考本文档章节:被扫支付商户接入模式其它接口调用仍然按照调用一次,上报一次来进行。
+	* @param string $value 
+	**/
+	public function SetInterface_url($value)
+	{
+		$this->values['interface_url'] = $value;
+	}
+	/**
+	* 获取上报对应的接口的完整URL,类似:https://api.mch.weixin.qq.com/pay/unifiedorder对于被扫支付,为更好的和商户共同分析一次业务行为的整体耗时情况,对于两种接入模式,请都在门店侧对一次被扫行为进行一次单独的整体上报,上报URL指定为:https://api.mch.weixin.qq.com/pay/micropay/total关于两种接入模式具体可参考本文档章节:被扫支付商户接入模式其它接口调用仍然按照调用一次,上报一次来进行。的值
+	* @return 值
+	**/
+	public function GetInterface_url()
+	{
+		return $this->values['interface_url'];
+	}
+	/**
+	* 判断上报对应的接口的完整URL,类似:https://api.mch.weixin.qq.com/pay/unifiedorder对于被扫支付,为更好的和商户共同分析一次业务行为的整体耗时情况,对于两种接入模式,请都在门店侧对一次被扫行为进行一次单独的整体上报,上报URL指定为:https://api.mch.weixin.qq.com/pay/micropay/total关于两种接入模式具体可参考本文档章节:被扫支付商户接入模式其它接口调用仍然按照调用一次,上报一次来进行。是否存在
+	* @return true 或 false
+	**/
+	public function IsInterface_urlSet()
+	{
+		return array_key_exists('interface_url', $this->values);
+	}
+
+
+	/**
+	* 设置接口耗时情况,单位为毫秒
+	* @param string $value 
+	**/
+	public function SetExecute_time_($value)
+	{
+		$this->values['execute_time_'] = $value;
+	}
+	/**
+	* 获取接口耗时情况,单位为毫秒的值
+	* @return 值
+	**/
+	public function GetExecute_time_()
+	{
+		return $this->values['execute_time_'];
+	}
+	/**
+	* 判断接口耗时情况,单位为毫秒是否存在
+	* @return true 或 false
+	**/
+	public function IsExecute_time_Set()
+	{
+		return array_key_exists('execute_time_', $this->values);
+	}
+
+
+	/**
+	* 设置SUCCESS/FAIL此字段是通信标识,非交易标识,交易是否成功需要查看trade_state来判断
+	* @param string $value 
+	**/
+	public function SetReturn_code($value)
+	{
+		$this->values['return_code'] = $value;
+	}
+	/**
+	* 获取SUCCESS/FAIL此字段是通信标识,非交易标识,交易是否成功需要查看trade_state来判断的值
+	* @return 值
+	**/
+	public function GetReturn_code()
+	{
+		return $this->values['return_code'];
+	}
+	/**
+	* 判断SUCCESS/FAIL此字段是通信标识,非交易标识,交易是否成功需要查看trade_state来判断是否存在
+	* @return true 或 false
+	**/
+	public function IsReturn_codeSet()
+	{
+		return array_key_exists('return_code', $this->values);
+	}
+
+
+	/**
+	* 设置返回信息,如非空,为错误原因签名失败参数格式校验错误
+	* @param string $value 
+	**/
+	public function SetReturn_msg($value)
+	{
+		$this->values['return_msg'] = $value;
+	}
+	/**
+	* 获取返回信息,如非空,为错误原因签名失败参数格式校验错误的值
+	* @return 值
+	**/
+	public function GetReturn_msg()
+	{
+		return $this->values['return_msg'];
+	}
+	/**
+	* 判断返回信息,如非空,为错误原因签名失败参数格式校验错误是否存在
+	* @return true 或 false
+	**/
+	public function IsReturn_msgSet()
+	{
+		return array_key_exists('return_msg', $this->values);
+	}
+
+
+	/**
+	* 设置SUCCESS/FAIL
+	* @param string $value 
+	**/
+	public function SetResult_code($value)
+	{
+		$this->values['result_code'] = $value;
+	}
+	/**
+	* 获取SUCCESS/FAIL的值
+	* @return 值
+	**/
+	public function GetResult_code()
+	{
+		return $this->values['result_code'];
+	}
+	/**
+	* 判断SUCCESS/FAIL是否存在
+	* @return true 或 false
+	**/
+	public function IsResult_codeSet()
+	{
+		return array_key_exists('result_code', $this->values);
+	}
+
+
+	/**
+	* 设置ORDERNOTEXIST—订单不存在SYSTEMERROR—系统错误
+	* @param string $value 
+	**/
+	public function SetErr_code($value)
+	{
+		$this->values['err_code'] = $value;
+	}
+	/**
+	* 获取ORDERNOTEXIST—订单不存在SYSTEMERROR—系统错误的值
+	* @return 值
+	**/
+	public function GetErr_code()
+	{
+		return $this->values['err_code'];
+	}
+	/**
+	* 判断ORDERNOTEXIST—订单不存在SYSTEMERROR—系统错误是否存在
+	* @return true 或 false
+	**/
+	public function IsErr_codeSet()
+	{
+		return array_key_exists('err_code', $this->values);
+	}
+
+
+	/**
+	* 设置结果信息描述
+	* @param string $value 
+	**/
+	public function SetErr_code_des($value)
+	{
+		$this->values['err_code_des'] = $value;
+	}
+	/**
+	* 获取结果信息描述的值
+	* @return 值
+	**/
+	public function GetErr_code_des()
+	{
+		return $this->values['err_code_des'];
+	}
+	/**
+	* 判断结果信息描述是否存在
+	* @return true 或 false
+	**/
+	public function IsErr_code_desSet()
+	{
+		return array_key_exists('err_code_des', $this->values);
+	}
+
+
+	/**
+	* 设置商户系统内部的订单号,商户可以在上报时提供相关商户订单号方便微信支付更好的提高服务质量。 
+	* @param string $value 
+	**/
+	public function SetOut_trade_no($value)
+	{
+		$this->values['out_trade_no'] = $value;
+	}
+	/**
+	* 获取商户系统内部的订单号,商户可以在上报时提供相关商户订单号方便微信支付更好的提高服务质量。 的值
+	* @return 值
+	**/
+	public function GetOut_trade_no()
+	{
+		return $this->values['out_trade_no'];
+	}
+	/**
+	* 判断商户系统内部的订单号,商户可以在上报时提供相关商户订单号方便微信支付更好的提高服务质量。 是否存在
+	* @return true 或 false
+	**/
+	public function IsOut_trade_noSet()
+	{
+		return array_key_exists('out_trade_no', $this->values);
+	}
+
+
+	/**
+	* 设置发起接口调用时的机器IP 
+	* @param string $value 
+	**/
+	public function SetUser_ip($value)
+	{
+		$this->values['user_ip'] = $value;
+	}
+	/**
+	* 获取发起接口调用时的机器IP 的值
+	* @return 值
+	**/
+	public function GetUser_ip()
+	{
+		return $this->values['user_ip'];
+	}
+	/**
+	* 判断发起接口调用时的机器IP 是否存在
+	* @return true 或 false
+	**/
+	public function IsUser_ipSet()
+	{
+		return array_key_exists('user_ip', $this->values);
+	}
+
+
+	/**
+	* 设置系统时间,格式为yyyyMMddHHmmss,如2009年12月27日9点10分10秒表示为20091227091010。其他详见时间规则
+	* @param string $value 
+	**/
+	public function SetTime($value)
+	{
+		$this->values['time'] = $value;
+	}
+	/**
+	* 获取系统时间,格式为yyyyMMddHHmmss,如2009年12月27日9点10分10秒表示为20091227091010。其他详见时间规则的值
+	* @return 值
+	**/
+	public function GetTime()
+	{
+		return $this->values['time'];
+	}
+	/**
+	* 判断系统时间,格式为yyyyMMddHHmmss,如2009年12月27日9点10分10秒表示为20091227091010。其他详见时间规则是否存在
+	* @return true 或 false
+	**/
+	public function IsTimeSet()
+	{
+		return array_key_exists('time', $this->values);
+	}
+}
+
+/**
+ * 
+ * 短链转换输入对象
+ * @author widyhu
+ *
+ */
+class WxPayShortUrl extends WxPayDataBase
+{
+	/**
+	* 设置微信分配的公众账号ID
+	* @param string $value 
+	**/
+	public function SetAppid($value)
+	{
+		$this->values['appid'] = $value;
+	}
+	/**
+	* 获取微信分配的公众账号ID的值
+	* @return 值
+	**/
+	public function GetAppid()
+	{
+		return $this->values['appid'];
+	}
+	/**
+	* 判断微信分配的公众账号ID是否存在
+	* @return true 或 false
+	**/
+	public function IsAppidSet()
+	{
+		return array_key_exists('appid', $this->values);
+	}
+
+
+	/**
+	* 设置微信支付分配的商户号
+	* @param string $value 
+	**/
+	public function SetMch_id($value)
+	{
+		$this->values['mch_id'] = $value;
+	}
+	/**
+	* 获取微信支付分配的商户号的值
+	* @return 值
+	**/
+	public function GetMch_id()
+	{
+		return $this->values['mch_id'];
+	}
+	/**
+	* 判断微信支付分配的商户号是否存在
+	* @return true 或 false
+	**/
+	public function IsMch_idSet()
+	{
+		return array_key_exists('mch_id', $this->values);
+	}
+
+
+	/**
+	* 设置需要转换的URL,签名用原串,传输需URL encode
+	* @param string $value 
+	**/
+	public function SetLong_url($value)
+	{
+		$this->values['long_url'] = $value;
+	}
+	/**
+	* 获取需要转换的URL,签名用原串,传输需URL encode的值
+	* @return 值
+	**/
+	public function GetLong_url()
+	{
+		return $this->values['long_url'];
+	}
+	/**
+	* 判断需要转换的URL,签名用原串,传输需URL encode是否存在
+	* @return true 或 false
+	**/
+	public function IsLong_urlSet()
+	{
+		return array_key_exists('long_url', $this->values);
+	}
+
+
+	/**
+	* 设置随机字符串,不长于32位。推荐随机数生成算法
+	* @param string $value 
+	**/
+	public function SetNonce_str($value)
+	{
+		$this->values['nonce_str'] = $value;
+	}
+	/**
+	* 获取随机字符串,不长于32位。推荐随机数生成算法的值
+	* @return 值
+	**/
+	public function GetNonce_str()
+	{
+		return $this->values['nonce_str'];
+	}
+	/**
+	* 判断随机字符串,不长于32位。推荐随机数生成算法是否存在
+	* @return true 或 false
+	**/
+	public function IsNonce_strSet()
+	{
+		return array_key_exists('nonce_str', $this->values);
+	}
+}
+
+/**
+ * 
+ * 提交被扫输入对象
+ * @author widyhu
+ *
+ */
+class WxPayMicroPay extends WxPayDataBase
+{
+	/**
+	* 设置微信分配的公众账号ID
+	* @param string $value 
+	**/
+	public function SetAppid($value)
+	{
+		$this->values['appid'] = $value;
+	}
+	/**
+	* 获取微信分配的公众账号ID的值
+	* @return 值
+	**/
+	public function GetAppid()
+	{
+		return $this->values['appid'];
+	}
+	/**
+	* 判断微信分配的公众账号ID是否存在
+	* @return true 或 false
+	**/
+	public function IsAppidSet()
+	{
+		return array_key_exists('appid', $this->values);
+	}
+
+
+	/**
+	* 设置微信支付分配的商户号
+	* @param string $value 
+	**/
+	public function SetMch_id($value)
+	{
+		$this->values['mch_id'] = $value;
+	}
+	/**
+	* 获取微信支付分配的商户号的值
+	* @return 值
+	**/
+	public function GetMch_id()
+	{
+		return $this->values['mch_id'];
+	}
+	/**
+	* 判断微信支付分配的商户号是否存在
+	* @return true 或 false
+	**/
+	public function IsMch_idSet()
+	{
+		return array_key_exists('mch_id', $this->values);
+	}
+
+
+	/**
+	* 设置终端设备号(商户自定义,如门店编号)
+	* @param string $value 
+	**/
+	public function SetDevice_info($value)
+	{
+		$this->values['device_info'] = $value;
+	}
+	/**
+	* 获取终端设备号(商户自定义,如门店编号)的值
+	* @return 值
+	**/
+	public function GetDevice_info()
+	{
+		return $this->values['device_info'];
+	}
+	/**
+	* 判断终端设备号(商户自定义,如门店编号)是否存在
+	* @return true 或 false
+	**/
+	public function IsDevice_infoSet()
+	{
+		return array_key_exists('device_info', $this->values);
+	}
+
+
+	/**
+	* 设置随机字符串,不长于32位。推荐随机数生成算法
+	* @param string $value 
+	**/
+	public function SetNonce_str($value)
+	{
+		$this->values['nonce_str'] = $value;
+	}
+	/**
+	* 获取随机字符串,不长于32位。推荐随机数生成算法的值
+	* @return 值
+	**/
+	public function GetNonce_str()
+	{
+		return $this->values['nonce_str'];
+	}
+	/**
+	* 判断随机字符串,不长于32位。推荐随机数生成算法是否存在
+	* @return true 或 false
+	**/
+	public function IsNonce_strSet()
+	{
+		return array_key_exists('nonce_str', $this->values);
+	}
+
+	/**
+	* 设置商品或支付单简要描述
+	* @param string $value 
+	**/
+	public function SetBody($value)
+	{
+		$this->values['body'] = $value;
+	}
+	/**
+	* 获取商品或支付单简要描述的值
+	* @return 值
+	**/
+	public function GetBody()
+	{
+		return $this->values['body'];
+	}
+	/**
+	* 判断商品或支付单简要描述是否存在
+	* @return true 或 false
+	**/
+	public function IsBodySet()
+	{
+		return array_key_exists('body', $this->values);
+	}
+
+
+	/**
+	* 设置商品名称明细列表
+	* @param string $value 
+	**/
+	public function SetDetail($value)
+	{
+		$this->values['detail'] = $value;
+	}
+	/**
+	* 获取商品名称明细列表的值
+	* @return 值
+	**/
+	public function GetDetail()
+	{
+		return $this->values['detail'];
+	}
+	/**
+	* 判断商品名称明细列表是否存在
+	* @return true 或 false
+	**/
+	public function IsDetailSet()
+	{
+		return array_key_exists('detail', $this->values);
+	}
+
+
+	/**
+	* 设置附加数据,在查询API和支付通知中原样返回,该字段主要用于商户携带订单的自定义数据
+	* @param string $value 
+	**/
+	public function SetAttach($value)
+	{
+		$this->values['attach'] = $value;
+	}
+	/**
+	* 获取附加数据,在查询API和支付通知中原样返回,该字段主要用于商户携带订单的自定义数据的值
+	* @return 值
+	**/
+	public function GetAttach()
+	{
+		return $this->values['attach'];
+	}
+	/**
+	* 判断附加数据,在查询API和支付通知中原样返回,该字段主要用于商户携带订单的自定义数据是否存在
+	* @return true 或 false
+	**/
+	public function IsAttachSet()
+	{
+		return array_key_exists('attach', $this->values);
+	}
+
+
+	/**
+	* 设置商户系统内部的订单号,32个字符内、可包含字母, 其他说明见商户订单号
+	* @param string $value 
+	**/
+	public function SetOut_trade_no($value)
+	{
+		$this->values['out_trade_no'] = $value;
+	}
+	/**
+	* 获取商户系统内部的订单号,32个字符内、可包含字母, 其他说明见商户订单号的值
+	* @return 值
+	**/
+	public function GetOut_trade_no()
+	{
+		return $this->values['out_trade_no'];
+	}
+	/**
+	* 判断商户系统内部的订单号,32个字符内、可包含字母, 其他说明见商户订单号是否存在
+	* @return true 或 false
+	**/
+	public function IsOut_trade_noSet()
+	{
+		return array_key_exists('out_trade_no', $this->values);
+	}
+
+
+	/**
+	* 设置订单总金额,单位为分,只能为整数,详见支付金额
+	* @param string $value 
+	**/
+	public function SetTotal_fee($value)
+	{
+		$this->values['total_fee'] = $value;
+	}
+	/**
+	* 获取订单总金额,单位为分,只能为整数,详见支付金额的值
+	* @return 值
+	**/
+	public function GetTotal_fee()
+	{
+		return $this->values['total_fee'];
+	}
+	/**
+	* 判断订单总金额,单位为分,只能为整数,详见支付金额是否存在
+	* @return true 或 false
+	**/
+	public function IsTotal_feeSet()
+	{
+		return array_key_exists('total_fee', $this->values);
+	}
+
+
+	/**
+	* 设置符合ISO 4217标准的三位字母代码,默认人民币:CNY,其他值列表详见货币类型
+	* @param string $value 
+	**/
+	public function SetFee_type($value)
+	{
+		$this->values['fee_type'] = $value;
+	}
+	/**
+	* 获取符合ISO 4217标准的三位字母代码,默认人民币:CNY,其他值列表详见货币类型的值
+	* @return 值
+	**/
+	public function GetFee_type()
+	{
+		return $this->values['fee_type'];
+	}
+	/**
+	* 判断符合ISO 4217标准的三位字母代码,默认人民币:CNY,其他值列表详见货币类型是否存在
+	* @return true 或 false
+	**/
+	public function IsFee_typeSet()
+	{
+		return array_key_exists('fee_type', $this->values);
+	}
+
+
+	/**
+	* 设置调用微信支付API的机器IP 
+	* @param string $value 
+	**/
+	public function SetSpbill_create_ip($value)
+	{
+		$this->values['spbill_create_ip'] = $value;
+	}
+	/**
+	* 获取调用微信支付API的机器IP 的值
+	* @return 值
+	**/
+	public function GetSpbill_create_ip()
+	{
+		return $this->values['spbill_create_ip'];
+	}
+	/**
+	* 判断调用微信支付API的机器IP 是否存在
+	* @return true 或 false
+	**/
+	public function IsSpbill_create_ipSet()
+	{
+		return array_key_exists('spbill_create_ip', $this->values);
+	}
+
+	/**
+	* 设置订单生成时间,格式为yyyyMMddHHmmss,如2009年12月25日9点10分10秒表示为20091225091010。详见时间规则
+	* @param string $value 
+	**/
+	public function SetTime_start($value)
+	{
+		$this->values['time_start'] = $value;
+	}
+	/**
+	* 获取订单生成时间,格式为yyyyMMddHHmmss,如2009年12月25日9点10分10秒表示为20091225091010。详见时间规则的值
+	* @return 值
+	**/
+	public function GetTime_start()
+	{
+		return $this->values['time_start'];
+	}
+	/**
+	* 判断订单生成时间,格式为yyyyMMddHHmmss,如2009年12月25日9点10分10秒表示为20091225091010。详见时间规则是否存在
+	* @return true 或 false
+	**/
+	public function IsTime_startSet()
+	{
+		return array_key_exists('time_start', $this->values);
+	}
+
+
+	/**
+	* 设置订单失效时间,格式为yyyyMMddHHmmss,如2009年12月27日9点10分10秒表示为20091227091010。详见时间规则
+	* @param string $value 
+	**/
+	public function SetTime_expire($value)
+	{
+		$this->values['time_expire'] = $value;
+	}
+	/**
+	* 获取订单失效时间,格式为yyyyMMddHHmmss,如2009年12月27日9点10分10秒表示为20091227091010。详见时间规则的值
+	* @return 值
+	**/
+	public function GetTime_expire()
+	{
+		return $this->values['time_expire'];
+	}
+	/**
+	* 判断订单失效时间,格式为yyyyMMddHHmmss,如2009年12月27日9点10分10秒表示为20091227091010。详见时间规则是否存在
+	* @return true 或 false
+	**/
+	public function IsTime_expireSet()
+	{
+		return array_key_exists('time_expire', $this->values);
+	}
+
+
+	/**
+	* 设置商品标记,代金券或立减优惠功能的参数,说明详见代金券或立减优惠
+	* @param string $value 
+	**/
+	public function SetGoods_tag($value)
+	{
+		$this->values['goods_tag'] = $value;
+	}
+	/**
+	* 获取商品标记,代金券或立减优惠功能的参数,说明详见代金券或立减优惠的值
+	* @return 值
+	**/
+	public function GetGoods_tag()
+	{
+		return $this->values['goods_tag'];
+	}
+	/**
+	* 判断商品标记,代金券或立减优惠功能的参数,说明详见代金券或立减优惠是否存在
+	* @return true 或 false
+	**/
+	public function IsGoods_tagSet()
+	{
+		return array_key_exists('goods_tag', $this->values);
+	}
+
+
+	/**
+	* 设置扫码支付授权码,设备读取用户微信中的条码或者二维码信息
+	* @param string $value 
+	**/
+	public function SetAuth_code($value)
+	{
+		$this->values['auth_code'] = $value;
+	}
+	/**
+	* 获取扫码支付授权码,设备读取用户微信中的条码或者二维码信息的值
+	* @return 值
+	**/
+	public function GetAuth_code()
+	{
+		return $this->values['auth_code'];
+	}
+	/**
+	* 判断扫码支付授权码,设备读取用户微信中的条码或者二维码信息是否存在
+	* @return true 或 false
+	**/
+	public function IsAuth_codeSet()
+	{
+		return array_key_exists('auth_code', $this->values);
+	}
+}
+
+/**
+ * 
+ * 撤销输入对象
+ * @author widyhu
+ *
+ */
+class WxPayReverse extends WxPayDataBase
+{
+	/**
+	* 设置微信分配的公众账号ID
+	* @param string $value 
+	**/
+	public function SetAppid($value)
+	{
+		$this->values['appid'] = $value;
+	}
+	/**
+	* 获取微信分配的公众账号ID的值
+	* @return 值
+	**/
+	public function GetAppid()
+	{
+		return $this->values['appid'];
+	}
+	/**
+	* 判断微信分配的公众账号ID是否存在
+	* @return true 或 false
+	**/
+	public function IsAppidSet()
+	{
+		return array_key_exists('appid', $this->values);
+	}
+
+
+	/**
+	* 设置微信支付分配的商户号
+	* @param string $value 
+	**/
+	public function SetMch_id($value)
+	{
+		$this->values['mch_id'] = $value;
+	}
+	/**
+	* 获取微信支付分配的商户号的值
+	* @return 值
+	**/
+	public function GetMch_id()
+	{
+		return $this->values['mch_id'];
+	}
+	/**
+	* 判断微信支付分配的商户号是否存在
+	* @return true 或 false
+	**/
+	public function IsMch_idSet()
+	{
+		return array_key_exists('mch_id', $this->values);
+	}
+
+
+	/**
+	* 设置微信的订单号,优先使用
+	* @param string $value 
+	**/
+	public function SetTransaction_id($value)
+	{
+		$this->values['transaction_id'] = $value;
+	}
+	/**
+	* 获取微信的订单号,优先使用的值
+	* @return 值
+	**/
+	public function GetTransaction_id()
+	{
+		return $this->values['transaction_id'];
+	}
+	/**
+	* 判断微信的订单号,优先使用是否存在
+	* @return true 或 false
+	**/
+	public function IsTransaction_idSet()
+	{
+		return array_key_exists('transaction_id', $this->values);
+	}
+
+
+	/**
+	* 设置商户系统内部的订单号,transaction_id、out_trade_no二选一,如果同时存在优先级:transaction_id> out_trade_no
+	* @param string $value 
+	**/
+	public function SetOut_trade_no($value)
+	{
+		$this->values['out_trade_no'] = $value;
+	}
+	/**
+	* 获取商户系统内部的订单号,transaction_id、out_trade_no二选一,如果同时存在优先级:transaction_id> out_trade_no的值
+	* @return 值
+	**/
+	public function GetOut_trade_no()
+	{
+		return $this->values['out_trade_no'];
+	}
+	/**
+	* 判断商户系统内部的订单号,transaction_id、out_trade_no二选一,如果同时存在优先级:transaction_id> out_trade_no是否存在
+	* @return true 或 false
+	**/
+	public function IsOut_trade_noSet()
+	{
+		return array_key_exists('out_trade_no', $this->values);
+	}
+
+
+	/**
+	* 设置随机字符串,不长于32位。推荐随机数生成算法
+	* @param string $value 
+	**/
+	public function SetNonce_str($value)
+	{
+		$this->values['nonce_str'] = $value;
+	}
+	/**
+	* 获取随机字符串,不长于32位。推荐随机数生成算法的值
+	* @return 值
+	**/
+	public function GetNonce_str()
+	{
+		return $this->values['nonce_str'];
+	}
+	/**
+	* 判断随机字符串,不长于32位。推荐随机数生成算法是否存在
+	* @return true 或 false
+	**/
+	public function IsNonce_strSet()
+	{
+		return array_key_exists('nonce_str', $this->values);
+	}
+}
+
+/**
+ * 
+ * 提交JSAPI输入对象
+ * @author widyhu
+ *
+ */
+class WxPayJsApiPay extends WxPayDataBase
+{
+	/**
+	* 设置微信分配的公众账号ID
+	* @param string $value 
+	**/
+	public function SetAppid($value)
+	{
+		$this->values['appId'] = $value;
+	}
+	/**
+	* 获取微信分配的公众账号ID的值
+	* @return 值
+	**/
+	public function GetAppid()
+	{
+		return $this->values['appId'];
+	}
+	/**
+	* 判断微信分配的公众账号ID是否存在
+	* @return true 或 false
+	**/
+	public function IsAppidSet()
+	{
+		return array_key_exists('appId', $this->values);
+	}
+
+
+	/**
+	* 设置支付时间戳
+	* @param string $value 
+	**/
+	public function SetTimeStamp($value)
+	{
+		$this->values['timeStamp'] = $value;
+	}
+	/**
+	* 获取支付时间戳的值
+	* @return 值
+	**/
+	public function GetTimeStamp()
+	{
+		return $this->values['timeStamp'];
+	}
+	/**
+	* 判断支付时间戳是否存在
+	* @return true 或 false
+	**/
+	public function IsTimeStampSet()
+	{
+		return array_key_exists('timeStamp', $this->values);
+	}
+	
+	/**
+	* 随机字符串
+	* @param string $value 
+	**/
+	public function SetNonceStr($value)
+	{
+		$this->values['nonceStr'] = $value;
+	}
+	/**
+	* 获取notify随机字符串值
+	* @return 值
+	**/
+	public function GetReturn_code()
+	{
+		return $this->values['nonceStr'];
+	}
+	/**
+	* 判断随机字符串是否存在
+	* @return true 或 false
+	**/
+	public function IsReturn_codeSet()
+	{
+		return array_key_exists('nonceStr', $this->values);
+	}
+
+
+	/**
+	* 设置订单详情扩展字符串
+	* @param string $value 
+	**/
+	public function SetPackage($value)
+	{
+		$this->values['package'] = $value;
+	}
+	/**
+	* 获取订单详情扩展字符串的值
+	* @return 值
+	**/
+	public function GetPackage()
+	{
+		return $this->values['package'];
+	}
+	/**
+	* 判断订单详情扩展字符串是否存在
+	* @return true 或 false
+	**/
+	public function IsPackageSet()
+	{
+		return array_key_exists('package', $this->values);
+	}
+	
+	/**
+	* 设置签名方式
+	* @param string $value 
+	**/
+	public function SetSignType($value)
+	{
+		$this->values['signType'] = $value;
+	}
+	/**
+	* 获取签名方式
+	* @return 值
+	**/
+	public function GetSignType()
+	{
+		return $this->values['signType'];
+	}
+	/**
+	* 判断签名方式是否存在
+	* @return true 或 false
+	**/
+	public function IsSignTypeSet()
+	{
+		return array_key_exists('signType', $this->values);
+	}
+	
+	/**
+	* 设置签名方式
+	* @param string $value 
+	**/
+	public function SetPaySign($value)
+	{
+		$this->values['paySign'] = $value;
+	}
+	/**
+	* 获取签名方式
+	* @return 值
+	**/
+	public function GetPaySign()
+	{
+		return $this->values['paySign'];
+	}
+	/**
+	* 判断签名方式是否存在
+	* @return true 或 false
+	**/
+	public function IsPaySignSet()
+	{
+		return array_key_exists('paySign', $this->values);
+	}
+}
+
+/**
+ * 
+ * 扫码支付模式一生成二维码参数
+ * @author widyhu
+ *
+ */
+class WxPayBizPayUrl extends WxPayDataBaseSignMd5
+{
+		/**
+	* 设置微信分配的公众账号ID
+	* @param string $value 
+	**/
+	public function SetAppid($value)
+	{
+		$this->values['appid'] = $value;
+	}
+	/**
+	* 获取微信分配的公众账号ID的值
+	* @return 值
+	**/
+	public function GetAppid()
+	{
+		return $this->values['appid'];
+	}
+	/**
+	* 判断微信分配的公众账号ID是否存在
+	* @return true 或 false
+	**/
+	public function IsAppidSet()
+	{
+		return array_key_exists('appid', $this->values);
+	}
+
+
+	/**
+	* 设置微信支付分配的商户号
+	* @param string $value 
+	**/
+	public function SetMch_id($value)
+	{
+		$this->values['mch_id'] = $value;
+	}
+	/**
+	* 获取微信支付分配的商户号的值
+	* @return 值
+	**/
+	public function GetMch_id()
+	{
+		return $this->values['mch_id'];
+	}
+	/**
+	* 判断微信支付分配的商户号是否存在
+	* @return true 或 false
+	**/
+	public function IsMch_idSet()
+	{
+		return array_key_exists('mch_id', $this->values);
+	}
+	
+	/**
+	* 设置支付时间戳
+	* @param string $value 
+	**/
+	public function SetTime_stamp($value)
+	{
+		$this->values['time_stamp'] = $value;
+	}
+	/**
+	* 获取支付时间戳的值
+	* @return 值
+	**/
+	public function GetTime_stamp()
+	{
+		return $this->values['time_stamp'];
+	}
+	/**
+	* 判断支付时间戳是否存在
+	* @return true 或 false
+	**/
+	public function IsTime_stampSet()
+	{
+		return array_key_exists('time_stamp', $this->values);
+	}
+	
+	/**
+	* 设置随机字符串
+	* @param string $value 
+	**/
+	public function SetNonce_str($value)
+	{
+		$this->values['nonce_str'] = $value;
+	}
+	/**
+	* 获取随机字符串的值
+	* @return 值
+	**/
+	public function GetNonce_str()
+	{
+		return $this->values['nonce_str'];
+	}
+	/**
+	* 判断随机字符串是否存在
+	* @return true 或 false
+	**/
+	public function IsNonce_strSet()
+	{
+		return array_key_exists('nonce_str', $this->values);
+	}
+	
+	/**
+	* 设置商品ID
+	* @param string $value 
+	**/
+	public function SetProduct_id($value)
+	{
+		$this->values['product_id'] = $value;
+	}
+	/**
+	* 获取商品ID的值
+	* @return 值
+	**/
+	public function GetProduct_id()
+	{
+		return $this->values['product_id'];
+	}
+	/**
+	* 判断商品ID是否存在
+	* @return true 或 false
+	**/
+	public function IsProduct_idSet()
+	{
+		return array_key_exists('product_id', $this->values);
+	}
+}
+

+ 13 - 0
sdk/wechat/WxPay.Exception.php

@@ -0,0 +1,13 @@
+<?php
+/**
+ * 
+ * 微信支付API异常类
+ * @author widyhu
+ *
+ */
+class WxPayException extends Exception {
+	public function errorMessage()
+	{
+		return $this->getMessage();
+	}
+}

+ 229 - 0
sdk/wechat/WxPay.JsApiPay.php

@@ -0,0 +1,229 @@
+<?php
+/**
+*
+* example目录下为简单的支付样例,仅能用于搭建快速体验微信支付使用
+* 样例的作用仅限于指导如何使用sdk,在安全上面仅做了简单处理, 复制使用样例代码时请慎重
+* 请勿直接直接使用样例对外提供服务
+* 
+**/
+require_once "WxPay.Api.php";
+/**
+ * 
+ * JSAPI支付实现类
+ * 该类实现了从微信公众平台获取code、通过code获取openid和access_token、
+ * 生成jsapi支付js接口所需的参数、生成获取共享收货地址所需的参数
+ * 
+ * 该类是微信支付提供的样例程序,商户可根据自己的需求修改,或者使用lib中的api自行开发
+ * 
+ * @author widy
+ *
+ */
+class JsApiPay
+{
+	/**
+	 * 
+	 * 网页授权接口微信服务器返回的数据,返回样例如下
+	 * {
+	 *  "access_token":"ACCESS_TOKEN",
+	 *  "expires_in":7200,
+	 *  "refresh_token":"REFRESH_TOKEN",
+	 *  "openid":"OPENID",
+	 *  "scope":"SCOPE",
+	 *  "unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
+	 * }
+	 * 其中access_token可用于获取共享收货地址
+	 * openid是微信支付jsapi支付接口必须的参数
+	 * @var array
+	 */
+	public $data = null;
+
+	public function __construct($config)
+	{
+		$this->config = $config;
+	}
+	
+	/**
+	 * 
+	 * 通过跳转获取用户的openid,跳转流程如下:
+	 * 1、设置自己需要调回的url及其其他参数,跳转到微信服务器https://open.weixin.qq.com/connect/oauth2/authorize
+	 * 2、微信服务处理完成之后会跳转回用户redirect_uri地址,此时会带上一些参数,如:code
+	 * 
+	 * @return 用户的openid
+	 */
+	public function GetOpenid()
+	{
+		//通过code获得openid
+		if (!isset($_GET['code'])){
+			//触发微信返回code码
+			$baseUrl = urlencode('http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'].$_SERVER['QUERY_STRING']);
+			$url = $this->_CreateOauthUrlForCode($baseUrl);
+			Header("Location: $url");
+			exit();
+		} else {
+			//获取code码,以获取openid
+		    $code = $_GET['code'];
+			$openid = $this->getOpenidFromMp($code);
+			return $openid;
+		}
+	}
+	
+	/**
+	 * 
+	 * 获取jsapi支付的参数
+	 * @param array $UnifiedOrderResult 统一支付接口返回的数据
+	 * @throws WxPayException
+	 * 
+	 * @return json数据,可直接填入js函数作为参数
+	 */
+	public function GetJsApiParameters($UnifiedOrderResult)
+	{
+		if(!array_key_exists("appid", $UnifiedOrderResult)
+		|| !array_key_exists("prepay_id", $UnifiedOrderResult)
+		|| $UnifiedOrderResult['prepay_id'] == "")
+		{
+			throw new WxPayException("参数错误");
+		}
+
+		$jsapi = new WxPayJsApiPay();
+		$jsapi->SetAppid($UnifiedOrderResult["appid"]);
+		$timeStamp = time();
+		$jsapi->SetTimeStamp("$timeStamp");
+		$jsapi->SetNonceStr(WxPayApi::getNonceStr());
+		$jsapi->SetPackage("prepay_id=" . $UnifiedOrderResult['prepay_id']);
+
+		$jsapi->SetPaySign($jsapi->MakeSign($this->config));
+		$parameters = json_encode($jsapi->GetValues());
+		return $parameters;
+	}
+	
+	/**
+	 * 
+	 * 通过code从工作平台获取openid机器access_token
+	 * @param string $code 微信跳转回来带上的code
+	 * 
+	 * @return openid
+	 */
+	public function GetOpenidFromMp($code)
+	{
+		$url = $this->__CreateOauthUrlForOpenid($code);
+
+		//初始化curl
+		$ch = curl_init();
+		$curlVersion = curl_version();
+		$ua = "WXPaySDK/3.0.9 (".PHP_OS.") PHP/".PHP_VERSION." CURL/".$curlVersion['version']." "
+		.$this->config->GetMerchantId();
+
+		//设置超时
+		curl_setopt($ch, CURLOPT_TIMEOUT, $this->curl_timeout);
+		curl_setopt($ch, CURLOPT_URL, $url);
+		curl_setopt($ch, CURLOPT_SSL_VERIFYPEER,FALSE);
+		curl_setopt($ch, CURLOPT_SSL_VERIFYHOST,FALSE);
+		curl_setopt($ch, CURLOPT_USERAGENT, $ua);
+		curl_setopt($ch, CURLOPT_HEADER, FALSE);
+		curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
+
+		$proxyHost = "0.0.0.0";
+		$proxyPort = 0;
+		$this->config->GetProxy($proxyHost, $proxyPort);
+		if($proxyHost != "0.0.0.0" && $proxyPort != 0){
+			curl_setopt($ch,CURLOPT_PROXY, $proxyHost);
+			curl_setopt($ch,CURLOPT_PROXYPORT, $proxyPort);
+		}
+		//运行curl,结果以jason形式返回
+		$res = curl_exec($ch);
+		curl_close($ch);
+		//取出openid
+		$data = json_decode($res,true);
+		$this->data = $data;
+		$openid = $data['openid'];
+		return $openid;
+	}
+	
+	/**
+	 * 
+	 * 拼接签名字符串
+	 * @param array $urlObj
+	 * 
+	 * @return 返回已经拼接好的字符串
+	 */
+	private function ToUrlParams($urlObj)
+	{
+		$buff = "";
+		foreach ($urlObj as $k => $v)
+		{
+			if($k != "sign"){
+				$buff .= $k . "=" . $v . "&";
+			}
+		}
+		
+		$buff = trim($buff, "&");
+		return $buff;
+	}
+	
+	/**
+	 * 
+	 * 获取地址js参数
+	 * 
+	 * @return 获取共享收货地址js函数需要的参数,json格式可以直接做参数使用
+	 */
+	public function GetEditAddressParameters()
+	{	
+		$getData = $this->data;
+		$data = array();
+		$data["appid"] = $this->config->GetAppId();
+		$data["url"] = "http://".$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
+		$time = time();
+		$data["timestamp"] = "$time";
+		$data["noncestr"] = WxPayApi::getNonceStr();
+		$data["accesstoken"] = $getData["access_token"];
+		ksort($data);
+		$params = $this->ToUrlParams($data);
+		$addrSign = sha1($params);
+		
+		$afterData = array(
+			"addrSign" => $addrSign,
+			"signType" => "sha1",
+			"scope" => "jsapi_address",
+			"appId" => $this->config->GetAppId(),
+			"timeStamp" => $data["timestamp"],
+			"nonceStr" => $data["noncestr"]
+		);
+		$parameters = json_encode($afterData);
+		return $parameters;
+	}
+	
+	/**
+	 * 
+	 * 构造获取code的url连接
+	 * @param string $redirectUrl 微信服务器回跳的url,需要url编码
+	 * 
+	 * @return 返回构造好的url
+	 */
+	private function _CreateOauthUrlForCode($redirectUrl)
+	{
+		$urlObj["appid"] = $this->config->GetAppId();
+		$urlObj["redirect_uri"] = "$redirectUrl";
+		$urlObj["response_type"] = "code";
+		$urlObj["scope"] = "snsapi_base";
+		$urlObj["state"] = "STATE"."#wechat_redirect";
+		$bizString = $this->ToUrlParams($urlObj);
+		return "https://open.weixin.qq.com/connect/oauth2/authorize?".$bizString;
+	}
+	
+	/**
+	 * 
+	 * 构造获取open和access_toke的url地址
+	 * @param string $code,微信跳转带回的code
+	 * 
+	 * @return 请求的url
+	 */
+	private function __CreateOauthUrlForOpenid($code)
+	{
+		$urlObj["appid"] = $this->config->GetAppId();
+		$urlObj["secret"] = $this->config->GetAppSecret();
+		$urlObj["code"] = $code;
+		$urlObj["grant_type"] = "authorization_code";
+		$bizString = $this->ToUrlParams($urlObj);
+		return "https://api.weixin.qq.com/sns/oauth2/access_token?".$bizString;
+	}
+}

+ 167 - 0
sdk/wechat/WxPay.MicroPay.php

@@ -0,0 +1,167 @@
+<?php
+/**
+*
+* example目录下为简单的支付样例,仅能用于搭建快速体验微信支付使用
+* 样例的作用仅限于指导如何使用sdk,在安全上面仅做了简单处理, 复制使用样例代码时请慎重
+* 请勿直接直接使用样例对外提供服务
+* 
+**/
+require_once "WxPay.Api.php";
+/**
+ * 
+ * 刷卡支付实现类
+ * 该类实现了一个刷卡支付的流程,流程如下:
+ * 1、提交刷卡支付
+ * 2、根据返回结果决定是否需要查询订单,如果查询之后订单还未变则需要返回查询(一般反复查10次)
+ * 3、如果反复查询10订单依然不变,则发起撤销订单
+ * 4、撤销订单需要循环撤销,一直撤销成功为止(注意循环次数,建议10次)
+ * 
+ * 该类是微信支付提供的样例程序,商户可根据自己的需求修改,或者使用lib中的api自行开发,为了防止
+ * 查询时hold住后台php进程,商户查询和撤销逻辑可在前端调用
+ * 
+ * @author widy
+ *
+ */
+class MicroPay
+{
+	public function __construct($config)
+	{
+		$this->config = $config;
+	}
+
+	/**
+	 * 
+	 * 提交刷卡支付,并且确认结果,接口比较慢
+	 * @param WxPayMicroPay $microPayInput
+	 * @throws WxpayException
+	 * @return 返回查询接口的结果
+	 */
+	public function pay($microPayInput)
+	{
+		//①、提交被扫支付
+		$result = WxPayApi::micropay($this->config, $microPayInput, 5);
+		//如果返回成功
+		if(!array_key_exists("return_code", $result)
+			|| !array_key_exists("result_code", $result))
+		{
+			echo "接口调用失败,请确认是否输入是否有误!";
+			throw new WxPayException("接口调用失败!");
+		}
+		
+		//取订单号
+		$out_trade_no = $microPayInput->GetOut_trade_no();
+		
+		//②、接口调用成功,明确返回调用失败
+		if($result["return_code"] == "SUCCESS" &&
+		   $result["result_code"] == "FAIL" && 
+		   $result["err_code"] != "USERPAYING" && 
+		   $result["err_code"] != "SYSTEMERROR")
+		{
+			return false;
+		}
+
+		//③、确认支付是否成功
+		$queryTimes = 10;
+		while($queryTimes > 0)
+		{
+			$succResult = 0;
+			$queryResult = $this->query($out_trade_no, $succResult);
+			//如果需要等待1s后继续
+			if($succResult == 2){
+				sleep(2);
+				continue;
+			} else if($succResult == 1){//查询成功
+				return $queryResult;
+			} else {//订单交易失败
+				break;
+			}
+		}
+		
+		//④、次确认失败,则撤销订单
+		if(!$this->cancel($out_trade_no))
+		{
+			throw new WxpayException("撤销单失败!");
+		}
+
+		return false;
+	}
+	
+	/**
+	 * 
+	 * 查询订单情况
+	 * @param string $out_trade_no  商户订单号
+	 * @param int $succCode         查询订单结果
+	 * @return 0 订单不成功,1表示订单成功,2表示继续等待
+	 */
+	public function query($out_trade_no, &$succCode)
+	{
+		$queryOrderInput = new WxPayOrderQuery();
+		$queryOrderInput->SetOut_trade_no($out_trade_no);
+		try{
+			$result = WxPayApi::orderQuery($this->config, $queryOrderInput);
+		} catch(Exception $e) {
+			Log::ERROR(json_encode($e));
+		}
+		if($result["return_code"] == "SUCCESS" 
+			&& $result["result_code"] == "SUCCESS")
+		{
+			//支付成功
+			if($result["trade_state"] == "SUCCESS"){
+				$succCode = 1;
+			   	return $result;
+			}
+			//用户支付中
+			else if($result["trade_state"] == "USERPAYING"){
+				$succCode = 2;
+				return false;
+			}
+		}
+		
+		//如果返回错误码为“此交易订单号不存在”则直接认定失败
+		if($result["err_code"] == "ORDERNOTEXIST")
+		{
+			$succCode = 0;
+		} else{
+			//如果是系统错误,则后续继续
+			$succCode = 2;
+		}
+		return false;
+	}
+	
+	/**
+	 * 
+	 * 撤销订单,如果失败会重复调用10次
+	 * @param string $out_trade_no
+	 * @param 调用深度 $depth
+	 */
+	public function cancel($out_trade_no, $depth = 0)
+	{
+		try {
+			if($depth > 10){
+				return false;
+			}
+			
+			$clostOrder = new WxPayReverse();
+			$clostOrder->SetOut_trade_no($out_trade_no);
+
+			$result = WxPayApi::reverse($this->config, $clostOrder);
+
+			
+			//接口调用失败
+			if($result["return_code"] != "SUCCESS"){
+				return false;
+			}
+			
+			//如果结果为success且不需要重新调用撤销,则表示撤销成功
+			if($result["result_code"] != "SUCCESS" 
+				&& $result["recall"] == "N"){
+				return true;
+			} else if($result["recall"] == "Y") {
+				return $this->cancel($out_trade_no, ++$depth);
+			}
+		} catch(Exception $e) {
+			Log::ERROR(json_encode($e));
+		}
+		return false;
+	}
+}

+ 76 - 0
sdk/wechat/WxPay.NativePay.php

@@ -0,0 +1,76 @@
+<?php
+/**
+*
+* example目录下为简单的支付样例,仅能用于搭建快速体验微信支付使用
+* 样例的作用仅限于指导如何使用sdk,在安全上面仅做了简单处理, 复制使用样例代码时请慎重
+* 请勿直接直接使用样例对外提供服务
+* 
+**/
+require_once "WxPay.Api.php";
+
+/**
+ * 
+ * 刷卡支付实现类
+ * @author widyhu
+ *
+ */
+class NativePay
+{
+	public function __construct($config)
+	{
+		$this->config = $config;
+	}
+	/**
+	 * 
+	 * 生成扫描支付URL,模式一
+	 * @param BizPayUrlInput $bizUrlInfo
+	 */
+	public function GetPrePayUrl($productId)
+	{
+		$biz = new WxPayBizPayUrl();
+		$biz->SetProduct_id($productId);
+		try{
+			$values = WxpayApi::bizpayurl($this->config, $biz);
+		} catch(Exception $e) {
+			Log::ERROR(json_encode($e));
+		}
+		$url = "weixin://wxpay/bizpayurl?" . $this->ToUrlParams($values);
+		return $url;
+	}
+	
+	/**
+	 * 
+	 * 参数数组转换为url参数
+	 * @param array $urlObj
+	 */
+	private function ToUrlParams($urlObj)
+	{
+		$buff = "";
+		foreach ($urlObj as $k => $v)
+		{
+			$buff .= $k . "=" . $v . "&";
+		}
+		
+		$buff = trim($buff, "&");
+		return $buff;
+	}
+	
+	/**
+	 * 
+	 * 生成直接支付url,支付url有效期为2小时,模式二
+	 * @param UnifiedOrderInput $input
+	 */
+	public function GetPayUrl($input)
+	{
+		if($input->GetTrade_type() == "NATIVE")
+		{
+			try{
+				$result = WxPayApi::unifiedOrder($this->config, $input);
+				return $result;
+			} catch(Exception $e) {
+				Log::ERROR(json_encode($e));
+			}
+		}
+		return false;
+	}
+}

+ 105 - 0
sdk/wechat/WxPay.Notify.php

@@ -0,0 +1,105 @@
+<?php
+/**
+ * 
+ * 回调基础类
+ * @author widyhu
+ *
+ */
+class WxPayNotify extends WxPayNotifyReply
+{
+	private $config = null;
+	/**
+	 * 
+	 * 回调入口
+	 * @param bool $needSign  是否需要签名返回
+	 */
+	final public function Handle($config, $needSign = true)
+	{
+		$this->config = $config;
+		$msg = "OK";
+		//当返回false的时候,表示notify中调用NotifyCallBack回调失败获取签名校验失败,此时直接回复失败
+		$result = WxpayApi::notify($config, array($this, 'NotifyCallBack'), $msg);
+		if($result == false){
+			$this->SetReturn_code("FAIL");
+			$this->SetReturn_msg($msg);
+			$this->ReplyNotify(false);
+			return;
+		} else {
+			//该分支在成功回调到NotifyCallBack方法,处理完成之后流程
+			$this->SetReturn_code("SUCCESS");
+			$this->SetReturn_msg("OK");
+		}
+		$this->ReplyNotify($needSign);
+	}
+	
+	/**
+	 * 
+	 * 回调方法入口,子类可重写该方法
+	 	//TODO 1、进行参数校验
+		//TODO 2、进行签名验证
+		//TODO 3、处理业务逻辑
+	 * 注意:
+	 * 1、微信回调超时时间为2s,建议用户使用异步处理流程,确认成功之后立刻回复微信服务器
+	 * 2、微信服务器在调用失败或者接到回包为非确认包的时候,会发起重试,需确保你的回调是可以重入
+	 * @param WxPayNotifyResults $objData 回调解释出的参数
+	 * @param WxPayConfigInterface $config
+	 * @param string $msg 如果回调处理失败,可以将错误信息输出到该方法
+	 * @return true回调出来完成不需要继续回调,false回调处理未完成需要继续回调
+	 */
+	public function NotifyProcess($objData, $config, &$msg)
+	{
+		//TODO 用户基础该类之后需要重写该方法,成功的时候返回true,失败返回false
+		return false;
+	}
+
+	/**
+	*
+	* 业务可以继承该方法,打印XML方便定位.
+	* @param string $xmlData 返回的xml参数
+	*
+	**/
+	public function LogAfterProcess($xmlData)
+	{
+		return;
+	}
+	
+	/**
+	 * 
+	 * notify回调方法,该方法中需要赋值需要输出的参数,不可重写
+	 * @param array $data
+	 * @return true回调出来完成不需要继续回调,false回调处理未完成需要继续回调
+	 */
+	final public function NotifyCallBack($data)
+	{
+		$msg = "OK";
+		$result = $this->NotifyProcess($data, $this->config, $msg);
+		
+		if($result == true){
+			$this->SetReturn_code("SUCCESS");
+			$this->SetReturn_msg("OK");
+		} else {
+			$this->SetReturn_code("FAIL");
+			$this->SetReturn_msg($msg);
+		}
+		return $result;
+	}
+	
+	/**
+	 * 
+	 * 回复通知
+	 * @param bool $needSign 是否需要签名输出
+	 */
+	final private function ReplyNotify($needSign = true)
+	{
+		//如果需要签名
+		if($needSign == true && 
+			$this->GetReturn_code() == "SUCCESS")
+		{
+			$this->SetSign($this->config);
+		}
+
+		$xml = $this->ToXml();
+		$this->LogAfterProcess($xml);
+		WxpayApi::replyNotify($xml);
+	}
+}

+ 115 - 0
src/Api.php

@@ -0,0 +1,115 @@
+<?php namespace Pay\Src;
+
+use Dever;
+
+class Api
+{
+	/**
+	 * 发起支付 下单 获取预支付信息
+	 *
+	 * @return mixed
+	 */
+	public function get($type = 1, $param = array())
+	{
+		$this->init($param);
+		if ($this->order_id > 0) {
+			$pay = Dever::db('pay/order')->one(array('order_id' => $this->order_id));
+			if ($pay && $pay['status'] == 1 && $pay['param']) {
+				$order = Dever::array_decode($pay['param']);
+				return array($order_id, $order);
+			}
+		}
+		return $this->method->order($this->account_id, $this->uid, $this->username, $this->product_id, $this->name, $this->cash, $this->openid, $type);
+	}
+
+	/**
+	 * 发起支付 用于页面支付(jsapi、小程序、支付宝h5等)
+	 *
+	 * @return mixed
+	 */
+	public function page()
+	{
+		if (!$this->refer) {
+			Dever::alert('没有回调url');
+		}
+		return $this->method->page($this->get(1), $this->refer);
+	}
+
+	/**
+	 * 发起支付 用于扫码支付
+	 *
+	 * @return mixed
+	 */
+	public function qrcode()
+	{
+		$url = $this->method->qrcode($this->get(2), $this->refer);
+		Dever::apply('sdk/qrcode');
+		return \QRcode::png($url);
+	}
+
+	/**
+	 * 初始化 设置参数
+	 *
+	 * @return mixed
+	 */
+	private function init($param = array())
+	{
+		$this->account_id = $this->getParam($param, 'account_id');
+		$this->uid = $this->getParam($param, 'uid');
+		$this->username = $this->getParam($param, 'username');
+		$this->product_id = $this->getParam($param, 'product_id');
+		$this->name = $this->getParam($param, 'name');
+		$this->cash = $this->getParam($param, 'cash');
+		$this->refer = $this->getParam($param, 'refer');
+		$this->order_id = $this->getParam($param, 'order_id');
+		$this->openid = $this->getParam($param, 'openid');
+
+		if (!$this->account_id) {
+			Dever::alert('没有账户信息');
+		}
+
+		if (!$this->uid || !$this->username) {
+			Dever::alert('没有用户信息');
+		}
+
+		if (!$this->product_id) {
+			Dever::alert('没有产品信息');
+		}
+
+		if (!$this->name) {
+			Dever::alert('没有支付信息');
+		}
+
+		if (!$this->cash) {
+			Dever::alert('没有支付金额');
+		}
+
+		return $this->pay();
+	}
+
+	/**
+	 * 初始化
+	 *
+	 * @return mixed
+	 */
+	private function getParam($param, $key)
+	{
+		if (isset($param[$key])) {
+			return $param[$key];
+		}
+		return Dever::input($key, false);
+	}
+
+	/**
+	 * 获取支付类
+	 *
+	 * @return mixed
+	 */
+	private function pay()
+	{
+		$pay = Dever::db('pay/account')->one($this->account_id);
+		$method = '\\Pay\\Lib\\' . ucwords($pay['type']);
+		$this->method = new $method($pay);
+		return $this;
+	}
+}