简介 ============================================ 接口名称:微信公众号支付接口 版本:V3.3 开发语言:PHP ======== 配置说明 =========================================== 1.【基本信息设置】 商户向微信提交
============================================
接口名称:微信公众号支付接口
版本:V3.3
开发语言:PHP
========
配置说明
===========================================
1.【基本信息设置】
商户向微信提交企业以及银行账户资料,商户功能审核通过后,可以获得帐户基本信息,找到本例程的配置文件「WxPay.pub.config.php」,配置好如下信息:
appId:微信公众号身份的唯一标识。审核通过后,在微信发送的邮件中查看。
Mchid:受理商ID,身份标识
Key:商户支付密钥Key。审核通过后,在微信发送的邮件中查看。
Appsecret:JSAPI接口中获取openid,审核后在公众平台开启开发模式后可查看。
2.【native支付链接设置】
native支付中,用户扫码后调微信会将productid和用户openid发送到商户设置的链接上,确保该链接与实际服务路径一致。本例程的响应服务为「./demo/native_call.php」
3.【JSAPI路径设置】
通过JSAPI发起支付的代码应该放置在商户设置的「支付授权目录」中。
并找到本例程的配置文件「WxPay.pub.config.php」,配置正确的路径。
4.【证书路径设置】
找到本例程的配置文件「WxPay.pub.config.php」,配置证书路径。
5.【异步通知url设置】
找到本例程的配置文件「WxPay.pub.config.php」,配置异步通知url。
6.【必须开启curl服务】
使用Crul需要修改服务器中php.ini文件的设置,找到php_curl.dll去掉前面的";"即可。
7.【设置curl超时时间】
本例程通过curl使用HTTP POST方法,此处可修改其超时时间,默认为30秒。找到本例程的配置文件「WxPay.pub.config.php」,配置curl超时时间。
============
代码文件结构
===========================================
wxpay_php
|-- README.txt---------------------使用说明文本
|-- WxPayHelper--------------------微信支付类库及常用文件
| |-- SDKRuntimeException.php----异常处理类
| |-- WxPay.pub.config.php-----------商户配置文件
| `-- WxPayPubHelper.php------------微信支付类库
|-- demo---------------------------例程
| |-- js_api_call.php------------JSAPI支付例程
| |-- native_call_qrcode.php-----native支付静态链接二维码例程
| |-- native_call.php------------native支付后台响应例程
| |-- native_call.log------------native支付后台响应日志
| |-- native_dynamic_qrcode.php--native支付动态链接二维码例程
| |-- notify_url.php-------------支付结果异步通知例程
| |-- notify_url.log-------------支付结果异步通知日志
| |-- order_query.php------------订单查询例程
| |-- refund.php-----------------退款例程
| |-- download_bill.php----------对账单例程
| |-- refund_query.php-----------退款查询例程
| |-- log_.php-------------------日志类
| `-- qrcode.js------------------二维码生成工具
`-- index.php
==============
微信支付帮助sdk
====================================================
1.每一个接口对应一个类。
2.常用工具(产生随机字符串、生成签名、以post方式提交xml、证书的使用等)封装成CommonUtil类。
3.接口分三种类型:请求型接口、响应型接口、其他。请求型接口是将参数封装成xml,以post方式提交到微信,微信响应结果;响应型接口则是响应微信的post请求。Wxpay_client_是请求型接口的基类。Wxpay_server_是响应型接口的基类。Wxpay_client_、Wxpay_server_都继承CommonUtil类
4.结构明细
【常用工具】--CommonUtil
trimString(),设置参数时需要用到的字符处理函数
createNoncestr(),产生随机字符串,不长于32位
formatBizQueryParaMap(),格式化参数,签名过程需要用到
getSign(),生成签名
arrayToXml(),array转xml
xmlToArray(),xml转 array
postXmlCurl(),以post方式提交xml到对应的接口url
postXmlSSLCurl(),使用证书,以post方式提交xml到对应的接口url
【请求型接口】--Wxpay_client_
统一支付接口----UnifiedOrder
订单查询接口----OrderQuery
退款申请接口----Refund
退款查询接口----RefundQuery
对账单接口------DownloadBill
短链接转换接口--ShortUrl
【响应型接口】--Wxpay_server_
通用通知接口----Notify
Native支付——请求商家获取商品信息接口--NativeCall
【其他】
静态链接二维码--NativeLink
JSAPI支付-------JsApi
1. [代码][PHP]代码
作者官网:www.wemallshop.com
2. [代码]SDKRuntimeException.php
<?php
class SDKRuntimeException extends Exception {
public function errorMessage()
{
return $this->getMessage();
}
}
?>
3. [代码]WxPay.pub.config.php
<?php
/**
* 配置账号信息
*/
class WxPayConf_pub
{
//=======【基本信息设置】=====================================
//微信公众号身份的唯一标识。审核通过后,在微信发送的邮件中查看
const APPID = '';
//受理商ID,身份标识
const MCHID = '';
//商户支付密钥Key。审核通过后,在微信发送的邮件中查看
const KEY = '';
//JSAPI接口中获取openid,审核后在公众平台开启开发模式后可查看
const APPSECRET = '';
//=======【JSAPI路径设置】===================================
//获取access_token过程中的跳转uri,通过跳转将code传入jsapi支付页面
const JS_API_CALL_URL = '';
//=======【证书路径设置】=====================================
//证书路径,注意应该填写绝对路径
const SSLCERT_PATH = '';
const SSLKEY_PATH = '';
//=======【异步通知url设置】===================================
//异步通知url,商户根据实际开发过程设定
const NOTIFY_URL = '';
//=======【curl超时设置】===================================
//本例程通过curl使用HTTP POST方法,此处可修改其超时时间,默认为30秒
const CURL_TIMEOUT = 30;
}
?>
4. [代码]WxPayPubHelper.php
<?php
/**
* 微信支付帮助库
* ====================================================
* 接口分三种类型:
* 【请求型接口】--Wxpay_client_
* 统一支付接口类--UnifiedOrder
* 订单查询接口--OrderQuery
* 退款申请接口--Refund
* 退款查询接口--RefundQuery
* 对账单接口--DownloadBill
* 短链接转换接口--ShortUrl
* 【响应型接口】--Wxpay_server_
* 通用通知接口--Notify
* Native支付——请求商家获取商品信息接口--NativeCall
* 【其他】
* 静态链接二维码--NativeLink
* JSAPI支付--JsApi
* =====================================================
* 【CommonUtil】常用工具:
* trimString(),设置参数时需要用到的字符处理函数
* createNoncestr(),产生随机字符串,不长于32位
* formatBizQueryParaMap(),格式化参数,签名过程需要用到
* getSign(),生成签名
* arrayToXml(),array转xml
* xmlToArray(),xml转 array
* postXmlCurl(),以post方式提交xml到对应的接口url
* postXmlSSLCurl(),使用证书,以post方式提交xml到对应的接口url
*/
include_once("SDKRuntimeException.php");
include_once("WxPay.pub.config.php");
/**
* 所有接口的基类
*/
class Common_util_pub
{
function __construct() {
}
function trimString($value)
{
$ret = null;
if (null != $value)
{
$ret = $value;
if (strlen($ret) == 0)
{
$ret = null;
}
}
return $ret;
}
/**
* 作用:产生随机字符串,不长于32位
*/
public function createNoncestr( $length = 32 )
{
$chars = "abcdefghijklmnopqrstuvwxyz0123456789";
$str ="";
for ( $i = 0; $i < $length; $i++ ) {
$str.= substr($chars, mt_rand(0, strlen($chars)-1), 1);
}
return $str;
}
/**
* 作用:格式化参数,签名过程需要使用
*/
function formatBizQueryParaMap($paraMap, $urlencode)
{
$buff = "";
ksort($paraMap);
foreach ($paraMap as $k => $v)
{
if($urlencode)
{
$v = urlencode($v);
}
//$buff .= strtolower($k) . "=" . $v . "&";
$buff .= $k . "=" . $v . "&";
}
$reqPar;
if (strlen($buff) > 0)
{
$reqPar = substr($buff, 0, strlen($buff)-1);
}
return $reqPar;
}
/**
* 作用:生成签名
*/
public function getSign($Obj)
{
foreach ($Obj as $k => $v)
{
$Parameters[$k] = $v;
}
//签名步骤一:按字典序排序参数
ksort($Parameters);
$String = $this->formatBizQueryParaMap($Parameters, false);
//echo '【string1】'.$String.'</br>';
//签名步骤二:在string后加入KEY
$String = $String."&key=".WxPayConf_pub::KEY;
//echo "【string2】".$String."</br>";
//签名步骤三:MD5加密
$String = md5($String);
//echo "【string3】 ".$String."</br>";
//签名步骤四:所有字符转为大写
$result_ = strtoupper($String);
//echo "【result】 ".$result_."</br>";
return $result_;
}
/**
* 作用:array转xml
*/
function arrayToXml($arr)
{
$xml = "<xml>";
foreach ($arr as $key=>$val)
{
if (is_numeric($val))
{
$xml.="<".$key.">".$val."</".$key.">";
}
else
$xml.="<".$key."><![CDATA[".$val."]]></".$key.">";
}
$xml.="</xml>";
return $xml;
}
/**
* 作用:将xml转为array
*/
public function xmlToArray($xml)
{
//将XML转为array
$array_data = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
return $array_data;
}
/**
* 作用:以post方式提交xml到对应的接口url
*/
public function postXmlCurl($xml,$url,$second=30)
{
//初始化curl
$ch = curl_init();
//设置超时
curl_setopt($ch, CURLOP_TIMEOUT, $second);
//这里设置代理,如果有的话
//curl_setopt($ch,CURLOPT_PROXY, '8.8.8.8');
//curl_setopt($ch,CURLOPT_PROXYPORT, 8080);
curl_setopt($ch,CURLOPT_URL, $url);
curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,FALSE);
curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,FALSE);
//设置header
curl_setopt($ch, CURLOPT_HEADER, FALSE);
//要求结果为字符串且输出到屏幕上
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
//post提交方式
curl_setopt($ch, CURLOPT_POST, TRUE);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
//运行curl
$data = curl_exec($ch);
curl_close($ch);
//返回结果
if($data)
{
curl_close($ch);
return $data;
}
else
{
$error = curl_errno($ch);
echo "curl出错,错误码:$error"."<br>";
echo "<a href='http://curl.haxx.se/libcurl/c/libcurl-errors.html'>错误原因查询</a></br>";
curl_close($ch);
return false;
}
}
/**
* 作用:使用证书,以post方式提交xml到对应的接口url
*/
function postXmlSSLCurl($xml,$url,$second=30)
{
$ch = curl_init();
//超时时间
curl_setopt($ch,CURLOPT_TIMEOUT,$second);
//这里设置代理,如果有的话
//curl_setopt($ch,CURLOPT_PROXY, '8.8.8.8');
//curl_setopt($ch,CURLOPT_PROXYPORT, 8080);
curl_setopt($ch,CURLOPT_URL, $url);
curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,FALSE);
curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,FALSE);
//设置header
curl_setopt($ch,CURLOPT_HEADER,FALSE);
//要求结果为字符串且输出到屏幕上
curl_setopt($ch,CURLOPT_RETURNTRANSFER,TRUE);
//设置证书
//使用证书:cert 与 key 分别属于两个.pem文件
//默认格式为PEM,可以注释
curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM');
curl_setopt($ch,CURLOPT_SSLCERT, WxPayConf_pub::SSLCERT_PATH);
//默认格式为PEM,可以注释
curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM');
curl_setopt($ch,CURLOPT_SSLKEY, WxPayConf_pub::SSLKEY_PATH);
//post提交方式
curl_setopt($ch,CURLOPT_POST, true);
curl_setopt($ch,CURLOPT_POSTFIELDS,$xml);
$data = curl_exec($ch);
//返回结果
if($data){
curl_close($ch);
return $data;
}
else {
$error = curl_errno($ch);
echo "curl出错,错误码:$error"."<br>";
echo "<a href='http://curl.haxx.se/libcurl/c/libcurl-errors.html'>错误原因查询</a></br>";
curl_close($ch);
return false;
}
}
/**
* 作用:打印数组
*/
function printErr($wording='',$err='')
{
print_r('<pre>');
echo $wording."</br>";
var_dump($err);
print_r('</pre>');
}
}
/**
* 请求型接口的基类
*/
class Wxpay_client_pub extends Common_util_pub
{
var $parameters;//请求参数,类型为关联数组
public $response;//微信返回的响应
public $result;//返回参数,类型为关联数组
var $url;//接口链接
var $curl_timeout;//curl超时时间
/**
* 作用:设置请求参数
*/
function setParameter($parameter, $parameterValue)
{
$this->parameters[$this->trimString($parameter)] = $this->trimString($parameterValue);
}
/**
* 作用:设置标配的请求参数,生成签名,生成接口参数xml
*/
function createXml()
{
$this->parameters["appid"] = WxPayConf_pub::APPID;//公众账号ID
$this->parameters["mch_id"] = WxPayConf_pub::MCHID;//商户号
$this->parameters["nonce_str"] = $this->createNoncestr();//随机字符串
$this->parameters["sign"] = $this->getSign($this->parameters);//签名
return $this->arrayToXml($this->parameters);
}
/**
* 作用:post请求xml
*/
function postXml()
{
$xml = $this->createXml();
$this->response = $this->postXmlCurl($xml,$this->url,$this->curl_timeout);
return $this->response;
}
/**
* 作用:使用证书post请求xml
*/
function postXmlSSL()
{
$xml = $this->createXml();
$this->response = $this->postXmlSSLCurl($xml,$this->url,$this->curl_timeout);
return $this->response;
}
/**
* 作用:获取结果,默认不使用证书
*/
function getResult()
{
$this->postXml();
$this->result = $this->xmlToArray($this->response);
return $this->result;
}
}
/**
* 统一支付接口类
*/
class UnifiedOrder_pub extends Wxpay_client_pub
{
function __construct()
{
//设置接口链接
$this->url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
//设置curl超时时间
$this->curl_timeout = WxPayConf_pub::CURL_TIMEOUT;
}
/**
* 生成接口参数xml
*/
function createXml()
{
try
{
//检测必填参数
if($this->parameters["out_trade_no"] == null)
{
throw new SDKRuntimeException("缺少统一支付接口必填参数out_trade_no!"."<br>");
}elseif($this->parameters["body"] == null){
throw new SDKRuntimeException("缺少统一支付接口必填参数body!"."<br>");
}elseif ($this->parameters["total_fee"] == null ) {
throw new SDKRuntimeException("缺少统一支付接口必填参数total_fee!"."<br>");
}elseif ($this->parameters["notify_url"] == null) {
throw new SDKRuntimeException("缺少统一支付接口必填参数notify_url!"."<br>");
}elseif ($this->parameters["trade_type"] == null) {
throw new SDKRuntimeException("缺少统一支付接口必填参数trade_type!"."<br>");
}elseif ($this->parameters["trade_type"] == "JSAPI" &&
$this->parameters["openid"] == NULL){
throw new SDKRuntimeException("统一支付接口中,缺少必填参数openid!trade_type为JSAPI时,openid为必填参数!"."<br>");
}
$this->parameters["appid"] = WxPayConf_pub::APPID;//公众账号ID
$this->parameters["mch_id"] = WxPayConf_pub::MCHID;//商户号
$this->parameters["spbill_create_ip"] = $_SERVER['REMOTE_ADDR'];//终端ip
$this->parameters["nonce_str"] = $this->createNoncestr();//随机字符串
$this->parameters["sign"] = $this->getSign($this->parameters);//签名
return $this->arrayToXml($this->parameters);
}catch (SDKRuntimeException $e)
{
die($e->errorMessage());
}
}
/**
* 获取prepay_id
*/
function getPrepayId()
{
$this->postXml();
$this->result = $this->xmlToArray($this->response);
$prepay_id = $this->result["prepay_id"];
return $prepay_id;
}
}
/**
* 订单查询接口
*/
class OrderQuery_pub extends Wxpay_client_pub
{
function __construct()
{
//设置接口链接
$this->url = "https://api.mch.weixin.qq.com/pay/orderquery";
//设置curl超时时间
$this->curl_timeout = WxPayConf_pub::CURL_TIMEOUT;
}
/**
* 生成接口参数xml
*/
function createXml()
{
try
{
//检测必填参数
if($this->parameters["out_trade_no"] == null &&
$this->parameters["transaction_id"] == null)
{
throw new SDKRuntimeException("订单查询接口中,out_trade_no、transaction_id至少填一个!"."<br>");
}
$this->parameters["appid"] = WxPayConf_pub::APPID;//公众账号ID
$this->parameters["mch_id"] = WxPayConf_pub::MCHID;//商户号
$this->parameters["nonce_str"] = $this->createNoncestr();//随机字符串
$this->parameters["sign"] = $this->getSign($this->parameters);//签名
return $this->arrayToXml($this->parameters);
}catch (SDKRuntimeException $e)
{
die($e->errorMessage());
}
}
}
/**
* 退款申请接口
*/
class Refund_pub extends Wxpay_client_pub
{
function __construct() {
//设置接口链接
$this->url = "https://api.mch.weixin.qq.com/secapi/pay/refund";
//设置curl超时时间
$this->curl_timeout = WxPayConf_pub::CURL_TIMEOUT;
}
/**
* 生成接口参数xml
*/
function createXml()
{
try
{
//检测必填参数
if($this->parameters["out_trade_no"] == null && $this->parameters["transaction_id"] == null) {
throw new SDKRuntimeException("退款申请接口中,out_trade_no、transaction_id至少填一个!"."<br>");
}elseif($this->parameters["out_refund_no"] == null){
throw new SDKRuntimeException("退款申请接口中,缺少必填参数out_refund_no!"."<br>");
}elseif($this->parameters["total_fee"] == null){
throw new SDKRuntimeException("退款申请接口中,缺少必填参数total_fee!"."<br>");
}elseif($this->parameters["refund_fee"] == null){
throw new SDKRuntimeException("退款申请接口中,缺少必填参数refund_fee!"."<br>");
}elseif($this->parameters["op_user_id"] == null){
throw new SDKRuntimeException("退款申请接口中,缺少必填参数op_user_id!"."<br>");
}
$this->parameters["appid"] = WxPayConf_pub::APPID;//公众账号ID
$this->parameters["mch_id"] = WxPayConf_pub::MCHID;//商户号
$this->parameters["nonce_str"] = $this->createNoncestr();//随机字符串
$this->parameters["sign"] = $this->getSign($this->parameters);//签名
return $this->arrayToXml($this->parameters);
}catch (SDKRuntimeException $e)
{
die($e->errorMessage());
}
}
/**
* 作用:获取结果,使用证书通信
*/
function getResult()
{
$this->postXmlSSL();
$this->result = $this->xmlToArray($this->response);
return $this->result;
}
}
/**
* 退款查询接口
*/
class RefundQuery_pub extends Wxpay_client_pub
{
function __construct() {
//设置接口链接
$this->url = "https://api.mch.weixin.qq.com/pay/refundquery";
//设置curl超时时间
$this->curl_timeout = WxPayConf_pub::CURL_TIMEOUT;
}
/**
* 生成接口参数xml
*/
function createXml()
{
try
{
if($this->parameters["out_refund_no"] == null &&
$this->parameters["out_trade_no"] == null &&
$this->parameters["transaction_id"] == null &&
$this->parameters["refund_id "] == null)
{
throw new SDKRuntimeException("退款查询接口中,out_refund_no、out_trade_no、transaction_id、refund_id四个参数必填一个!"."<br>");
}
$this->parameters["appid"] = WxPayConf_pub::APPID;//公众账号ID
$this->parameters["mch_id"] = WxPayConf_pub::MCHID;//商户号
$this->parameters["nonce_str"] = $this->createNoncestr();//随机字符串
$this->parameters["sign"] = $this->getSign($this->parameters);//签名
return $this->arrayToXml($this->parameters);
}catch (SDKRuntimeException $e)
{
die($e->errorMessage());
}
}
/**
* 作用:获取结果,使用证书通信
*/
function getResult()
{
$this->postXmlSSL();
$this->result = $this->xmlToArray($this->response);
return $this->result;
}
}
/**
* 对账单接口
*/
class DownloadBill_pub extends Wxpay_client_pub
{
function __construct()
{
//设置接口链接
$this->url = "https://api.mch.weixin.qq.com/pay/downloadbill";
//设置curl超时时间
$this->curl_timeout = WxPayConf_pub::CURL_TIMEOUT;
}
/**
* 生成接口参数xml
*/
function createXml()
{
try
{
if($this->parameters["bill_date"] == null )
{
throw new SDKRuntimeException("对账单接口中,缺少必填参数bill_date!"."<br>");
}
$this->parameters["appid"] = WxPayConf_pub::APPID;//公众账号ID
$this->parameters["mch_id"] = WxPayConf_pub::MCHID;//商户号
$this->parameters["nonce_str"] = $this->createNoncestr();//随机字符串
$this->parameters["sign"] = $this->getSign($this->parameters);//签名
return $this->arrayToXml($this->parameters);
}catch (SDKRuntimeException $e)
{
die($e->errorMessage());
}
}
/**
* 作用:获取结果,默认不使用证书
*/
function getResult()
{
$this->postXml();
$this->result = $this->xmlToArray($this->result_xml);
return $this->result;
}
}
/**
* 短链接转换接口
*/
class ShortUrl_pub extends Wxpay_client_pub
{
function __construct()
{
//设置接口链接
$this->url = "https://api.mch.weixin.qq.com/tools/shorturl";
//设置curl超时时间
$this->curl_timeout = WxPayConf_pub::CURL_TIMEOUT;
}
/**
* 生成接口参数xml
*/
function createXml()
{
try
{
if($this->parameters["long_url"] == null )
{
throw new SDKRuntimeException("短链接转换接口中,缺少必填参数long_url!"."<br>");
}
$this->parameters["appid"] = WxPayConf_pub::APPID;//公众账号ID
$this->parameters["mch_id"] = WxPayConf_pub::MCHID;//商户号
$this->parameters["nonce_str"] = $this->createNoncestr();//随机字符串
$this->parameters["sign"] = $this->getSign($this->parameters);//签名
return $this->arrayToXml($this->parameters);
}catch (SDKRuntimeException $e)
{
die($e->errorMessage());
}
}
/**
* 获取prepay_id
*/
function getShortUrl()
{
$this->postXml();
$prepay_id = $this->result["short_url"];
return $prepay_id;
}
}
/**
* 响应型接口基类
*/
class Wxpay_server_pub extends Common_util_pub
{
public $data;//接收到的数据,类型为关联数组
var $returnParameters;//返回参数,类型为关联数组
/**
* 将微信的请求xml转换成关联数组,以方便数据处理
*/
function saveData($xml)
{
$this->data = $this->xmlToArray($xml);
}
function checkSign()
{
$tmpData = $this->data;
unset($tmpData['sign']);
$sign = $this->getSign($tmpData);//本地签名
if ($this->data['sign'] == $sign) {
return TRUE;
}
return FALSE;
}
/**
* 获取微信的请求数据
*/
function getData()
{
return $this->data;
}
/**
* 设置返回微信的xml数据
*/
function setReturnParameter($parameter, $parameterValue)
{
$this->returnParameters[$this->trimString($parameter)] = $this->trimString($parameterValue);
}
/**
* 生成接口参数xml
*/
function createXml()
{
return $this->arrayToXml($this->returnParameters);
}
/**
* 将xml数据返回微信
*/
function returnXml()
{
$returnXml = $this->createXml();
return $returnXml;
}
}
/**
* 通用通知接口
*/
class Notify_pub extends Wxpay_server_pub
{
}
/**
* 请求商家获取商品信息接口
*/
class NativeCall_pub extends Wxpay_server_pub
{
/**
* 生成接口参数xml
*/
function createXml()
{
if($this->returnParameters["return_code"] == "SUCCESS"){
$this->returnParameters["appid"] = WxPayConf_pub::APPID;//公众账号ID
$this->returnParameters["mch_id"] = WxPayConf_pub::MCHID;//商户号
$this->returnParameters["nonce_str"] = $this->createNoncestr();//随机字符串
$this->returnParameters["sign"] = $this->getSign($this->returnParameters);//签名
}
return $this->arrayToXml($this->returnParameters);
}
/**
* 获取product_id
*/
function getProductId()
{
$product_id = $this->data["product_id"];
return $product_id;
}
}
/**
* 静态链接二维码
*/
class NativeLink_pub extends Common_util_pub
{
var $parameters;//静态链接参数
var $url;//静态链接
function __construct()
{
}
/**
* 设置参数
*/
function setParameter($parameter, $parameterValue)
{
$this->parameters[$this->trimString($parameter)] = $this->trimString($parameterValue);
}
/**
* 生成Native支付链接二维码
*/
function createLink()
{
try
{
if($this->parameters["product_id"] == null)
{
throw new SDKRuntimeException("缺少Native支付二维码链接必填参数product_id!"."<br>");
}
$this->parameters["appid"] = WxPayConf_pub::APPID;//公众账号ID
$this->parameters["mch_id"] = WxPayConf_pub::MCHID;//商户号
$time_stamp = time();
$this->parameters["time_stamp"] = "$time_stamp";//时间戳
$this->parameters["nonce_str"] = $this->createNoncestr();//随机字符串
$this->parameters["sign"] = $this->getSign($this->parameters);//签名
$bizString = $this->formatBizQueryParaMap($this->parameters, false);
$this->url = "weixin://wxpay/bizpayurl?".$bizString;
}catch (SDKRuntimeException $e)
{
die($e->errorMessage());
}
}
/**
* 返回链接
*/
function getUrl()
{
$this->createLink();
return $this->url;
}
}
/**
* JSAPI支付——H5网页端调起支付接口
*/
class JsApi_pub extends Common_util_pub
{
var $code;//code码,用以获取openid
var $openid;//用户的openid
var $parameters;//jsapi参数,格式为json
var $prepay_id;//使用统一支付接口得到的预支付id
var $curl_timeout;//curl超时时间
function __construct()
{
//设置curl超时时间
$this->curl_timeout = WxPayConf_pub::CURL_TIMEOUT;
}
/**
* 作用:生成可以获得code的url
*/
function createOauthUrlForCode($redirectUrl)
{
$urlObj["appid"] = WxPayConf_pub::APPID;
$urlObj["redirect_uri"] = "$redirectUrl";
$urlObj["response_type"] = "code";
$urlObj["scope"] = "snsapi_base";
$urlObj["state"] = "STATE"."#wechat_redirect";
$bizString = $this->formatBizQueryParaMap($urlObj, false);
return "https://open.weixin.qq.com/connect/oauth2/authorize?".$bizString;
}
/**
* 作用:生成可以获得openid的url
*/
function createOauthUrlForOpenid()
{
$urlObj["appid"] = WxPayConf_pub::APPID;
$urlObj["secret"] = WxPayConf_pub::APPSECRET;
$urlObj["code"] = $this->code;
$urlObj["grant_type"] = "authorization_code";
$bizString = $this->formatBizQueryParaMap($urlObj, false);
return "https://api.weixin.qq.com/sns/oauth2/access_token?".$bizString;
}
/**
* 作用:通过curl向微信提交code,以获取openid
*/
function getOpenid()
{
$url = $this->createOauthUrlForOpenid();
//初始化curl
$ch = curl_init();
//设置超时
curl_setopt($ch, CURLOP_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_HEADER, FALSE);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
//运行curl,结果以jason形式返回
$res = curl_exec($ch);
curl_close($ch);
//取出openid
$data = json_decode($res,true);
$this->openid = $data['openid'];
return $this->openid;
}
/**
* 作用:设置prepay_id
*/
function setPrepayId($prepayId)
{
$this->prepay_id = $prepayId;
}
/**
* 作用:设置code
*/
function setCode($code_)
{
$this->code = $code_;
}
/**
* 作用:设置jsapi的参数
*/
public function getParameters()
{
$jsApiObj["appId"] = WxPayConf_pub::APPID;
$timeStamp = time();
$jsApiObj["timeStamp"] = "$timeStamp";
$jsApiObj["nonceStr"] = $this->createNoncestr();
$jsApiObj["package"] = "prepay_id=$this->prepay_id";
$jsApiObj["signType"] = "MD5";
$jsApiObj["paySign"] = $this->getSign($jsApiObj);
$this->parameters = json_encode($jsApiObj);
return $this->parameters;
}
}
?>
5. [代码]download_bill.php
<?php
/**
* 对账单接口demo
* ====================================================
* 商户可以通过该接口下载历史交易清单。
*/
include_once("../WxPayPubHelper/WxPayPubHelper.php");
//对账单日期
if (!isset($_POST["bill_date"])){
$bill_date = "20140814";
}
else{
$bill_date = $_POST["bill_date"];
//使用对账单接口
$downloadBill = new DownloadBill_pub();
//设置对账单接口参数
//设置必填参数
//appid已填,商户无需重复填写
//mch_id已填,商户无需重复填写
//noncestr已填,商户无需重复填写
//sign已填,商户无需重复填写
$downloadBill->setParameter("bill_date","$bill_date");//对账单日期
$downloadBill->setParameter("bill_type","ALL");//账单类型
//非必填参数,商户可根据实际情况选填
//$downloadBill->setParameter("device_info","XXXX");//设备号
//对账单接口结果
$downloadBillResult = $downloadBill->getResult();
echo $downloadBillResult['return_code'];
if ($downloadBillResult['return_code'] == "FAIL") {
echo "通信出错:".$downloadBillResult['return_msg'];
}else{
print_r('<pre>');
echo "【对账单详情】"."</br>";
print_r($downloadBill->response);
print_r('</pre>');
}
}
?>
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<title>微信安全支付</title>
</head>
<body>
</br></br>
<div align="center">
<form action="./download_bill.php" method="post">
<p>对账单查询</p>
<p>日期(格式:20140101): <input type="text" name="bill_date" value="<?php echo $bill_date; ?>"></p>
<button type="submit" >提交</button>
</form>
</br>
<a href="../index.php">返回首页</a>
</br></br>
<?php
?>
</div>
</body>
</html>
6. [代码]index.php
<!DOCTYPE HTML> <html> <head> <meta charset="UTF-8"> <title>微信安全支付</title> </head> <body> </br></br> <div > <ul> <h1><a href="./js_api_call.php" >1.JSapi支付demo(在微信客户端中点击)</a></h1> <h1><a href="./native_call_qrcode.php" >2.native支付模式一demo(用微信扫的静态链接二维码)</a></h1> <h1><a href="./native_dynamic_qrcode.php" >3.native支付模式二demo(用微信扫的动态链接二维码)</a></h1> <h1><a href="./order_query.php" >4.支付查询接口demo</a></h1> <h1><a href="./download_bill.php" >5.对账单接口demo</a></h1> <h1><a href="./refund.php" >6.退款接口demo</a></h1> <h1><a href="./refund_query.php" >7.退款查询接口demo</a></h1> </ul> </div> </body> </html>
7. [代码]js_api_call.php
<?php
/**
* JS_API支付demo
* ====================================================
* 在微信浏览器里面打开H5网页中执行JS调起支付。接口输入输出数据格式为JSON。
* 成功调起支付需要三个步骤:
* 步骤1:网页授权获取用户openid
* 步骤2:使用统一支付接口,获取prepay_id
* 步骤3:使用jsapi调起支付
*/
include_once("./WxPayPubHelper/WxPayPubHelper.php");
//使用jsapi接口
$jsApi = new JsApi_pub();
//=========步骤1:网页授权获取用户openid============
//通过code获得openid
if (!isset($_GET['code']))
{
//触发微信返回code码
$url = $jsApi->createOauthUrlForCode(WxPayConf_pub::JS_API_CALL_URL);
Header("Location: $url");
}else
{
//获取code码,以获取openid
$code = $_GET['code'];
$jsApi->setCode($code);
$openid = $jsApi->getOpenId();
}
//=========步骤2:使用统一支付接口,获取prepay_id============
//使用统一支付接口
$unifiedOrder = new UnifiedOrder_pub();
//设置统一支付接口参数
//设置必填参数
//appid已填,商户无需重复填写
//mch_id已填,商户无需重复填写
//noncestr已填,商户无需重复填写
//spbill_create_ip已填,商户无需重复填写
//sign已填,商户无需重复填写
$body = $_GET["body"];
$out_trade_no = $_GET["orderid"];
$total_fee = $_GET["totalprice"];
$url = $_GET["url"];
$unifiedOrder->setParameter("openid","$openid");//商品描述
$unifiedOrder->setParameter("body","$body");//商品描述
//自定义订单号,此处仅作举例
// $timeStamp = time();
// $out_trade_no = WxPayConf_pub::APPID."$timeStamp";
$unifiedOrder->setParameter("out_trade_no","$out_trade_no");//商户订单号
$unifiedOrder->setParameter("total_fee","$total_fee");//总金额
$unifiedOrder->setParameter("notify_url",WxPayConf_pub::NOTIFY_URL);//通知地址
$unifiedOrder->setParameter("trade_type","JSAPI");//交易类型
//非必填参数,商户可根据实际情况选填
//$unifiedOrder->setParameter("sub_mch_id","XXXX");//子商户号
//$unifiedOrder->setParameter("device_info","XXXX");//设备号
//$unifiedOrder->setParameter("attach","XXXX");//附加数据
//$unifiedOrder->setParameter("time_start","XXXX");//交易起始时间
//$unifiedOrder->setParameter("time_expire","XXXX");//交易结束时间
//$unifiedOrder->setParameter("goods_tag","XXXX");//商品标记
//$unifiedOrder->setParameter("openid","XXXX");//用户标识
//$unifiedOrder->setParameter("product_id","XXXX");//商品ID
$prepay_id = $unifiedOrder->getPrepayId();
//=========步骤3:使用jsapi调起支付============
$jsApi->setPrepayId($prepay_id);
$jsApiParameters = $jsApi->getParameters();
//echo $jsApiParameters;
?>
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8"/>
<title>微信安全支付</title>
<script type="text/javascript">
//调用微信JS api 支付
function jsApiCall()
{
WeixinJSBridge.invoke(
'getBrandWCPayRequest',
<?php echo $jsApiParameters; ?>,
function(res){
WeixinJSBridge.log(res.err_msg);
// alert(res.err_code+res.err_desc+res.err_msg);
if (res.err_msg == 'get_brand_wcpay_request:ok') {
alert("支付成功!");
}else if (res.err_msg == 'get_brand_wcpay_request:cancel') {
alert("已取消支付!");
}else if (res.err_msg == 'get_brand_wcpay_request:fail') {
alert("支付失败!");
};
window.location.href = '<?php echo $url; ?>';
}
);
}
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>
</head>
<body>
</body>
</html>
8. [代码]log_.php
<?php
class Log_
{
// 打印log
function log_result($file,$word)
{
$fp = fopen($file,"a");
flock($fp, LOCK_EX) ;
fwrite($fp,"执行日期:".strftime("%Y-%m-%d-%H:%M:%S",time())."\n".$word."\n\n");
flock($fp, LOCK_UN);
fclose($fp);
}
}
?>
9. [代码]native_call.php
<?php
/**
* Native(原生)支付模式一demo
* ====================================================
* 模式一:商户按固定格式生成链接二维码,用户扫码后调微信
* 会将productid和用户openid发送到商户设置的链接上,商户收到
* 请求生成订单,调用统一支付接口下单提交到微信,微信会返回
* 给商户prepayid。
* 本例程对应的二维码由native_call_qrcode.php生成;
* 本例程对应的响应服务为native_call.php;
* 需要两者配合使用。
*
*/
include_once("./log_.php");
include_once("../WxPayPubHelper/WxPayPubHelper.php");
//以log文件形式记录回调信息,用于调试
$log_ = new Log_();
$log_name="./native_call.log";
//使用native通知接口
$nativeCall = new NativeCall_pub();
//接收微信请求
$xml = $GLOBALS['HTTP_RAW_POST_DATA'];
$log_->log_result($log_name,"【接收到的native通知】:\n".$xml."\n");
$nativeCall->saveData($xml);
if($nativeCall->checkSign() == FALSE){
$nativeCall->setReturnParameter("return_code","FAIL");//返回状态码
$nativeCall->setReturnParameter("return_msg","签名失败");//返回信息
}else{
//提取product_id
$product_id = $nativeCall->getProductId();
//使用统一支付接口
$unifiedOrder = new UnifiedOrder_pub();
//根据不同的$product_id设定对应的下单参数,此处只举例一种
switch ($product_id)
{
case WxPayConf_pub::APPID."static"://与native_call_qrcode.php中的静态链接二维码对应
//设置统一支付接口参数
//设置必填参数
//appid已填,商户无需重复填写
//mch_id已填,商户无需重复填写
//noncestr已填,商户无需重复填写
//spbill_create_ip已填,商户无需重复填写
//sign已填,商户无需重复填写
$unifiedOrder->setParameter("body","贡献一分钱");//商品描述
//自定义订单号,此处仅作举例
$timeStamp = time();
$out_trade_no = WxPayConf_pub::APPID."$timeStamp";
$unifiedOrder->setParameter("out_trade_no","$out_trade_no");//商户订单号 $unifiedOrder->setParameter("product_id","$product_id");//商品ID
$unifiedOrder->setParameter("total_fee","1");//总金额
$unifiedOrder->setParameter("notify_url",WxPayConf_pub::NOTIFY_URL);//通知地址
$unifiedOrder->setParameter("trade_type","NATIVE");//交易类型
$unifiedOrder->setParameter("product_id","$product_id");//用户标识
//非必填参数,商户可根据实际情况选填
//$unifiedOrder->setParameter("sub_mch_id","XXXX");//子商户号
//$unifiedOrder->setParameter("device_info","XXXX");//设备号
//$unifiedOrder->setParameter("attach","XXXX");//附加数据
//$unifiedOrder->setParameter("time_start","XXXX");//交易起始时间
//$unifiedOrder->setParameter("time_expire","XXXX");//交易结束时间
//$unifiedOrder->setParameter("goods_tag","XXXX");//商品标记
//$unifiedOrder->setParameter("openid","XXXX");//用户标识
//获取prepay_id
$prepay_id = $unifiedOrder->getPrepayId();
//设置返回码
//设置必填参数
//appid已填,商户无需重复填写
//mch_id已填,商户无需重复填写
//noncestr已填,商户无需重复填写
//sign已填,商户无需重复填写
$nativeCall->setReturnParameter("return_code","SUCCESS");//返回状态码
$nativeCall->setReturnParameter("result_code","SUCCESS");//业务结果
$nativeCall->setReturnParameter("prepay_id","$prepay_id");//预支付ID
break;
default:
//设置返回码
//设置必填参数
//appid已填,商户无需重复填写
//mch_id已填,商户无需重复填写
//noncestr已填,商户无需重复填写
//sign已填,商户无需重复填写
$nativeCall->setReturnParameter("return_code","SUCCESS");//返回状态码
$nativeCall->setReturnParameter("result_code","FAIL");//业务结果
$nativeCall->setReturnParameter("err_code_des","此商品无效");//业务结果
break;
}
}
//将结果返回微信
$returnXml = $nativeCall->returnXml();
$log_->log_result($log_name,"【返回微信的native响应】:\n".$returnXml."\n");
echo $returnXml;
//交易完成
?>
10. [代码]native_call_qrcode.php
<?php
/**
* Native(原生)支付模式一demo
* ====================================================
* 模式一:商户按固定格式生成链接二维码,用户扫码后调微信
* 会将productid和用户openid发送到商户设置的链接上,商户收到
* 请求生成订单,调用统一支付接口下单提交到微信,微信会返回
* 给商户prepayid。
* 本例程对应的二维码由native_call_qrcode.php生成;
* 本例程对应的响应服务为native_call.php;
* 需要两者配合使用。
*/
include_once("../WxPayPubHelper/WxPayPubHelper.php");
//设置静态链接
$nativeLink = new NativeLink_pub();
//设置静态链接参数
//设置必填参数
//appid已填,商户无需重复填写
//mch_id已填,商户无需重复填写
//noncestr已填,商户无需重复填写
//time_stamp已填,商户无需重复填写
//sign已填,商户无需重复填写
$product_id = WxPayConf_pub::APPID."static";//自定义商品id
$nativeLink->setParameter("product_id","$product_id");//商品id
//获取链接
$product_url = $nativeLink->getUrl();
//使用短链接转换接口
$shortUrl = new ShortUrl_pub();
//设置必填参数
//appid已填,商户无需重复填写
//mch_id已填,商户无需重复填写
//noncestr已填,商户无需重复填写
//sign已填,商户无需重复填写
$shortUrl->setParameter("long_url","$product_url");//URL链接
//获取短链接
$codeUrl = $shortUrl->getShortUrl();
?>
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<title>微信安全支付</title>
</head>
<body>
<div align="center" id="qrcode">
<p >扫我,扫我</p>
</div>
<div align="center">
<a href="../index.php">返回首页</a>
</div>
</body>
<script src="./qrcode.js"></script>
<script>
var url = "<?php echo $product_url;?>";
//参数1表示图像大小,取值范围1-10;参数2表示质量,取值范围'L','M','Q','H'
var qr = qrcode(10, 'M');
qr.addData(url);
qr.make();
var dom=document.createElement('DIV');
dom.innerHTML = qr.createImgTag();
var element=document.getElementById("qrcode");
element.appendChild(dom);
</script>
</html>
11. [代码]native_dynamic_qrcode.php
<?php
/**
* Native(原生)支付-模式二-demo
* ====================================================
* 商户生成订单,先调用统一支付接口获取到code_url,
* 此URL直接生成二维码,用户扫码后调起支付。
*
*/
include_once("../WxPayPubHelper/WxPayPubHelper.php");
//使用统一支付接口
$unifiedOrder = new UnifiedOrder_pub();
//设置统一支付接口参数
//设置必填参数
//appid已填,商户无需重复填写
//mch_id已填,商户无需重复填写
//noncestr已填,商户无需重复填写
//spbill_create_ip已填,商户无需重复填写
//sign已填,商户无需重复填写
$unifiedOrder->setParameter("body","贡献一分钱");//商品描述
//自定义订单号,此处仅作举例
$timeStamp = time();
$out_trade_no = WxPayConf_pub::APPID."$timeStamp";
$unifiedOrder->setParameter("out_trade_no","$out_trade_no");//商户订单号
$unifiedOrder->setParameter("total_fee","1");//总金额
$unifiedOrder->setParameter("notify_url",WxPayConf_pub::NOTIFY_URL);//通知地址
$unifiedOrder->setParameter("trade_type","NATIVE");//交易类型
//非必填参数,商户可根据实际情况选填
//$unifiedOrder->setParameter("sub_mch_id","XXXX");//子商户号
//$unifiedOrder->setParameter("device_info","XXXX");//设备号
//$unifiedOrder->setParameter("attach","XXXX");//附加数据
//$unifiedOrder->setParameter("time_start","XXXX");//交易起始时间
//$unifiedOrder->setParameter("time_expire","XXXX");//交易结束时间
//$unifiedOrder->setParameter("goods_tag","XXXX");//商品标记
//$unifiedOrder->setParameter("openid","XXXX");//用户标识
//$unifiedOrder->setParameter("product_id","XXXX");//商品ID
//获取统一支付接口结果
$unifiedOrderResult = $unifiedOrder->getResult();
//商户根据实际情况设置相应的处理流程
if ($unifiedOrderResult["return_code"] == "FAIL")
{
//商户自行增加处理流程
echo "通信出错:".$unifiedOrderResult['return_msg']."<br>";
}
elseif($unifiedOrderResult["result_code"] == "FAIL")
{
//商户自行增加处理流程
echo "错误代码:".$unifiedOrderResult['err_code']."<br>";
echo "错误代码描述:".$unifiedOrderResult['err_code_des']."<br>";
}
elseif($unifiedOrderResult["code_url"] != NULL)
{
//从统一支付接口获取到code_url
$code_url = $unifiedOrderResult["code_url"];
//商户自行增加处理流程
//......
}
?>
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<title>微信安全支付</title>
</head>
<body>
<div align="center" id="qrcode">
</div>
<div align="center">
<p>订单号:<?php echo $out_trade_no; ?></p>
</div>
<div align="center">
<form action="./order_query.php" method="post">
<input name="out_trade_no" type='hidden' value="<?php echo $out_trade_no; ?>">
<button type="submit" >查询订单状态</button>
</form>
</div>
<br>
<div align="center">
<form action="./refund.php" method="post">
<input name="out_trade_no" type='hidden' value="<?php echo $out_trade_no; ?>">
<input name="refund_fee" type='hidden' value="1">
<button type="submit" >申请退款</button>
</form>
</div>
<br>
<div align="center">
<a href="../index.php">返回首页</a>
</div>
</body>
<script src="./qrcode.js"></script>
<script>
if(<?php echo $unifiedOrderResult["code_url"] != NULL; ?>)
{
var url = "<?php echo $code_url;?>";
//参数1表示图像大小,取值范围1-10;参数2表示质量,取值范围'L','M','Q','H'
var qr = qrcode(10, 'M');
qr.addData(url);
qr.make();
var wording=document.createElement('p');
wording.innerHTML = "扫我,扫我";
var code=document.createElement('DIV');
code.innerHTML = qr.createImgTag();
var element=document.getElementById("qrcode");
element.appendChild(wording);
element.appendChild(code);
}
</script>
</html>
12. [代码]notify_url.php
<?php
/**
* 通用通知接口demo
* ====================================================
* 支付完成后,微信会把相关支付和用户信息发送到商户设定的通知URL,
* 商户接收回调信息后,根据需要设定相应的处理流程。
*
* 这里举例使用log文件形式记录回调信息。
*/
include_once("./log_.php");
include_once("./WxPayPubHelper/WxPayPubHelper.php");
include_once('../../Public/Conf/config.php');
//使用通用通知接口
$notify = new Notify_pub();
//存储微信的回调
$xml = $GLOBALS['HTTP_RAW_POST_DATA'];
$notify->saveData($xml);
//验证签名,并回应微信。
//对后台通知交互时,如果微信收到商户的应答不是成功或超时,微信认为通知失败,
//微信会通过一定的策略(如30分钟共8次)定期重新发起通知,
//尽可能提高通知的成功率,但微信不保证通知最终能成功。
if($notify->checkSign() == FALSE){
$notify->setReturnParameter("return_code","FAIL");//返回状态码
$notify->setReturnParameter("return_msg","签名失败");//返回信息
}else{
$notify->setReturnParameter("return_code","SUCCESS");//设置返回码
}
$returnXml = $notify->returnXml();
echo $returnXml;
//==商户根据实际情况设置相应的处理流程,此处仅作举例=======
//以log文件形式记录回调信息
$log_ = new Log_();
$log_name="./notify_url.log";//log文件路径
$log_->log_result($log_name,"【接收到的notify通知】:\n".$xml."\n");
if($notify->checkSign() == TRUE)
{
if ($notify->data["return_code"] == "FAIL") {
//此处应该更新一下订单状态,商户自行增删操作
$log_->log_result($log_name,"【通信出错】:\n".$xml."\n");
}
elseif($notify->data["result_code"] == "FAIL"){
//此处应该更新一下订单状态,商户自行增删操作
$log_->log_result($log_name,"【业务出错】:\n".$xml."\n");
}
else{
//此处应该更新一下订单状态,商户自行增删操作
$log_->log_result($log_name,"【支付成功】:\n".$xml."\n");
}
//商户自行增加处理流程,
//例如:更新订单状态
//例如:数据库操作
//例如:推送支付完成信息
$xml = $notify->xmlToArray($xml);
// 商户订单号
$out_trade_no = $xml ['out_trade_no'];
$total_fee = $xml ['total_fee'];
$uid = $xml ['openid'];
$log_->log_result($log_name,"【订单号】:\n".$out_trade_no."\n");
// 判断该笔订单是否在商户网站中已经做过处理
// 如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序
// 如果有做过处理,不执行商户的业务程序
if (! empty ( $out_trade_no )) {
$sql = "update " . DB_PREFIX . "order set pay_status=1 where orderid='" . $out_trade_no . "'";
mysql_query ( $sql, $conn );
}
}
?>
13. [代码]order_query.php
<?php
/**
* 订单查询-demo
* ====================================================
* 该接口提供所有微信支付订单的查询。
* 当支付通知处理异常或丢失的情况,商户可以通过该接口查询订单支付状态。
*
*/
include_once("../WxPayPubHelper/WxPayPubHelper.php");
//退款的订单号
if (!isset($_POST["out_trade_no"]))
{
$out_trade_no = " ";
}else{
$out_trade_no = $_POST["out_trade_no"];
//使用订单查询接口
$orderQuery = new OrderQuery_pub();
//设置必填参数
//appid已填,商户无需重复填写
//mch_id已填,商户无需重复填写
//noncestr已填,商户无需重复填写
//sign已填,商户无需重复填写
$orderQuery->setParameter("out_trade_no","$out_trade_no");//商户订单号
//非必填参数,商户可根据实际情况选填
//$orderQuery->setParameter("sub_mch_id","XXXX");//子商户号
//$orderQuery->setParameter("transaction_id","XXXX");//微信订单号
//获取订单查询结果
$orderQueryResult = $orderQuery->getResult();
//商户根据实际情况设置相应的处理流程,此处仅作举例
if ($orderQueryResult["return_code"] == "FAIL") {
echo "通信出错:".$orderQueryResult['return_msg']."<br>";
}
elseif($orderQueryResult["result_code"] == "FAIL"){
echo "错误代码:".$orderQueryResult['err_code']."<br>";
echo "错误代码描述:".$orderQueryResult['err_code_des']."<br>";
}
else{
echo "交易状态:".$orderQueryResult['trade_state']."<br>";
echo "设备号:".$orderQueryResult['device_info']."<br>";
echo "用户标识:".$orderQueryResult['openid']."<br>";
echo "是否关注公众账号:".$orderQueryResult['is_subscribe']."<br>";
echo "交易类型:".$orderQueryResult['trade_type']."<br>";
echo "付款银行:".$orderQueryResult['bank_type']."<br>";
echo "总金额:".$orderQueryResult['total_fee']."<br>";
echo "现金券金额:".$orderQueryResult['coupon_fee']."<br>";
echo "货币种类:".$orderQueryResult['fee_type']."<br>";
echo "微信支付订单号:".$orderQueryResult['transaction_id']."<br>";
echo "商户订单号:".$orderQueryResult['out_trade_no']."<br>";
echo "商家数据包:".$orderQueryResult['attach']."<br>";
echo "支付完成时间:".$orderQueryResult['time_end']."<br>";
}
}
//商户自行增加处理流程
//......
?>
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<title>微信安全支付</title>
</head>
<body>
</br></br>
<div align="center">
<form action="./order_query.php" method="post">
<p>订单查询</p>
<p>单号: <input type="text" name="out_trade_no" value="<?php echo $out_trade_no; ?>"></p>
<button type="submit" >提交</button>
</form>
</br>
<a href="../index.php">返回首页</a>
</div>
</body>
</html>
14. [代码]qrcode.js
var qrcode=function(){var qrcode=function(typeNumber,errorCorrectLevel){var PAD0=0xEC;var PAD1=0x11;var _typeNumber=typeNumber;var _errorCorrectLevel=QRErrorCorrectLevel[errorCorrectLevel];var _modules=null;var _moduleCount=0;var _dataCache=null;var _dataList=new Array();var _this={};var makeImpl=function(test,maskPattern){_moduleCount=_typeNumber*4+17;_modules=function(moduleCount){var modules=new Array(moduleCount);for(var row=0;row<moduleCount;row+=1){modules[row]=new Array(moduleCount);for(var col=0;col<moduleCount;col+=1){modules[row][col]=null;}}
return modules;}(_moduleCount);setupPositionProbePattern(0,0);setupPositionProbePattern(_moduleCount-7,0);setupPositionProbePattern(0,_moduleCount-7);setupPositionAdjustPattern();setupTimingPattern();setupTypeInfo(test,maskPattern);if(_typeNumber>=7){setupTypeNumber(test);}
if(_dataCache==null){_dataCache=createData(_typeNumber,_errorCorrectLevel,_dataList);}
mapData(_dataCache,maskPattern);};var setupPositionProbePattern=function(row,col){for(var r=-1;r<=7;r+=1){if(row+r<=-1||_moduleCount<=row+r)continue;for(var c=-1;c<=7;c+=1){if(col+c<=-1||_moduleCount<=col+c)continue;if((0<=r&&r<=6&&(c==0||c==6))||(0<=c&&c<=6&&(r==0||r==6))||(2<=r&&r<=4&&2<=c&&c<=4)){_modules[row+r][col+c]=true;}else{_modules[row+r][col+c]=false;}}}};var getBestMaskPattern=function(){var minLostPoint=0;var pattern=0;for(var i=0;i<8;i+=1){makeImpl(true,i);var lostPoint=QRUtil.getLostPoint(_this);if(i==0||minLostPoint>lostPoint){minLostPoint=lostPoint;pattern=i;}}
return pattern;};var setupTimingPattern=function(){for(var r=8;r<_moduleCount-8;r+=1){if(_modules[r][6]!=null){continue;}
_modules[r][6]=(r%2==0);}
for(var c=8;c<_moduleCount-8;c+=1){if(_modules[6][c]!=null){continue;}
_modules[6][c]=(c%2==0);}};var setupPositionAdjustPattern=function(){var pos=QRUtil.getPatternPosition(_typeNumber);for(var i=0;i<pos.length;i+=1){for(var j=0;j<pos.length;j+=1){var row=pos[i];var col=pos[j];if(_modules[row][col]!=null){continue;}
for(var r=-2;r<=2;r+=1){for(var c=-2;c<=2;c+=1){if(r==-2||r==2||c==-2||c==2||(r==0&&c==0)){_modules[row+r][col+c]=true;}else{_modules[row+r][col+c]=false;}}}}}};var setupTypeNumber=function(test){var bits=QRUtil.getBCHTypeNumber(_typeNumber);for(var i=0;i<18;i+=1){var mod=(!test&&((bits>>i)&1)==1);_modules[Math.floor(i/3)][i%3+_moduleCount-8-3]=mod;}
for(var i=0;i<18;i+=1){var mod=(!test&&((bits>>i)&1)==1);_modules[i%3+_moduleCount-8-3][Math.floor(i/3)]=mod;}};var setupTypeInfo=function(test,maskPattern){var data=(_errorCorrectLevel<<3)|maskPattern;var bits=QRUtil.getBCHTypeInfo(data);for(var i=0;i<15;i+=1){var mod=(!test&&((bits>>i)&1)==1);if(i<6){_modules[i][8]=mod;}else if(i<8){_modules[i+1][8]=mod;}else{_modules[_moduleCount-15+i][8]=mod;}}
for(var i=0;i<15;i+=1){var mod=(!test&&((bits>>i)&1)==1);if(i<8){_modules[8][_moduleCount-i-1]=mod;}else if(i<9){_modules[8][15-i-1+1]=mod;}else{_modules[8][15-i-1]=mod;}}
_modules[_moduleCount-8][8]=(!test);};var mapData=function(data,maskPattern){var inc=-1;var row=_moduleCount-1;var bitIndex=7;var byteIndex=0;var maskFunc=QRUtil.getMaskFunction(maskPattern);for(var col=_moduleCount-1;col>0;col-=2){if(col==6)col-=1;while(true){for(var c=0;c<2;c+=1){if(_modules[row][col-c]==null){var dark=false;if(byteIndex<data.length){dark=(((data[byteIndex]>>>bitIndex)&1)==1);}
var mask=maskFunc(row,col-c);if(mask){dark=!dark;}
_modules[row][col-c]=dark;bitIndex-=1;if(bitIndex==-1){byteIndex+=1;bitIndex=7;}}}
row+=inc;if(row<0||_moduleCount<=row){row-=inc;inc=-inc;break;}}}};var createBytes=function(buffer,rsBlocks){var offset=0;var maxDcCount=0;var maxEcCount=0;var dcdata=new Array(rsBlocks.length);var ecdata=new Array(rsBlocks.length);for(var r=0;r<rsBlocks.length;r+=1){var dcCount=rsBlocks[r].dataCount;var ecCount=rsBlocks[r].totalCount-dcCount;maxDcCount=Math.max(maxDcCount,dcCount);maxEcCount=Math.max(maxEcCount,ecCount);dcdata[r]=new Array(dcCount);for(var i=0;i<dcdata[r].length;i+=1){dcdata[r][i]=0xff&buffer.getBuffer()[i+offset];}
offset+=dcCount;var rsPoly=QRUtil.getErrorCorrectPolynomial(ecCount);var rawPoly=qrPolynomial(dcdata[r],rsPoly.getLength()-1);var modPoly=rawPoly.mod(rsPoly);ecdata[r]=new Array(rsPoly.getLength()-1);for(var i=0;i<ecdata[r].length;i+=1){var modIndex=i+modPoly.getLength()-ecdata[r].length;ecdata[r][i]=(modIndex>=0)?modPoly.getAt(modIndex):0;}}
var totalCodeCount=0;for(var i=0;i<rsBlocks.length;i+=1){totalCodeCount+=rsBlocks[i].totalCount;}
var data=new Array(totalCodeCount);var index=0;for(var i=0;i<maxDcCount;i+=1){for(var r=0;r<rsBlocks.length;r+=1){if(i<dcdata[r].length){data[index]=dcdata[r][i];index+=1;}}}
for(var i=0;i<maxEcCount;i+=1){for(var r=0;r<rsBlocks.length;r+=1){if(i<ecdata[r].length){data[index]=ecdata[r][i];index+=1;}}}
return data;};var createData=function(typeNumber,errorCorrectLevel,dataList){var rsBlocks=QRRSBlock.getRSBlocks(typeNumber,errorCorrectLevel);var buffer=qrBitBuffer();for(var i=0;i<dataList.length;i+=1){var data=dataList[i];buffer.put(data.getMode(),4);buffer.put(data.getLength(),QRUtil.getLengthInBits(data.getMode(),typeNumber));data.write(buffer);}
var totalDataCount=0;for(var i=0;i<rsBlocks.length;i+=1){totalDataCount+=rsBlocks[i].dataCount;}
if(buffer.getLengthInBits()>totalDataCount*8){throw new Error('code length overflow. ('
+buffer.getLengthInBits()
+'>'
+totalDataCount*8
+')');}
if(buffer.getLengthInBits()+4<=totalDataCount*8){buffer.put(0,4);}
while(buffer.getLengthInBits()%8!=0){buffer.putBit(false);}
while(true){if(buffer.getLengthInBits()>=totalDataCount*8){break;}
buffer.put(PAD0,8);if(buffer.getLengthInBits()>=totalDataCount*8){break;}
buffer.put(PAD1,8);}
return createBytes(buffer,rsBlocks);};_this.addData=function(data){var newData=qr8BitByte(data);_dataList.push(newData);_dataCache=null;};_this.isDark=function(row,col){if(row<0||_moduleCount<=row||col<0||_moduleCount<=col){throw new Error(row+','+col);}
return _modules[row][col];};_this.getModuleCount=function(){return _moduleCount;};_this.make=function(){makeImpl(false,getBestMaskPattern());};_this.createTableTag=function(cellSize,margin){cellSize=cellSize||2;margin=(typeof margin=='undefined')?cellSize*4:margin;var qrHtml='';qrHtml+='<table style="';qrHtml+=' border-width: 0px; border-style: none;';qrHtml+=' border-collapse: collapse;';qrHtml+=' padding: 0px; margin: '+margin+'px;';qrHtml+='">';qrHtml+='<tbody>';for(var r=0;r<_this.getModuleCount();r+=1){qrHtml+='<tr>';for(var c=0;c<_this.getModuleCount();c+=1){qrHtml+='<td style="';qrHtml+=' border-width: 0px; border-style: none;';qrHtml+=' border-collapse: collapse;';qrHtml+=' padding: 0px; margin: 0px;';qrHtml+=' width: '+cellSize+'px;';qrHtml+=' height: '+cellSize+'px;';qrHtml+=' background-color: ';qrHtml+=_this.isDark(r,c)?'#000000':'#ffffff';qrHtml+=';';qrHtml+='"/>';}
qrHtml+='</tr>';}
qrHtml+='</tbody>';qrHtml+='</table>';return qrHtml;};_this.createImgTag=function(cellSize,margin){cellSize=cellSize||2;margin=(typeof margin=='undefined')?cellSize*4:margin;var size=_this.getModuleCount()*cellSize+margin*2;var min=margin;var max=size-margin;return createImgTag(size,size,function(x,y){if(min<=x&&x<max&&min<=y&&y<max){var c=Math.floor((x-min)/cellSize);var r=Math.floor((y-min)/cellSize);return _this.isDark(r,c)?0:1;}else{return 1;}});};return _this;};qrcode.stringToBytes=function(s){var bytes=new Array();for(var i=0;i<s.length;i+=1){var c=s.charCodeAt(i);bytes.push(c&0xff);}
return bytes;};qrcode.createStringToBytes=function(unicodeData,numChars){var unicodeMap=function(){var bin=base64DecodeInputStream(unicodeData);var read=function(){var b=bin.read();if(b==-1)throw new Error();return b;};var count=0;var unicodeMap={};while(true){var b0=bin.read();if(b0==-1)break;var b1=read();var b2=read();var b3=read();var k=String.fromCharCode((b0<<8)|b1);var v=(b2<<8)|b3;unicodeMap[k]=v;count+=1;}
if(count!=numChars){throw new Error(count+' != '+numChars);}
return unicodeMap;}();var unknownChar='?'.charCodeAt(0);return function(s){var bytes=new Array();for(var i=0;i<s.length;i+=1){var c=s.charCodeAt(i);if(c<128){bytes.push(c);}else{var b=unicodeMap[s.charAt(i)];if(typeof b=='number'){if((b&0xff)==b){bytes.push(b);}else{bytes.push(b>>>8);bytes.push(b&0xff);}}else{bytes.push(unknownChar);}}}
return bytes;};};var QRMode={MODE_NUMBER:1<<0,MODE_ALPHA_NUM:1<<1,MODE_8BIT_BYTE:1<<2,MODE_KANJI:1<<3};var QRErrorCorrectLevel={L:1,M:0,Q:3,H:2};var QRMaskPattern={PATTERN000:0,PATTERN001:1,PATTERN010:2,PATTERN011:3,PATTERN100:4,PATTERN101:5,PATTERN110:6,PATTERN111:7};var QRUtil=function(){var PATTERN_POSITION_TABLE=[[],[6,18],[6,22],[6,26],[6,30],[6,34],[6,22,38],[6,24,42],[6,26,46],[6,28,50],[6,30,54],[6,32,58],[6,34,62],[6,26,46,66],[6,26,48,70],[6,26,50,74],[6,30,54,78],[6,30,56,82],[6,30,58,86],[6,34,62,90],[6,28,50,72,94],[6,26,50,74,98],[6,30,54,78,102],[6,28,54,80,106],[6,32,58,84,110],[6,30,58,86,114],[6,34,62,90,118],[6,26,50,74,98,122],[6,30,54,78,102,126],[6,26,52,78,104,130],[6,30,56,82,108,134],[6,34,60,86,112,138],[6,30,58,86,114,142],[6,34,62,90,118,146],[6,30,54,78,102,126,150],[6,24,50,76,102,128,154],[6,28,54,80,106,132,158],[6,32,58,84,110,136,162],[6,26,54,82,110,138,166],[6,30,58,86,114,142,170]];var G15=(1<<10)|(1<<8)|(1<<5)|(1<<4)|(1<<2)|(1<<1)|(1<<0);var G18=(1<<12)|(1<<11)|(1<<10)|(1<<9)|(1<<8)|(1<<5)|(1<<2)|(1<<0);var G15_MASK=(1<<14)|(1<<12)|(1<<10)|(1<<4)|(1<<1);var _this={};var getBCHDigit=function(data){var digit=0;while(data!=0){digit+=1;data>>>=1;}
return digit;};_this.getBCHTypeInfo=function(data){var d=data<<10;while(getBCHDigit(d)-getBCHDigit(G15)>=0){d^=(G15<<(getBCHDigit(d)-getBCHDigit(G15)));}
return((data<<10)|d)^G15_MASK;};_this.getBCHTypeNumber=function(data){var d=data<<12;while(getBCHDigit(d)-getBCHDigit(G18)>=0){d^=(G18<<(getBCHDigit(d)-getBCHDigit(G18)));}
return(data<<12)|d;};_this.getPatternPosition=function(typeNumber){return PATTERN_POSITION_TABLE[typeNumber-1];};_this.getMaskFunction=function(maskPattern){switch(maskPattern){case QRMaskPattern.PATTERN000:return function(i,j){return(i+j)%2==0;};case QRMaskPattern.PATTERN001:return function(i,j){return i%2==0;};case QRMaskPattern.PATTERN010:return function(i,j){return j%3==0;};case QRMaskPattern.PATTERN011:return function(i,j){return(i+j)%3==0;};case QRMaskPattern.PATTERN100:return function(i,j){return(Math.floor(i/2)+Math.floor(j/3))%2==0;};case QRMaskPattern.PATTERN101:return function(i,j){return(i*j)%2+(i*j)%3==0;};case QRMaskPattern.PATTERN110:return function(i,j){return((i*j)%2+(i*j)%3)%2==0;};case QRMaskPattern.PATTERN111:return function(i,j){return((i*j)%3+(i+j)%2)%2==0;};default:throw new Error('bad maskPattern:'+maskPattern);}};_this.getErrorCorrectPolynomial=function(errorCorrectLength){var a=qrPolynomial([1],0);for(var i=0;i<errorCorrectLength;i+=1){a=a.multiply(qrPolynomial([1,QRMath.gexp(i)],0));}
return a;};_this.getLengthInBits=function(mode,type){if(1<=type&&type<10){switch(mode){case QRMode.MODE_NUMBER:return 10;case QRMode.MODE_ALPHA_NUM:return 9;case QRMode.MODE_8BIT_BYTE:return 8;case QRMode.MODE_KANJI:return 8;default:throw new Error('mode:'+mode);}}else if(type<27){switch(mode){case QRMode.MODE_NUMBER:return 12;case QRMode.MODE_ALPHA_NUM:return 11;case QRMode.MODE_8BIT_BYTE:return 16;case QRMode.MODE_KANJI:return 10;default:throw new Error('mode:'+mode);}}else if(type<41){switch(mode){case QRMode.MODE_NUMBER:return 14;case QRMode.MODE_ALPHA_NUM:return 13;case QRMode.MODE_8BIT_BYTE:return 16;case QRMode.MODE_KANJI:return 12;default:throw new Error('mode:'+mode);}}else{throw new Error('type:'+type);}};_this.getLostPoint=function(qrcode){var moduleCount=qrcode.getModuleCount();var lostPoint=0;for(var row=0;row<moduleCount;row+=1){for(var col=0;col<moduleCount;col+=1){var sameCount=0;var dark=qrcode.isDark(row,col);for(var r=-1;r<=1;r+=1){if(row+r<0||moduleCount<=row+r){continue;}
for(var c=-1;c<=1;c+=1){if(col+c<0||moduleCount<=col+c){continue;}
if(r==0&&c==0){continue;}
if(dark==qrcode.isDark(row+r,col+c)){sameCount+=1;}}}
if(sameCount>5){lostPoint+=(3+sameCount-5);}}};for(var row=0;row<moduleCount-1;row+=1){for(var col=0;col<moduleCount-1;col+=1){var count=0;if(qrcode.isDark(row,col))count+=1;if(qrcode.isDark(row+1,col))count+=1;if(qrcode.isDark(row,col+1))count+=1;if(qrcode.isDark(row+1,col+1))count+=1;if(count==0||count==4){lostPoint+=3;}}}
for(var row=0;row<moduleCount;row+=1){for(var col=0;col<moduleCount-6;col+=1){if(qrcode.isDark(row,col)&&!qrcode.isDark(row,col+1)&&qrcode.isDark(row,col+2)&&qrcode.isDark(row,col+3)&&qrcode.isDark(row,col+4)&&!qrcode.isDark(row,col+5)&&qrcode.isDark(row,col+6)){lostPoint+=40;}}}
for(var col=0;col<moduleCount;col+=1){for(var row=0;row<moduleCount-6;row+=1){if(qrcode.isDark(row,col)&&!qrcode.isDark(row+1,col)&&qrcode.isDark(row+2,col)&&qrcode.isDark(row+3,col)&&qrcode.isDark(row+4,col)&&!qrcode.isDark(row+5,col)&&qrcode.isDark(row+6,col)){lostPoint+=40;}}}
var darkCount=0;for(var col=0;col<moduleCount;col+=1){for(var row=0;row<moduleCount;row+=1){if(qrcode.isDark(row,col)){darkCount+=1;}}}
var ratio=Math.abs(100*darkCount/moduleCount/moduleCount-50)/5;lostPoint+=ratio*10;return lostPoint;};return _this;}();var QRMath=function(){var EXP_TABLE=new Array(256);var LOG_TABLE=new Array(256);for(var i=0;i<8;i+=1){EXP_TABLE[i]=1<<i;}
for(var i=8;i<256;i+=1){EXP_TABLE[i]=EXP_TABLE[i-4]^EXP_TABLE[i-5]^EXP_TABLE[i-6]^EXP_TABLE[i-8];}
for(var i=0;i<255;i+=1){LOG_TABLE[EXP_TABLE[i]]=i;}
var _this={};_this.glog=function(n){if(n<1){throw new Error('glog('+n+')');}
return LOG_TABLE[n];};_this.gexp=function(n){while(n<0){n+=255;}
while(n>=256){n-=255;}
return EXP_TABLE[n];};return _this;}();function qrPolynomial(num,shift){if(typeof num.length=='undefined'){throw new Error(num.length+'/'+shift);}
var _num=function(){var offset=0;while(offset<num.length&&num[offset]==0){offset+=1;}
var _num=new Array(num.length-offset+shift);for(var i=0;i<num.length-offset;i+=1){_num[i]=num[i+offset];}
return _num;}();var _this={};_this.getAt=function(index){return _num[index];};_this.getLength=function(){return _num.length;};_this.multiply=function(e){var num=new Array(_this.getLength()+e.getLength()-1);for(var i=0;i<_this.getLength();i+=1){for(var j=0;j<e.getLength();j+=1){num[i+j]^=QRMath.gexp(QRMath.glog(_this.getAt(i))+QRMath.glog(e.getAt(j)));}}
return qrPolynomial(num,0);};_this.mod=function(e){if(_this.getLength()-e.getLength()<0){return _this;}
var ratio=QRMath.glog(_this.getAt(0))-QRMath.glog(e.getAt(0));var num=new Array(_this.getLength());for(var i=0;i<_this.getLength();i+=1){num[i]=_this.getAt(i);}
for(var i=0;i<e.getLength();i+=1){num[i]^=QRMath.gexp(QRMath.glog(e.getAt(i))+ratio);}
return qrPolynomial(num,0).mod(e);};return _this;};var QRRSBlock=function(){var RS_BLOCK_TABLE=[[1,26,19],[1,26,16],[1,26,13],[1,26,9],[1,44,34],[1,44,28],[1,44,22],[1,44,16],[1,70,55],[1,70,44],[2,35,17],[2,35,13],[1,100,80],[2,50,32],[2,50,24],[4,25,9],[1,134,108],[2,67,43],[2,33,15,2,34,16],[2,33,11,2,34,12],[2,86,68],[4,43,27],[4,43,19],[4,43,15],[2,98,78],[4,49,31],[2,32,14,4,33,15],[4,39,13,1,40,14],[2,121,97],[2,60,38,2,61,39],[4,40,18,2,41,19],[4,40,14,2,41,15],[2,146,116],[3,58,36,2,59,37],[4,36,16,4,37,17],[4,36,12,4,37,13],[2,86,68,2,87,69],[4,69,43,1,70,44],[6,43,19,2,44,20],[6,43,15,2,44,16]];var qrRSBlock=function(totalCount,dataCount){var _this={};_this.totalCount=totalCount;_this.dataCount=dataCount;return _this;};var _this={};var getRsBlockTable=function(typeNumber,errorCorrectLevel){switch(errorCorrectLevel){case QRErrorCorrectLevel.L:return RS_BLOCK_TABLE[(typeNumber-1)*4+0];case QRErrorCorrectLevel.M:return RS_BLOCK_TABLE[(typeNumber-1)*4+1];case QRErrorCorrectLevel.Q:return RS_BLOCK_TABLE[(typeNumber-1)*4+2];case QRErrorCorrectLevel.H:return RS_BLOCK_TABLE[(typeNumber-1)*4+3];default:return undefined;}};_this.getRSBlocks=function(typeNumber,errorCorrectLevel){var rsBlock=getRsBlockTable(typeNumber,errorCorrectLevel);if(typeof rsBlock=='undefined'){throw new Error('bad rs block @ typeNumber:'+typeNumber+'/errorCorrectLevel:'+errorCorrectLevel);}
var length=rsBlock.length/3;var list=new Array();for(var i=0;i<length;i+=1){var count=rsBlock[i*3+0];var totalCount=rsBlock[i*3+1];var dataCount=rsBlock[i*3+2];for(var j=0;j<count;j+=1){list.push(qrRSBlock(totalCount,dataCount));}}
return list;};return _this;}();var qrBitBuffer=function(){var _buffer=new Array();var _length=0;var _this={};_this.getBuffer=function(){return _buffer;};_this.getAt=function(index){var bufIndex=Math.floor(index/8);return((_buffer[bufIndex]>>>(7-index%8))&1)==1;};_this.put=function(num,length){for(var i=0;i<length;i+=1){_this.putBit(((num>>>(length-i-1))&1)==1);}};_this.getLengthInBits=function(){return _length;};_this.putBit=function(bit){var bufIndex=Math.floor(_length/8);if(_buffer.length<=bufIndex){_buffer.push(0);}
if(bit){_buffer[bufIndex]|=(0x80>>>(_length%8));}
_length+=1;};return _this;};var qr8BitByte=function(data){var _mode=QRMode.MODE_8BIT_BYTE;var _data=data;var _bytes=qrcode.stringToBytes(data);var _this={};_this.getMode=function(){return _mode;};_this.getLength=function(buffer){return _bytes.length;};_this.write=function(buffer){for(var i=0;i<_bytes.length;i+=1){buffer.put(_bytes[i],8);}};return _this;};var byteArrayOutputStream=function(){var _bytes=new Array();var _this={};_this.writeByte=function(b){_bytes.push(b&0xff);};_this.writeShort=function(i){_this.writeByte(i);_this.writeByte(i>>>8);};_this.writeBytes=function(b,off,len){off=off||0;len=len||b.length;for(var i=0;i<len;i+=1){_this.writeByte(b[i+off]);}};_this.writeString=function(s){for(var i=0;i<s.length;i+=1){_this.writeByte(s.charCodeAt(i));}};_this.toByteArray=function(){return _bytes;};_this.toString=function(){var s='';s+='[';for(var i=0;i<_bytes.length;i+=1){if(i>0){s+=',';}
s+=_bytes[i];}
s+=']';return s;};return _this;};var base64EncodeOutputStream=function(){var _buffer=0;var _buflen=0;var _length=0;var _base64='';var _this={};var writeEncoded=function(b){_base64+=String.fromCharCode(encode(b&0x3f));};var encode=function(n){if(n<0){}else if(n<26){return 0x41+n;}else if(n<52){return 0x61+(n-26);}else if(n<62){return 0x30+(n-52);}else if(n==62){return 0x2b;}else if(n==63){return 0x2f;}
throw new Error('n:'+n);};_this.writeByte=function(n){_buffer=(_buffer<<8)|(n&0xff);_buflen+=8;_length+=1;while(_buflen>=6){writeEncoded(_buffer>>>(_buflen-6));_buflen-=6;}};_this.flush=function(){if(_buflen>0){writeEncoded(_buffer<<(6-_buflen));_buffer=0;_buflen=0;}
if(_length%3!=0){var padlen=3-_length%3;for(var i=0;i<padlen;i+=1){_base64+='=';}}};_this.toString=function(){return _base64;};return _this;};var base64DecodeInputStream=function(str){var _str=str;var _pos=0;var _buffer=0;var _buflen=0;var _this={};_this.read=function(){while(_buflen<8){if(_pos>=_str.length){if(_buflen==0){return-1;}
throw new Error('unexpected end of file./'+_buflen);}
var c=_str.charAt(_pos);_pos+=1;if(c=='='){_buflen=0;return-1;}else if(c.match(/^\s$/)){continue;}
_buffer=(_buffer<<6)|decode(c.charCodeAt(0));_buflen+=6;}
var n=(_buffer>>>(_buflen-8))&0xff;_buflen-=8;return n;};var decode=function(c){if(0x41<=c&&c<=0x5a){return c-0x41;}else if(0x61<=c&&c<=0x7a){return c-0x61+26;}else if(0x30<=c&&c<=0x39){return c-0x30+52;}else if(c==0x2b){return 62;}else if(c==0x2f){return 63;}else{throw new Error('c:'+c);}};return _this;};var gifImage=function(width,height){var _width=width;var _height=height;var _data=new Array(width*height);var _this={};_this.setPixel=function(x,y,pixel){_data[y*_width+x]=pixel;};_this.write=function(out){out.writeString('GIF87a');out.writeShort(_width);out.writeShort(_height);out.writeByte(0x80);out.writeByte(0);out.writeByte(0);out.writeByte(0x00);out.writeByte(0x00);out.writeByte(0x00);out.writeByte(0xff);out.writeByte(0xff);out.writeByte(0xff);out.writeString(',');out.writeShort(0);out.writeShort(0);out.writeShort(_width);out.writeShort(_height);out.writeByte(0);var lzwMinCodeSize=2;var raster=getLZWRaster(lzwMinCodeSize);out.writeByte(lzwMinCodeSize);var offset=0;while(raster.length-offset>255){out.writeByte(255);out.writeBytes(raster,offset,255);offset+=255;}
out.writeByte(raster.length-offset);out.writeBytes(raster,offset,raster.length-offset);out.writeByte(0x00);out.writeString(';');};var bitOutputStream=function(out){var _out=out;var _bitLength=0;var _bitBuffer=0;var _this={};_this.write=function(data,length){if((data>>>length)!=0){throw new Error('length over');}
while(_bitLength+length>=8){_out.writeByte(0xff&((data<<_bitLength)|_bitBuffer));length-=(8-_bitLength);data>>>=(8-_bitLength);_bitBuffer=0;_bitLength=0;}
_bitBuffer=(data<<_bitLength)|_bitBuffer;_bitLength=_bitLength+length;};_this.flush=function(){if(_bitLength>0){_out.writeByte(_bitBuffer);}};return _this;};var getLZWRaster=function(lzwMinCodeSize){var clearCode=1<<lzwMinCodeSize;var endCode=(1<<lzwMinCodeSize)+1;var bitLength=lzwMinCodeSize+1;var table=lzwTable();for(var i=0;i<clearCode;i+=1){table.add(String.fromCharCode(i));}
table.add(String.fromCharCode(clearCode));table.add(String.fromCharCode(endCode));var byteOut=byteArrayOutputStream();var bitOut=bitOutputStream(byteOut);bitOut.write(clearCode,bitLength);var dataIndex=0;var s=String.fromCharCode(_data[dataIndex]);dataIndex+=1;while(dataIndex<_data.length){var c=String.fromCharCode(_data[dataIndex]);dataIndex+=1;if(table.contains(s+c)){s=s+c;}else{bitOut.write(table.indexOf(s),bitLength);if(table.size()<0xfff){if(table.size()==(1<<bitLength)){bitLength+=1;}
table.add(s+c);}
s=c;}}
bitOut.write(table.indexOf(s),bitLength);bitOut.write(endCode,bitLength);bitOut.flush();return byteOut.toByteArray();};var lzwTable=function(){var _map={};var _size=0;var _this={};_this.add=function(key){if(_this.contains(key)){throw new Error('dup key:'+key);}
_map[key]=_size;_size+=1;};_this.size=function(){return _size;};_this.indexOf=function(key){return _map[key];};_this.contains=function(key){return typeof _map[key]!='undefined';};return _this;};return _this;};var createImgTag=function(width,height,getPixel,alt){var gif=gifImage(width,height);for(var y=0;y<height;y+=1){for(var x=0;x<width;x+=1){gif.setPixel(x,y,getPixel(x,y));}}
var b=byteArrayOutputStream();gif.write(b);var base64=base64EncodeOutputStream();var bytes=b.toByteArray();for(var i=0;i<bytes.length;i+=1){base64.writeByte(bytes[i]);}
base64.flush();var img='';img+='<img';img+='\u0020src="';img+='data:image/gif;base64,';img+=base64;img+='"';img+='\u0020width="';img+=width;img+='"';img+='\u0020height="';img+=height;img+='"';if(alt){img+='\u0020alt="';img+=alt;img+='"';}
img+='/>';return img;};return qrcode;}();/* |xGv00|ca8fc6bde81a353e7cede123b304bdb9 */
15. [代码]refund.php
<?php
/**
* 退款申请接口-demo
* ====================================================
* 注意:同一笔单的部分退款需要设置相同的订单号和不同的
* out_refund_no。一笔退款失败后重新提交,要采用原来的
* out_refund_no。总退款金额不能超过用户实际支付金额(现
* 金券金额不能退款)。
*/
include_once("../WxPayPubHelper/WxPayPubHelper.php");
//输入需退款的订单号
if (!isset($_POST["out_trade_no"]) || !isset($_POST["refund_fee"]))
{
$out_trade_no = " ";
$refund_fee = "1";
}else{
$out_trade_no = $_POST["out_trade_no"];
$refund_fee = $_POST["refund_fee"];
//商户退款单号,商户自定义,此处仅作举例
$out_refund_no = "$out_trade_no"."$time_stamp";
//总金额需与订单号out_trade_no对应,demo中的所有订单的总金额为1分
$total_fee = "1";
//使用退款接口
$refund = new Refund_pub();
//设置必填参数
//appid已填,商户无需重复填写
//mch_id已填,商户无需重复填写
//noncestr已填,商户无需重复填写
//sign已填,商户无需重复填写
$refund->setParameter("out_trade_no","$out_trade_no");//商户订单号
$refund->setParameter("out_refund_no","$out_refund_no");//商户退款单号
$refund->setParameter("total_fee","$total_fee");//总金额
$refund->setParameter("refund_fee","$refund_fee");//退款金额
$refund->setParameter("op_user_id",WxPayConf_pub::MCHID);//操作员
//非必填参数,商户可根据实际情况选填
//$refund->setParameter("sub_mch_id","XXXX");//子商户号
//$refund->setParameter("device_info","XXXX");//设备号
//$refund->setParameter("transaction_id","XXXX");//微信订单号
//调用结果
$refundResult = $refund->getResult();
//商户根据实际情况设置相应的处理流程,此处仅作举例
if ($refundResult["return_code"] == "FAIL") {
echo "通信出错:".$refundResult['return_msg']."<br>";
}
else{
echo "业务结果:".$refundResult['result_code']."<br>";
echo "错误代码:".$refundResult['err_code']."<br>";
echo "错误代码描述:".$refundResult['err_code_des']."<br>";
echo "公众账号ID:".$refundResult['appid']."<br>";
echo "商户号:".$refundResult['mch_id']."<br>";
echo "子商户号:".$refundResult['sub_mch_id']."<br>";
echo "设备号:".$refundResult['device_info']."<br>";
echo "签名:".$refundResult['sign']."<br>";
echo "微信订单号:".$refundResult['transaction_id']."<br>";
echo "商户订单号:".$refundResult['out_trade_no']."<br>";
echo "商户退款单号:".$refundResult['out_refund_no']."<br>";
echo "微信退款单号:".$refundResult['refund_idrefund_id']."<br>";
echo "退款渠道:".$refundResult['refund_channel']."<br>";
echo "退款金额:".$refundResult['refund_fee']."<br>";
echo "现金券退款金额:".$refundResult['coupon_refund_fee']."<br>";
}
}
?>
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<title>微信安全支付</title>
</head>
<body>
</br></br></br></br>
<div align="center">
<form action="./refund.php" method="post">
<p>申请退款:</p>
<p>退款单号: <input type="text" name="out_trade_no" value=<?php echo $out_trade_no; ?> ></p>
<p>退款金额(分): <input type="text" name="refund_fee" value=<?php echo $refund_fee; ?> ></p>
<button type="submit" >提交</button>
</form>
</br>
<a href="../index.php">返回首页</a>
</div>
</body>
</html>
16. [代码]refund_query.php
<?php
/**
* 退款申请接口-demo
* ====================================================
*
*
*/
include_once("../WxPayPubHelper/WxPayPubHelper.php");
//要查询的订单号
if (!isset($_POST["out_trade_no"]))
{
$out_trade_no = " ";
}else{
$out_trade_no = $_POST["out_trade_no"];
//使用退款查询接口
$refundQuery = new RefundQuery_pub();
//设置必填参数
//appid已填,商户无需重复填写
//mch_id已填,商户无需重复填写
//noncestr已填,商户无需重复填写
//sign已填,商户无需重复填写
$refundQuery->setParameter("out_trade_no","$out_trade_no");//商户订单号
// $refundQuery->setParameter("out_refund_no","XXXX");//商户退款单号
// $refundQuery->setParameter("refund_id","XXXX");//微信退款单号
// $refundQuery->setParameter("transaction_id","XXXX");//微信退款单号
//非必填参数,商户可根据实际情况选填
//$refundQuery->setParameter("sub_mch_id","XXXX");//子商户号
//$refundQuery->setParameter("device_info","XXXX");//设备号
//退款查询接口结果
$refundQueryResult = $refundQuery->getResult();
//商户根据实际情况设置相应的处理流程,此处仅作举例
if ($refundQueryResult["return_code"] == "FAIL") {
echo "通信出错:".$refundQueryResult['return_msg']."<br>";
}
else{
echo "业务结果:".$refundQueryResult['result_code']."<br>";
echo "错误代码:".$refundQueryResult['err_code']."<br>";
echo "错误代码描述:".$refundQueryResult['err_code_des']."<br>";
echo "公众账号ID:".$refundQueryResult['appid']."<br>";
echo "商户号:".$refundQueryResult['mch_id']."<br>";
echo "子商户号:".$refundQueryResult['sub_mch_id']."<br>";
echo "设备号:".$refundQueryResult['device_info']."<br>";
echo "签名:".$refundQueryResult['sign']."<br>";
echo "微信订单号:".$refundQueryResult['transaction_id']."<br>";
echo "商户订单号:".$refundQueryResult['out_trade_no']."<br>";
echo "退款笔数:".$refundQueryResult['refund_count']."<br>";
echo "商户退款单号:".$refundQueryResult['out_refund_no']."<br>";
echo "微信退款单号:".$refundQueryResult['refund_idrefund_id']."<br>";
echo "退款渠道:".$refundQueryResult['refund_channel']."<br>";
echo "退款金额:".$refundQueryResult['refund_fee']."<br>";
echo "现金券退款金额:".$refundQueryResult['coupon_refund_fee']."<br>";
echo "退款状态:".$refundQueryResult['refund_status']."<br>";
}
}
?>
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<title>微信安全支付</title>
</head>
<body>
</br></br></br></br>
<div align="center">
<form action="./refund_query.php" method="post">
<p>退款查询</p>
<p>单号: <input type="text" name="out_trade_no"></p>
<button type="submit" >提交</button>
</form>
</br>
<a href="../index.php">返回首页</a>
</div>
</body>
</html>
