2020.02新版
This commit is contained in:
26
plugins/wxpay/cert/apiclient_cert.pem
Normal file
26
plugins/wxpay/cert/apiclient_cert.pem
Normal file
@@ -0,0 +1,26 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEaTCCA9KgAwIBAgIEANG/jDANBgkqhkiG9w0BAQUFADCBijELMAkGA1UEBhMC
|
||||
Q04xEjAQBgNVBAgTCUd1YW5nZG9uZzERMA8GA1UEBxMIU2hlbnpoZW4xEDAOBgNV
|
||||
BAoTB1RlbmNlbnQxDDAKBgNVBAsTA1dYRzETMBEGA1UEAxMKTW1wYXltY2hDQTEf
|
||||
MB0GCSqGSIb3DQEJARYQbW1wYXltY2hAdGVuY2VudDAeFw0xNzAzMjkwNTAwMTVa
|
||||
Fw0yNzAzMjcwNTAwMTVaMIGYMQswCQYDVQQGEwJDTjESMBAGA1UECBMJR3Vhbmdk
|
||||
b25nMREwDwYDVQQHEwhTaGVuemhlbjEQMA4GA1UEChMHVGVuY2VudDEOMAwGA1UE
|
||||
CxMFTU1QYXkxLTArBgNVBAMUJOmDkeW3nui/veaipue9kee7nOenkeaKgOaciemZ
|
||||
kOWFrOWPuDERMA8GA1UEBBMIMjMxNzM3OTQwggEiMA0GCSqGSIb3DQEBAQUAA4IB
|
||||
DwAwggEKAoIBAQDY/WCuI8RuyJpasVZqBBmUxqxjM4gmF7Wj1U/gp+wGusRs9gtO
|
||||
Bf4NTlfZDO9ou5sdWYa3kJwahVIeItfkgGiv8177ahDiTgfvdvx4+BLrn05FhrhF
|
||||
+EvPwsuxE/FA3Isz/QK2rsszZOPQMhEOAkGQxqXC/V6q46vyYa+SmUoxkMRC6Wfz
|
||||
Wu2lLPE0CAzgiLndWyIRM3vaoCbbFcTWh5BwBUVTG6hg47LBSG7a5eZQi+c0RwIh
|
||||
nT4CWXQC1c7WbI8StUqFfSPrRE3m8GpeLrj72GZ9UaYJq70zMXjq/V/+I7r82Gnb
|
||||
+3sWAtxNb/PMTRhTAWIYMZzFA4ipPcIOh98xAgMBAAGjggFGMIIBQjAJBgNVHRME
|
||||
AjAAMCwGCWCGSAGG+EIBDQQfFh0iQ0VTLUNBIEdlbmVyYXRlIENlcnRpZmljYXRl
|
||||
IjAdBgNVHQ4EFgQUDv+iqN6c2wuMEtuh30OQNIIL/NYwgb8GA1UdIwSBtzCBtIAU
|
||||
PgUm9iJitBVbiM1kfrDUYqflhnShgZCkgY0wgYoxCzAJBgNVBAYTAkNOMRIwEAYD
|
||||
VQQIEwlHdWFuZ2RvbmcxETAPBgNVBAcTCFNoZW56aGVuMRAwDgYDVQQKEwdUZW5j
|
||||
ZW50MQwwCgYDVQQLEwNXWEcxEzARBgNVBAMTCk1tcGF5bWNoQ0ExHzAdBgkqhkiG
|
||||
9w0BCQEWEG1tcGF5bWNoQHRlbmNlbnSCCQC7VJcrvADoVzAOBgNVHQ8BAf8EBAMC
|
||||
BsAwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwIwDQYJKoZIhvcNAQEFBQADgYEAivnt
|
||||
rYQqtdb7Z5USL6qSrhEHm62m8VYlQEYEENr+AUs5C7SaHunHM6TVLeTIY6Cnl2C8
|
||||
NQDnBWWc5BiciwygAvfnXnM7VU60llLnuksFWkLqfqEx7ZI9FquTvXqMcicwv8bx
|
||||
5B6HrkdgmF2H5/EYkvVnFTXk5/wXBnKiLg5hz4s=
|
||||
-----END CERTIFICATE-----
|
||||
28
plugins/wxpay/cert/apiclient_key.pem
Normal file
28
plugins/wxpay/cert/apiclient_key.pem
Normal file
@@ -0,0 +1,28 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDY/WCuI8RuyJpa
|
||||
sVZqBBmUxqxjM4gmF7Wj1U/gp+wGusRs9gtOBf4NTlfZDO9ou5sdWYa3kJwahVIe
|
||||
ItfkgGiv8177ahDiTgfvdvx4+BLrn05FhrhF+EvPwsuxE/FA3Isz/QK2rsszZOPQ
|
||||
MhEOAkGQxqXC/V6q46vyYa+SmUoxkMRC6WfzWu2lLPE0CAzgiLndWyIRM3vaoCbb
|
||||
FcTWh5BwBUVTG6hg47LBSG7a5eZQi+c0RwIhnT4CWXQC1c7WbI8StUqFfSPrRE3m
|
||||
8GpeLrj72GZ9UaYJq70zMXjq/V/+I7r82Gnb+3sWAtxNb/PMTRhTAWIYMZzFA4ip
|
||||
PcIOh98xAgMBAAECggEATG7sGEsXDWLyJBIle1CYZjSZUpQ7WBev7tbbvSnJVRGC
|
||||
0VLV5pTryWoYPad1yXGUEQGRF6YDpr/hjiX94EpvFdNnWK4i5mRQHUTPaBkSKRdD
|
||||
bfAnhtYQdk2KjISWzZ8iFZ0A0LK/dwoJyTNpmIKo78NZblbresyZq9ZHDx+Z590N
|
||||
btQE8d5mWjsWOfXkmUd4QSwuVzpqWQhTUEKcNRXHm2lNYxAE+nMIBT7hn1MNm/3p
|
||||
0v1pIqkLl4Lw+Xe92xeHWAK+xnHA62nURvxTjK2iSvEilFSBvlghfD7RxSLMRVb1
|
||||
tvbuD8YGUFXoOKSCZLs64SdqLLQBnpXe0Q04BdWqZQKBgQD0R0q2TtPIXiskVkVE
|
||||
QtCALOxEmQv4RHFTU4ZRQRujRROxlNVeCCS2/rciaLTGtORwrtvQne2lUbKC7Ilg
|
||||
X19YEjjC/RyjNSxhhBhuK/08WeRTG2I0sA4yCiAcAuTN25h/r4SzUF5BnDal4ob9
|
||||
3jbFDwBjptH3NBqaKRyWRuBp4wKBgQDjZt8/hbqK8xaZWBkvvCjPhdKTZfs/5xs0
|
||||
iJevjw5vRzYwlqLouJS6N+JMJPUbq7eLcrJ2xGm9vqyi5uTw7y3shOeUCh4g3QJV
|
||||
7S2LoIJXIf+i3/oh1yCRPo5JEW5gYtlbMjecsvsS1gxkY2131x0xpjV0WDiCLE0K
|
||||
8iD1oSeu2wKBgGHjJ6dCk09ZnQQkpgEinRaf6dXbVpaYJqlzcQGii4azqZ6hu5bA
|
||||
wKWsEIrzVm3CE0CscV15y79Rq60XSD2cOkK6mpBYiV9FcZFqM7gCXKoQg5RiBsqC
|
||||
Ok4HDLLs3e84LjYMiaqpa/vys1tqGRomL+BrkIZeVQkwkfBwxQnbQRZtAoGACtRO
|
||||
U2cZ8B4NeHYClQxf4SodUhmsMmneGM1cc+bbKB97DCtQTMblhky9ASVNaujtj72B
|
||||
lDhcVMXs0MEwK+0oAbh+ksU8lBISV2c5IQoeyul6lBYYgl4NVf1lp0MmP37VnQsy
|
||||
LMs1O7tn0awOfYOIB2JD72t4HXLgpGHNggUPr7sCgYEA5L3VNRo5OFb7O9kpDWBh
|
||||
VZllfyaPz/C2UOnMjbmUYRsVDIAeWun/Rb8gOqgZh1H74Cm2WbBmutgUDX6HJ1TW
|
||||
NklWS1x9cByxLcvDCdfWJJ0yGoYbhFjGAM0+pwg5kWGM+6TugdOHvKxLO/X9dziR
|
||||
4t0uaLPYY5bneoNkXdstRBk=
|
||||
-----END PRIVATE KEY-----
|
||||
21
plugins/wxpay/config.ini
Normal file
21
plugins/wxpay/config.ini
Normal file
@@ -0,0 +1,21 @@
|
||||
[config]
|
||||
;支付插件英文名称,需和目录名称一致,不能有重复
|
||||
name = "wxpay"
|
||||
|
||||
;支付插件显示名称
|
||||
showname = "微信官方支付"
|
||||
|
||||
;支付插件作者
|
||||
author = "微信"
|
||||
|
||||
;支付插件作者链接
|
||||
link = "https://pay.weixin.qq.com/"
|
||||
|
||||
;支付插件支持的支付方式,多种方式用英文,隔开,可选的有alipay,qqpay,wxpay,bank
|
||||
types = "wxpay"
|
||||
|
||||
;支付插件要求传入的参数以及参数显示名称,可选的有appid,appkey,appsecret,appurl,appmchid
|
||||
inputs = "appid:公众号APPID,appmchid:商户号,appkey:商户支付密钥,appsecret:公众号SECRET"
|
||||
|
||||
;支付插件要求传入的支付方式参数
|
||||
select = "1:扫码支付,2:公众号支付,3:H5支付"
|
||||
32
plugins/wxpay/h5.php
Normal file
32
plugins/wxpay/h5.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
/*
|
||||
* 微信H5支付
|
||||
*/
|
||||
if(!defined('IN_PLUGIN'))exit();
|
||||
|
||||
@header('Content-Type: text/html; charset=UTF-8');
|
||||
|
||||
require_once PAY_ROOT."inc/WxPay.Api.php";
|
||||
require_once PAY_ROOT."inc/WxPay.NativePay.php";
|
||||
$notify = new NativePay();
|
||||
$input = new WxPayUnifiedOrder();
|
||||
$input->SetBody($ordername);
|
||||
$input->SetOut_trade_no(TRADE_NO);
|
||||
$input->SetTotal_fee(strval($order['money']*100));
|
||||
$input->SetSpbill_create_ip($clientip);
|
||||
$input->SetTime_start(date("YmdHis"));
|
||||
$input->SetTime_expire(date("YmdHis", time() + 600));
|
||||
$input->SetNotify_url($conf['localurl'].'pay/wxpay/notify/'.TRADE_NO.'/');
|
||||
$input->SetTrade_type("MWEB");
|
||||
$result = $notify->GetPayUrl($input);
|
||||
if($result["result_code"]=='SUCCESS'){
|
||||
$redirect_url=$siteurl.'pay/wxpay/return/'.TRADE_NO.'/';
|
||||
$url=$result['mweb_url'].'&redirect_url='.urlencode($redirect_url);
|
||||
exit("<script>window.location.replace('{$url}');</script>");
|
||||
}elseif(isset($result["err_code"])){
|
||||
sysmsg('微信支付下单失败!['.$result["err_code"].'] '.$result["err_code_des"]);
|
||||
}else{
|
||||
sysmsg('微信支付下单失败!['.$result["return_code"].'] '.$result["return_msg"]);
|
||||
}
|
||||
|
||||
?>
|
||||
616
plugins/wxpay/inc/WxPay.Api.php
Normal file
616
plugins/wxpay/inc/WxPay.Api.php
Normal file
@@ -0,0 +1,616 @@
|
||||
<?php
|
||||
require_once PAY_ROOT."inc/WxPay.Exception.php";
|
||||
require_once PAY_ROOT."inc/WxPay.Config.php";
|
||||
require_once PAY_ROOT."inc/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 WxPayUnifiedOrder $inputObj
|
||||
* @param int $timeOut
|
||||
* @throws WxPayException
|
||||
* @return 成功时返回,其他抛异常
|
||||
*/
|
||||
public static function unifiedOrder($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() == "JSAPI" && !$inputObj->IsProduct_idSet()){
|
||||
throw new WxPayException("统一支付接口中,缺少必填参数product_id!trade_type为JSAPI时,product_id为必填参数!");
|
||||
}
|
||||
|
||||
//异步通知url未设置,则使用配置文件中的url
|
||||
if(!$inputObj->IsNotify_urlSet()){
|
||||
$inputObj->SetNotify_url(WxPayConfig::NOTIFY_URL);//异步通知url
|
||||
}
|
||||
|
||||
$inputObj->SetAppid(WxPayConfig::APPID);//公众账号ID
|
||||
$inputObj->SetMch_id(WxPayConfig::MCHID);//商户号
|
||||
$inputObj->SetNonce_str(self::getNonceStr());//随机字符串
|
||||
|
||||
//签名
|
||||
$inputObj->SetSign();
|
||||
$xml = $inputObj->ToXml();
|
||||
|
||||
$startTimeStamp = self::getMillisecond();//请求开始时间
|
||||
$response = self::postXmlCurl($xml, $url, false, $timeOut);
|
||||
$result = WxPayResults::Init($response);
|
||||
self::reportCostTime($url, $startTimeStamp, $result);//上报请求花费时间
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* 查询订单,WxPayOrderQuery中out_trade_no、transaction_id至少填一个
|
||||
* appid、mchid、spbill_create_ip、nonce_str不需要填入
|
||||
* @param WxPayOrderQuery $inputObj
|
||||
* @param int $timeOut
|
||||
* @throws WxPayException
|
||||
* @return 成功时返回,其他抛异常
|
||||
*/
|
||||
public static function orderQuery($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(WxPayConfig::APPID);//公众账号ID
|
||||
$inputObj->SetMch_id(WxPayConfig::MCHID);//商户号
|
||||
$inputObj->SetNonce_str(self::getNonceStr());//随机字符串
|
||||
|
||||
$inputObj->SetSign();//签名
|
||||
$xml = $inputObj->ToXml();
|
||||
|
||||
$startTimeStamp = self::getMillisecond();//请求开始时间
|
||||
$response = self::postXmlCurl($xml, $url, false, $timeOut);
|
||||
$result = WxPayResults::Init($response);
|
||||
self::reportCostTime($url, $startTimeStamp, $result);//上报请求花费时间
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* 关闭订单,WxPayCloseOrder中out_trade_no必填
|
||||
* appid、mchid、spbill_create_ip、nonce_str不需要填入
|
||||
* @param WxPayCloseOrder $inputObj
|
||||
* @param int $timeOut
|
||||
* @throws WxPayException
|
||||
* @return 成功时返回,其他抛异常
|
||||
*/
|
||||
public static function closeOrder($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(WxPayConfig::APPID);//公众账号ID
|
||||
$inputObj->SetMch_id(WxPayConfig::MCHID);//商户号
|
||||
$inputObj->SetNonce_str(self::getNonceStr());//随机字符串
|
||||
|
||||
$inputObj->SetSign();//签名
|
||||
$xml = $inputObj->ToXml();
|
||||
|
||||
$startTimeStamp = self::getMillisecond();//请求开始时间
|
||||
$response = self::postXmlCurl($xml, $url, false, $timeOut);
|
||||
$result = WxPayResults::Init($response);
|
||||
self::reportCostTime($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 WxPayRefund $inputObj
|
||||
* @param int $timeOut
|
||||
* @throws WxPayException
|
||||
* @return 成功时返回,其他抛异常
|
||||
*/
|
||||
public static function refund($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(WxPayConfig::APPID);//公众账号ID
|
||||
$inputObj->SetMch_id(WxPayConfig::MCHID);//商户号
|
||||
$inputObj->SetNonce_str(self::getNonceStr());//随机字符串
|
||||
|
||||
$inputObj->SetSign();//签名
|
||||
$xml = $inputObj->ToXml();
|
||||
$startTimeStamp = self::getMillisecond();//请求开始时间
|
||||
$response = self::postXmlCurl($xml, $url, true, $timeOut);
|
||||
$result = WxPayResults::Init($response);
|
||||
self::reportCostTime($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 WxPayRefundQuery $inputObj
|
||||
* @param int $timeOut
|
||||
* @throws WxPayException
|
||||
* @return 成功时返回,其他抛异常
|
||||
*/
|
||||
public static function refundQuery($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(WxPayConfig::APPID);//公众账号ID
|
||||
$inputObj->SetMch_id(WxPayConfig::MCHID);//商户号
|
||||
$inputObj->SetNonce_str(self::getNonceStr());//随机字符串
|
||||
|
||||
$inputObj->SetSign();//签名
|
||||
$xml = $inputObj->ToXml();
|
||||
|
||||
$startTimeStamp = self::getMillisecond();//请求开始时间
|
||||
$response = self::postXmlCurl($xml, $url, false, $timeOut);
|
||||
$result = WxPayResults::Init($response);
|
||||
self::reportCostTime($url, $startTimeStamp, $result);//上报请求花费时间
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载对账单,WxPayDownloadBill中bill_date为必填参数
|
||||
* appid、mchid、spbill_create_ip、nonce_str不需要填入
|
||||
* @param WxPayDownloadBill $inputObj
|
||||
* @param int $timeOut
|
||||
* @throws WxPayException
|
||||
* @return 成功时返回,其他抛异常
|
||||
*/
|
||||
public static function downloadBill($inputObj, $timeOut = 6)
|
||||
{
|
||||
$url = "https://api.mch.weixin.qq.com/pay/downloadbill";
|
||||
//检测必填参数
|
||||
if(!$inputObj->IsBill_dateSet()) {
|
||||
throw new WxPayException("对账单接口中,缺少必填参数bill_date!");
|
||||
}
|
||||
$inputObj->SetAppid(WxPayConfig::APPID);//公众账号ID
|
||||
$inputObj->SetMch_id(WxPayConfig::MCHID);//商户号
|
||||
$inputObj->SetNonce_str(self::getNonceStr());//随机字符串
|
||||
|
||||
$inputObj->SetSign();//签名
|
||||
$xml = $inputObj->ToXml();
|
||||
|
||||
$response = self::postXmlCurl($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 WxPayWxPayMicroPay $inputObj
|
||||
* @param int $timeOut
|
||||
*/
|
||||
public static function micropay($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(WxPayConfig::APPID);//公众账号ID
|
||||
$inputObj->SetMch_id(WxPayConfig::MCHID);//商户号
|
||||
$inputObj->SetNonce_str(self::getNonceStr());//随机字符串
|
||||
|
||||
$inputObj->SetSign();//签名
|
||||
$xml = $inputObj->ToXml();
|
||||
|
||||
$startTimeStamp = self::getMillisecond();//请求开始时间
|
||||
$response = self::postXmlCurl($xml, $url, false, $timeOut);
|
||||
$result = WxPayResults::Init($response);
|
||||
self::reportCostTime($url, $startTimeStamp, $result);//上报请求花费时间
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* 撤销订单API接口,WxPayReverse中参数out_trade_no和transaction_id必须填写一个
|
||||
* appid、mchid、spbill_create_ip、nonce_str不需要填入
|
||||
* @param WxPayReverse $inputObj
|
||||
* @param int $timeOut
|
||||
* @throws WxPayException
|
||||
*/
|
||||
public static function reverse($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(WxPayConfig::APPID);//公众账号ID
|
||||
$inputObj->SetMch_id(WxPayConfig::MCHID);//商户号
|
||||
$inputObj->SetNonce_str(self::getNonceStr());//随机字符串
|
||||
|
||||
$inputObj->SetSign();//签名
|
||||
$xml = $inputObj->ToXml();
|
||||
|
||||
$startTimeStamp = self::getMillisecond();//请求开始时间
|
||||
$response = self::postXmlCurl($xml, $url, true, $timeOut);
|
||||
$result = WxPayResults::Init($response);
|
||||
self::reportCostTime($url, $startTimeStamp, $result);//上报请求花费时间
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* 企业付款,WxPayTransfer中partner_trade_no必填
|
||||
* partner_trade_no、openid、check_name、amount、desc为必填参数
|
||||
* appid、mchid、spbill_create_ip、nonce_str不需要填入
|
||||
* @param WxPayTransfer $inputObj
|
||||
* @param int $timeOut
|
||||
* @throws WxPayException
|
||||
* @return 成功时返回,其他抛异常
|
||||
*/
|
||||
public static function transfer($inputObj, $timeOut = 6)
|
||||
{
|
||||
$url = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers";
|
||||
//检测必填参数
|
||||
if(!$inputObj->IsPartner_trade_noSet()){
|
||||
throw new WxPayException("企业付款接口中,缺少必填参数partner_trade_no!");
|
||||
}else if(!$inputObj->IsOpenidSet()){
|
||||
throw new WxPayException("企业付款接口中,缺少必填参数openid!");
|
||||
}else if(!$inputObj->IsCheck_nameSet()){
|
||||
throw new WxPayException("企业付款接口中,缺少必填参数check_name!");
|
||||
}else if(!$inputObj->IsAmountSet()){
|
||||
throw new WxPayException("企业付款接口中,缺少必填参数amount!");
|
||||
}else if(!$inputObj->IsDescSet()){
|
||||
throw new WxPayException("企业付款接口中,缺少必填参数desc!");
|
||||
}
|
||||
$inputObj->SetAppid(WxPayConfig::APPID);//公众账号ID
|
||||
$inputObj->SetMch_id(WxPayConfig::MCHID);//商户号
|
||||
$inputObj->SetNonce_str(self::getNonceStr());//随机字符串
|
||||
|
||||
$inputObj->SetSign();//签名
|
||||
$xml = $inputObj->ToXml();
|
||||
$response = self::postXmlCurl($xml, $url, true, $timeOut);
|
||||
$result = WxPayResults::Init2($response);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* 测速上报,该方法内部封装在report中,使用时请注意异常流程
|
||||
* WxPayReport中interface_url、return_code、result_code、user_ip、execute_time_必填
|
||||
* appid、mchid、spbill_create_ip、nonce_str不需要填入
|
||||
* @param WxPayReport $inputObj
|
||||
* @param int $timeOut
|
||||
* @throws WxPayException
|
||||
* @return 成功时返回,其他抛异常
|
||||
*/
|
||||
public static function report($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(WxPayConfig::APPID);//公众账号ID
|
||||
$inputObj->SetMch_id(WxPayConfig::MCHID);//商户号
|
||||
$inputObj->SetUser_ip($_SERVER['REMOTE_ADDR']);//终端ip
|
||||
$inputObj->SetTime(date("YmdHis"));//商户上报时间
|
||||
$inputObj->SetNonce_str(self::getNonceStr());//随机字符串
|
||||
|
||||
$inputObj->SetSign();//签名
|
||||
$xml = $inputObj->ToXml();
|
||||
|
||||
$startTimeStamp = self::getMillisecond();//请求开始时间
|
||||
$response = self::postXmlCurl($xml, $url, false, $timeOut);
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* 生成二维码规则,模式一生成支付二维码
|
||||
* appid、mchid、spbill_create_ip、nonce_str不需要填入
|
||||
* @param WxPayBizPayUrl $inputObj
|
||||
* @param int $timeOut
|
||||
* @throws WxPayException
|
||||
* @return 成功时返回,其他抛异常
|
||||
*/
|
||||
public static function bizpayurl($inputObj, $timeOut = 6)
|
||||
{
|
||||
if(!$inputObj->IsProduct_idSet()){
|
||||
throw new WxPayException("生成二维码,缺少必填参数product_id!");
|
||||
}
|
||||
|
||||
$inputObj->SetAppid(WxPayConfig::APPID);//公众账号ID
|
||||
$inputObj->SetMch_id(WxPayConfig::MCHID);//商户号
|
||||
$inputObj->SetTime_stamp(time());//时间戳
|
||||
$inputObj->SetNonce_str(self::getNonceStr());//随机字符串
|
||||
|
||||
$inputObj->SetSign();//签名
|
||||
|
||||
return $inputObj->GetValues();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* 转换短链接
|
||||
* 该接口主要用于扫码原生支付模式一中的二维码链接转成短链接(weixin://wxpay/s/XXXXXX),
|
||||
* 减小二维码数据量,提升扫描速度和精确度。
|
||||
* appid、mchid、spbill_create_ip、nonce_str不需要填入
|
||||
* @param WxPayShortUrl $inputObj
|
||||
* @param int $timeOut
|
||||
* @throws WxPayException
|
||||
* @return 成功时返回,其他抛异常
|
||||
*/
|
||||
public static function shorturl($inputObj, $timeOut = 6)
|
||||
{
|
||||
$url = "https://api.mch.weixin.qq.com/tools/shorturl";
|
||||
//检测必填参数
|
||||
if(!$inputObj->IsLong_urlSet()) {
|
||||
throw new WxPayException("需要转换的URL,签名用原串,传输需URL encode!");
|
||||
}
|
||||
$inputObj->SetAppid(WxPayConfig::APPID);//公众账号ID
|
||||
$inputObj->SetMch_id(WxPayConfig::MCHID);//商户号
|
||||
$inputObj->SetNonce_str(self::getNonceStr());//随机字符串
|
||||
|
||||
$inputObj->SetSign();//签名
|
||||
$xml = $inputObj->ToXml();
|
||||
|
||||
$startTimeStamp = self::getMillisecond();//请求开始时间
|
||||
$response = self::postXmlCurl($xml, $url, false, $timeOut);
|
||||
$result = WxPayResults::Init($response);
|
||||
self::reportCostTime($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($callback, &$msg)
|
||||
{
|
||||
//获取通知的数据
|
||||
$xml = file_get_contents("php://input");
|
||||
//如果返回成功则验证签名
|
||||
try {
|
||||
$result = WxPayResults::Init($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 string $usrl
|
||||
* @param int $startTimeStamp
|
||||
* @param array $data
|
||||
*/
|
||||
private static function reportCostTime($url, $startTimeStamp, $data)
|
||||
{
|
||||
//如果不需要上报数据
|
||||
if(WxPayConfig::REPORT_LEVENL == 0){
|
||||
return;
|
||||
}
|
||||
//如果仅失败上报
|
||||
if(WxPayConfig::REPORT_LEVENL == 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($objInput);
|
||||
} catch (WxPayException $e){
|
||||
//不做任何处理
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 以post方式提交xml到对应的接口url
|
||||
*
|
||||
* @param string $xml 需要post的xml数据
|
||||
* @param string $url url
|
||||
* @param bool $useCert 是否需要证书,默认不需要
|
||||
* @param int $second url执行超时时间,默认30s
|
||||
* @throws WxPayException
|
||||
*/
|
||||
private static function postXmlCurl($xml, $url, $useCert = false, $second = 30)
|
||||
{
|
||||
$ch = curl_init();
|
||||
//设置超时
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT, $second);
|
||||
|
||||
//如果有配置代理这里就设置代理
|
||||
if(WxPayConfig::CURL_PROXY_HOST != "0.0.0.0"
|
||||
&& WxPayConfig::CURL_PROXY_PORT != 0){
|
||||
curl_setopt($ch,CURLOPT_PROXY, WxPayConfig::CURL_PROXY_HOST);
|
||||
curl_setopt($ch,CURLOPT_PROXYPORT, WxPayConfig::CURL_PROXY_PORT);
|
||||
}
|
||||
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);
|
||||
|
||||
if($useCert == true){
|
||||
//设置证书
|
||||
//使用证书:cert 与 key 分别属于两个.pem文件
|
||||
curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM');
|
||||
curl_setopt($ch,CURLOPT_SSLCERT, WxPayConfig::SSLCERT_PATH);
|
||||
curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM');
|
||||
curl_setopt($ch,CURLOPT_SSLKEY, WxPayConfig::SSLKEY_PATH);
|
||||
}
|
||||
//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
plugins/wxpay/inc/WxPay.Config.php
Normal file
63
plugins/wxpay/inc/WxPay.Config.php
Normal file
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
/**
|
||||
* 配置账号信息
|
||||
*/
|
||||
define("WX_API_APPID", $channel['appid']);
|
||||
define("WX_API_MCHID", $channel['appmchid']);
|
||||
define("WX_API_KEY", $channel['appkey']);
|
||||
define("WX_API_APPSECRET", $channel['appsecret']);
|
||||
|
||||
class WxPayConfig
|
||||
{
|
||||
//=======【基本信息设置】=====================================
|
||||
//
|
||||
/**
|
||||
* TODO: 修改这里配置为您自己申请的商户信息
|
||||
* 微信公众号信息配置
|
||||
*
|
||||
* APPID:绑定支付的APPID(必须配置,开户邮件中可查看)
|
||||
*
|
||||
* MCHID:商户号(必须配置,开户邮件中可查看)
|
||||
*
|
||||
* KEY:商户支付密钥,参考开户邮件设置(必须配置,登录商户平台自行设置)
|
||||
* 设置地址:https://pay.weixin.qq.com/index.php/account/api_cert
|
||||
*
|
||||
* APPSECRET:公众帐号secert(仅JSAPI支付的时候需要配置, 登录公众平台,进入开发者中心可设置),
|
||||
* 获取地址:https://mp.weixin.qq.com/advanced/advanced?action=dev&t=advanced/dev&token=2005451881&lang=zh_CN
|
||||
* @var string
|
||||
*/
|
||||
const APPID = WX_API_APPID;
|
||||
const MCHID = WX_API_MCHID;
|
||||
const KEY = WX_API_KEY;
|
||||
const APPSECRET = WX_API_APPSECRET;
|
||||
|
||||
//=======【证书路径设置】=====================================
|
||||
/**
|
||||
* TODO:设置商户证书路径
|
||||
* 证书路径,注意应该填写绝对路径(仅退款、撤销订单时需要,可登录商户平台下载,
|
||||
* API证书下载地址:https://pay.weixin.qq.com/index.php/account/api_cert,下载之前需要安装商户操作证书)
|
||||
* @var path
|
||||
*/
|
||||
const SSLCERT_PATH = PAY_ROOT.'cert/apiclient_cert.pem';
|
||||
const SSLKEY_PATH = PAY_ROOT.'cert/apiclient_key.pem';
|
||||
|
||||
//=======【curl代理设置】===================================
|
||||
/**
|
||||
* TODO:这里设置代理机器,只有需要代理的时候才设置,不需要代理,请设置为0.0.0.0和0
|
||||
* 本例程通过curl使用HTTP POST方法,此处可修改代理服务器,
|
||||
* 默认CURL_PROXY_HOST=0.0.0.0和CURL_PROXY_PORT=0,此时不开启代理(如有需要才设置)
|
||||
* @var unknown_type
|
||||
*/
|
||||
const CURL_PROXY_HOST = "0.0.0.0";//"10.152.18.220";
|
||||
const CURL_PROXY_PORT = 0;//8080;
|
||||
|
||||
//=======【上报信息配置】===================================
|
||||
/**
|
||||
* TODO:接口调用上报等级,默认紧错误上报(注意:上报超时间为【1s】,上报无论成败【永不抛出异常】,
|
||||
* 不会影响接口调用流程),开启上报之后,方便微信监控请求调用的质量,建议至少
|
||||
* 开启错误上报。
|
||||
* 上报等级,0.关闭上报; 1.仅错误出错上报; 2.全量上报
|
||||
* @var int
|
||||
*/
|
||||
const REPORT_LEVENL = 1;
|
||||
}
|
||||
3293
plugins/wxpay/inc/WxPay.Data.php
Normal file
3293
plugins/wxpay/inc/WxPay.Data.php
Normal file
File diff suppressed because it is too large
Load Diff
13
plugins/wxpay/inc/WxPay.Exception.php
Normal file
13
plugins/wxpay/inc/WxPay.Exception.php
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* 微信支付API异常类
|
||||
* @author widyhu
|
||||
*
|
||||
*/
|
||||
class WxPayException extends Exception {
|
||||
public function errorMessage()
|
||||
{
|
||||
return $this->getMessage();
|
||||
}
|
||||
}
|
||||
206
plugins/wxpay/inc/WxPay.JsApiPay.php
Normal file
206
plugins/wxpay/inc/WxPay.JsApiPay.php
Normal file
@@ -0,0 +1,206 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
*
|
||||
* 通过跳转获取用户的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']);
|
||||
$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->SetSignType("MD5");
|
||||
$jsapi->SetPaySign($jsapi->MakeSign());
|
||||
$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();
|
||||
//设置超时
|
||||
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_HEADER, FALSE);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
|
||||
if(WxPayConfig::CURL_PROXY_HOST != "0.0.0.0"
|
||||
&& WxPayConfig::CURL_PROXY_PORT != 0){
|
||||
curl_setopt($ch,CURLOPT_PROXY, WxPayConfig::CURL_PROXY_HOST);
|
||||
curl_setopt($ch,CURLOPT_PROXYPORT, WxPayConfig::CURL_PROXY_PORT);
|
||||
}
|
||||
//运行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"] = WxPayConfig::APPID;
|
||||
$data["url"] = "http://".$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
|
||||
$time = time();
|
||||
$data["timestamp"] = "$time";
|
||||
$data["noncestr"] = "1234568";
|
||||
$data["accesstoken"] = $getData["access_token"];
|
||||
ksort($data);
|
||||
$params = $this->ToUrlParams($data);
|
||||
$addrSign = sha1($params);
|
||||
|
||||
$afterData = array(
|
||||
"addrSign" => $addrSign,
|
||||
"signType" => "sha1",
|
||||
"scope" => "jsapi_address",
|
||||
"appId" => WxPayConfig::APPID,
|
||||
"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"] = WxPayConfig::APPID;
|
||||
$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"] = WxPayConfig::APPID;
|
||||
$urlObj["secret"] = WxPayConfig::APPSECRET;
|
||||
$urlObj["code"] = $code;
|
||||
$urlObj["grant_type"] = "authorization_code";
|
||||
$bizString = $this->ToUrlParams($urlObj);
|
||||
return "https://api.weixin.qq.com/sns/oauth2/access_token?".$bizString;
|
||||
}
|
||||
}
|
||||
52
plugins/wxpay/inc/WxPay.NativePay.php
Normal file
52
plugins/wxpay/inc/WxPay.NativePay.php
Normal file
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* 刷卡支付实现类
|
||||
* @author widyhu
|
||||
*
|
||||
*/
|
||||
class NativePay
|
||||
{
|
||||
/**
|
||||
*
|
||||
* 生成扫描支付URL,模式一
|
||||
* @param BizPayUrlInput $bizUrlInfo
|
||||
*/
|
||||
public function GetPrePayUrl($productId)
|
||||
{
|
||||
$biz = new WxPayBizPayUrl();
|
||||
$biz->SetProduct_id($productId);
|
||||
$values = WxpayApi::bizpayurl($biz);
|
||||
$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)
|
||||
{
|
||||
$result = WxPayApi::unifiedOrder($input);
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
84
plugins/wxpay/inc/WxPay.Notify.php
Normal file
84
plugins/wxpay/inc/WxPay.Notify.php
Normal file
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* 回调基础类
|
||||
* @author widyhu
|
||||
*
|
||||
*/
|
||||
class WxPayNotify extends WxPayNotifyReply
|
||||
{
|
||||
/**
|
||||
*
|
||||
* 回调入口
|
||||
* @param bool $needSign 是否需要签名输出
|
||||
*/
|
||||
final public function Handle($needSign = true)
|
||||
{
|
||||
$msg = "OK";
|
||||
//当返回false的时候,表示notify中调用NotifyCallBack回调失败获取签名校验失败,此时直接回复失败
|
||||
$result = WxpayApi::notify(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);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* 回调方法入口,子类可重写该方法
|
||||
* 注意:
|
||||
* 1、微信回调超时时间为2s,建议用户使用异步处理流程,确认成功之后立刻回复微信服务器
|
||||
* 2、微信服务器在调用失败或者接到回包为非确认包的时候,会发起重试,需确保你的回调是可以重入
|
||||
* @param array $data 回调解释出的参数
|
||||
* @param string $msg 如果回调处理失败,可以将错误信息输出到该方法
|
||||
* @return true回调出来完成不需要继续回调,false回调处理未完成需要继续回调
|
||||
*/
|
||||
public function NotifyProcess($data, &$msg)
|
||||
{
|
||||
//TODO 用户基础该类之后需要重写该方法,成功的时候返回true,失败返回false
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* notify回调方法,该方法中需要赋值需要输出的参数,不可重写
|
||||
* @param array $data
|
||||
* @return true回调出来完成不需要继续回调,false回调处理未完成需要继续回调
|
||||
*/
|
||||
final public function NotifyCallBack($data)
|
||||
{
|
||||
$msg = "OK";
|
||||
$result = $this->NotifyProcess($data, $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($return_code) == "SUCCESS")
|
||||
{
|
||||
$this->SetSign();
|
||||
}
|
||||
WxpayApi::replyNotify($this->ToXml());
|
||||
}
|
||||
}
|
||||
131
plugins/wxpay/jspay.php
Normal file
131
plugins/wxpay/jspay.php
Normal file
@@ -0,0 +1,131 @@
|
||||
<?php
|
||||
/*
|
||||
* 微信公众号支付
|
||||
* https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_3
|
||||
*/
|
||||
if(!defined('IN_PLUGIN'))exit();
|
||||
|
||||
@header('Content-Type: text/html; charset=UTF-8');
|
||||
|
||||
if($_SESSION[$trade_no.'_wxpay']){
|
||||
$jsApiParameters=$_SESSION[$trade_no.'_wxpay'];
|
||||
}else{
|
||||
require_once PAY_ROOT."inc/WxPay.Api.php";
|
||||
require_once PAY_ROOT."inc/WxPay.JsApiPay.php";
|
||||
//①、获取用户openid
|
||||
$tools = new JsApiPay();
|
||||
$openId = $tools->GetOpenid();
|
||||
if(!$openId)sysmsg('OpenId获取失败');
|
||||
$DB->query("update `pre_order` set `buyer` ='$openId' where `trade_no`='".TRADE_NO."'");
|
||||
|
||||
//②、统一下单
|
||||
$input = new WxPayUnifiedOrder();
|
||||
$input->SetBody($ordername);
|
||||
$input->SetOut_trade_no(TRADE_NO);
|
||||
$input->SetTotal_fee(strval($order['money']*100));
|
||||
$input->SetTime_start(date("YmdHis"));
|
||||
$input->SetTime_expire(date("YmdHis", time() + 600));
|
||||
$input->SetNotify_url($conf['localurl'].'pay/wxpay/notify/'.TRADE_NO.'/');
|
||||
$input->SetTrade_type("JSAPI");
|
||||
$input->SetProduct_id("01001");
|
||||
$input->SetOpenid($openId);
|
||||
$order = WxPayApi::unifiedOrder($input);
|
||||
|
||||
if($order["result_code"]=='SUCCESS'){
|
||||
$jsApiParameters = $tools->GetJsApiParameters($order);
|
||||
}else{
|
||||
sysmsg('微信支付下单失败!['.$order["return_code"].'] '.$order["return_msg"].'['.$order["err_code"].'] '.$order["err_code_des"]);
|
||||
}
|
||||
$_SESSION[$trade_no.'_wxpay'] = $jsApiParameters;
|
||||
}
|
||||
|
||||
if($_GET['d']==1){
|
||||
$redirect_url='data.backurl';
|
||||
}else{
|
||||
$redirect_url='\'/pay/wxpay/ok/'.TRADE_NO.'/\'';
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
|
||||
<link href="//cdn.staticfile.org/ionic/1.3.2/css/ionic.min.css" rel="stylesheet" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="bar bar-header bar-light" align-title="center">
|
||||
<h1 class="title">微信安全支付</h1>
|
||||
</div>
|
||||
<div class="has-header" style="padding: 5px;position: absolute;width: 100%;">
|
||||
<div class="text-center" style="color: #a09ee5;">
|
||||
<i class="icon ion-information-circled" style="font-size: 80px;"></i><br>
|
||||
<span>正在跳转...</span>
|
||||
<script src="//cdn.staticfile.org/jquery/1.12.4/jquery.min.js"></script>
|
||||
<script src="//cdn.staticfile.org/layer/2.3/layer.js"></script>
|
||||
<script>
|
||||
$(document).on('touchmove',function(e){
|
||||
e.preventDefault();
|
||||
});
|
||||
//调用微信JS api 支付
|
||||
function jsApiCall()
|
||||
{
|
||||
WeixinJSBridge.invoke(
|
||||
'getBrandWCPayRequest',
|
||||
<?php echo $jsApiParameters; ?>,
|
||||
function(res){
|
||||
if(res.err_msg == "get_brand_wcpay_request:ok" ) {
|
||||
loadmsg();
|
||||
}
|
||||
//WeixinJSBridge.log(res.err_msg);
|
||||
//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();
|
||||
}
|
||||
}
|
||||
// 检查是否支付完成
|
||||
function loadmsg() {
|
||||
$.ajax({
|
||||
type: "GET",
|
||||
dataType: "json",
|
||||
url: "/getshop.php",
|
||||
timeout: 10000, //ajax请求超时时间10s
|
||||
data: {type: "wxpay", trade_no: "<?php echo TRADE_NO?>"}, //post数据
|
||||
success: function (data, textStatus) {
|
||||
//从服务器得到数据,显示数据并继续查询
|
||||
if (data.code == 1) {
|
||||
layer.msg('支付成功,正在跳转中...', {icon: 16,shade: 0.01,time: 15000});
|
||||
window.location.href=<?php echo $redirect_url?>;
|
||||
}else{
|
||||
setTimeout("loadmsg()", 2000);
|
||||
}
|
||||
},
|
||||
//Ajax请求超时,继续查询
|
||||
error: function (XMLHttpRequest, textStatus, errorThrown) {
|
||||
if (textStatus == "timeout") {
|
||||
setTimeout("loadmsg()", 1000);
|
||||
} else { //异常
|
||||
setTimeout("loadmsg()", 4000);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
window.onload = callpay();
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
71
plugins/wxpay/notify.php
Normal file
71
plugins/wxpay/notify.php
Normal file
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
if(!defined('IN_PLUGIN'))exit();
|
||||
require_once PAY_ROOT."inc/WxPay.Api.php";
|
||||
require_once PAY_ROOT."inc/WxPay.Notify.php";
|
||||
|
||||
//初始化日志
|
||||
//$logHandler= new CLogFileHandler("../logs/".date('Y-m-d').'.log');
|
||||
//$log = Log::Init($logHandler, 15);
|
||||
|
||||
class PayNotifyCallBack extends WxPayNotify
|
||||
{
|
||||
//查询订单
|
||||
public function Queryorder($transaction_id)
|
||||
{
|
||||
$input = new WxPayOrderQuery();
|
||||
$input->SetTransaction_id($transaction_id);
|
||||
$result = WxPayApi::orderQuery($input);
|
||||
//Log::DEBUG("query:" . json_encode($result));
|
||||
if(array_key_exists("return_code", $result)
|
||||
&& array_key_exists("result_code", $result)
|
||||
&& $result["return_code"] == "SUCCESS"
|
||||
&& $result["result_code"] == "SUCCESS")
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//重写回调处理函数
|
||||
public function NotifyProcess($data, &$msg)
|
||||
{
|
||||
//file_put_contents('log.txt',"call back:" . json_encode($data));
|
||||
$notfiyOutput = array();
|
||||
|
||||
if(!array_key_exists("transaction_id", $data)){
|
||||
$msg = "输入参数不正确";
|
||||
return false;
|
||||
}
|
||||
//查询订单,判断订单真实性
|
||||
if(!$this->Queryorder($data["transaction_id"])){
|
||||
$msg = "订单查询失败";
|
||||
return false;
|
||||
}
|
||||
global $DB,$date,$order;
|
||||
if($data['return_code']=='SUCCESS'){
|
||||
if($data['result_code']=='SUCCESS'){
|
||||
if($data['out_trade_no'] == TRADE_NO && $data['total_fee']==strval($order['money']*100) && $order['status']==0){
|
||||
if($DB->exec("update `pre_order` set `status` ='1' where `trade_no`='".TRADE_NO."'")){
|
||||
$DB->exec("update `pre_order` set `api_trade_no` ='{$data['transaction_id']}',`endtime` ='$date',`buyer` ='{$data['openid']}',`date`=NOW() where `trade_no`='".TRADE_NO."'");
|
||||
processOrder($order);
|
||||
}
|
||||
return true;
|
||||
}else{
|
||||
$msg='该订单已经处理';
|
||||
return true;
|
||||
}
|
||||
}else{
|
||||
$msg='['.$data['err_code'].']'.$data['err_code_des'];
|
||||
return false;
|
||||
}
|
||||
}else{
|
||||
$msg='['.$data['return_code'].']'.$data['return_msg'];
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
//Log::DEBUG("begin notify");
|
||||
$notify = new PayNotifyCallBack();
|
||||
$notify->Handle(false);
|
||||
31
plugins/wxpay/ok.php
Normal file
31
plugins/wxpay/ok.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
/*
|
||||
* 微信公众号支付成功停留页面
|
||||
*/
|
||||
@header('Content-Type: text/html; charset=UTF-8');
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
|
||||
<link href="//cdn.staticfile.org/ionic/1.3.2/css/ionic.min.css" rel="stylesheet" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="bar bar-header bar-light" align-title="center">
|
||||
<h1 class="title">支付结果页面</h1>
|
||||
</div>
|
||||
<div class="has-header" style="padding: 5px;position: absolute;width: 100%;">
|
||||
<div class="text-center" style="color: #a09ee5;">
|
||||
<i class="icon ion-checkmark-circled" style="font-size: 80px;"></i><br>
|
||||
<span>支付成功,请关闭此页面</span>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
document.querySelector('body').addEventListener('touchmove', function (event) {
|
||||
event.preventDefault();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
140
plugins/wxpay/qrcode.php
Normal file
140
plugins/wxpay/qrcode.php
Normal file
@@ -0,0 +1,140 @@
|
||||
<?php
|
||||
/*
|
||||
* 微信电脑扫码支付
|
||||
*/
|
||||
if(!defined('IN_PLUGIN'))exit();
|
||||
|
||||
@header('Content-Type: text/html; charset=UTF-8');
|
||||
|
||||
$sitename=htmlspecialchars(base64_decode($_GET['sitename']));
|
||||
|
||||
require_once PAY_ROOT."inc/WxPay.Api.php";
|
||||
require_once PAY_ROOT."inc/WxPay.NativePay.php";
|
||||
$notify = new NativePay();
|
||||
$input = new WxPayUnifiedOrder();
|
||||
$input->SetBody($ordername);
|
||||
$input->SetOut_trade_no(TRADE_NO);
|
||||
$input->SetTotal_fee(strval($order['money']*100));
|
||||
$input->SetSpbill_create_ip($clientip);
|
||||
$input->SetTime_start(date("YmdHis"));
|
||||
$input->SetTime_expire(date("YmdHis", time() + 600));
|
||||
$input->SetNotify_url($conf['localurl'].'pay/wxpay/notify/'.TRADE_NO.'/');
|
||||
$input->SetTrade_type("NATIVE");
|
||||
$result = $notify->GetPayUrl($input);
|
||||
if($result["result_code"]=='SUCCESS'){
|
||||
$code_url=$result['code_url'];
|
||||
}elseif(isset($result["err_code"])){
|
||||
sysmsg('微信支付下单失败!['.$result["err_code"].'] '.$result["err_code_des"]);
|
||||
}else{
|
||||
sysmsg('微信支付下单失败!['.$result["return_code"].'] '.$result["return_msg"]);
|
||||
}
|
||||
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||
<meta http-equiv="Content-Language" content="zh-cn">
|
||||
<meta name="renderer" content="webkit">
|
||||
<title>微信安全支付 - <?php echo $sitename?></title>
|
||||
<link href="/assets/css/wechat_pay.css" rel="stylesheet" media="screen">
|
||||
</head>
|
||||
<body>
|
||||
<div class="body">
|
||||
<h1 class="mod-title">
|
||||
<span class="ico-wechat"></span><span class="text">微信支付</span>
|
||||
</h1>
|
||||
<div class="mod-ct">
|
||||
<div class="order">
|
||||
</div>
|
||||
<div class="amount">¥<?php echo $order['money']?></div>
|
||||
<div class="qr-image" id="qrcode">
|
||||
</div>
|
||||
|
||||
<div class="detail" id="orderDetail">
|
||||
<dl class="detail-ct" style="display: none;">
|
||||
<dt>商家</dt>
|
||||
<dd id="storeName"><?php echo $sitename?></dd>
|
||||
<dt>购买物品</dt>
|
||||
<dd id="productName"><?php echo $order['name']?></dd>
|
||||
<dt>商户订单号</dt>
|
||||
<dd id="billId"><?php echo $order['trade_no']?></dd>
|
||||
<dt>创建时间</dt>
|
||||
<dd id="createTime"><?php echo $order['addtime']?></dd>
|
||||
</dl>
|
||||
<a href="javascript:void(0)" class="arrow"><i class="ico-arrow"></i></a>
|
||||
</div>
|
||||
<div class="tip">
|
||||
<span class="dec dec-left"></span>
|
||||
<span class="dec dec-right"></span>
|
||||
<div class="ico-scan"></div>
|
||||
<div class="tip-text">
|
||||
<p>请使用微信扫一扫</p>
|
||||
<p>扫描二维码完成支付</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tip-text">
|
||||
</div>
|
||||
</div>
|
||||
<div class="foot">
|
||||
<div class="inner">
|
||||
<p>手机用户可保存上方二维码到手机中</p>
|
||||
<p>在微信扫一扫中选择“相册”即可</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="/assets/js/qcloud_util.js"></script>
|
||||
<script src="/assets/js/jquery-qrcode.min.js"></script>
|
||||
<script src="//cdn.staticfile.org/layer/2.3/layer.js"></script>
|
||||
<script>
|
||||
$('#qrcode').qrcode({
|
||||
text: "<?php echo $code_url?>",
|
||||
width: 230,
|
||||
height: 230,
|
||||
foreground: "#000000",
|
||||
background: "#ffffff",
|
||||
typeNumber: -1
|
||||
});
|
||||
// 订单详情
|
||||
$('#orderDetail .arrow').click(function (event) {
|
||||
if ($('#orderDetail').hasClass('detail-open')) {
|
||||
$('#orderDetail .detail-ct').slideUp(500, function () {
|
||||
$('#orderDetail').removeClass('detail-open');
|
||||
});
|
||||
} else {
|
||||
$('#orderDetail .detail-ct').slideDown(500, function () {
|
||||
$('#orderDetail').addClass('detail-open');
|
||||
});
|
||||
}
|
||||
});
|
||||
// 检查是否支付完成
|
||||
function loadmsg() {
|
||||
$.ajax({
|
||||
type: "GET",
|
||||
dataType: "json",
|
||||
url: "/getshop.php",
|
||||
timeout: 10000, //ajax请求超时时间10s
|
||||
data: {type: "wxpay", trade_no: "<?php echo $order['trade_no']?>"}, //post数据
|
||||
success: function (data, textStatus) {
|
||||
//从服务器得到数据,显示数据并继续查询
|
||||
if (data.code == 1) {
|
||||
layer.msg('支付成功,正在跳转中...', {icon: 16,shade: 0.01,time: 15000});
|
||||
window.location.href=data.backurl;
|
||||
}else{
|
||||
setTimeout("loadmsg()", 4000);
|
||||
}
|
||||
},
|
||||
//Ajax请求超时,继续查询
|
||||
error: function (XMLHttpRequest, textStatus, errorThrown) {
|
||||
if (textStatus == "timeout") {
|
||||
setTimeout("loadmsg()", 1000);
|
||||
} else { //异常
|
||||
setTimeout("loadmsg()", 4000);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
window.onload = loadmsg();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
28
plugins/wxpay/refund.php
Normal file
28
plugins/wxpay/refund.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
/*
|
||||
* 微信退款接口
|
||||
*/
|
||||
if(!defined('IN_REFUND'))exit();
|
||||
|
||||
require_once PAY_ROOT."inc/WxPay.Api.php";
|
||||
|
||||
try{
|
||||
$input = new WxPayRefund();
|
||||
$input->SetTransaction_id($order['api_trade_no']);
|
||||
$input->SetTotal_fee(strval($order['realmoney']*100));
|
||||
$input->SetRefund_fee(strval($order['realmoney']*100));
|
||||
$input->SetOut_refund_no($order['trade_no']);
|
||||
$input->SetOp_user_id(WxPayConfig::MCHID);
|
||||
$result = WxPayApi::refund($input);
|
||||
if($result['return_code']=='SUCCESS' && $result['result_code']=='SUCCESS'){
|
||||
$result = ['code'=>0, 'trade_no'=>$result['transaction_id'], 'refund_fee'=>$result['refund_fee']];
|
||||
}elseif(isset($result["err_code"])){
|
||||
$result = ['code'=>-1, 'msg'=>'['.$result["err_code"].']'.$result["err_code_des"]];
|
||||
}else{
|
||||
$result = ['code'=>-1, 'msg'=>'['.$result["return_code"].']'.$result["return_msg"]];
|
||||
}
|
||||
} catch(Exception $e) {
|
||||
$result = ['code'=>-1, 'msg'=>$e->getMessage()];
|
||||
}
|
||||
|
||||
return $result;
|
||||
64
plugins/wxpay/return.php
Normal file
64
plugins/wxpay/return.php
Normal file
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
/*
|
||||
* 微信H5支付返回中转页面
|
||||
*/
|
||||
if(!defined('IN_PLUGIN'))exit();
|
||||
|
||||
@header('Content-Type: text/html; charset=UTF-8');
|
||||
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
|
||||
<link href="//cdn.bootcss.com/ionic/1.3.1/css/ionic.min.css" rel="stylesheet" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="bar bar-header bar-light" align-title="center">
|
||||
<h1 class="title">订单处理结果</h1>
|
||||
</div>
|
||||
<div class="has-header" style="padding: 5px;position: absolute;width: 100%;">
|
||||
<div class="text-center" style="color: #a09ee5;">
|
||||
<i class="icon ion-information-circled" style="font-size: 80px;"></i><br>
|
||||
<span>正在检测付款结果...</span>
|
||||
<script src="//cdn.bootcss.com/jquery/1.12.4/jquery.min.js"></script>
|
||||
<script src="//cdn.bootcss.com/layer/2.3/layer.js"></script>
|
||||
<script>
|
||||
$(document).on('touchmove',function(e){
|
||||
e.preventDefault();
|
||||
});
|
||||
// 检查是否支付完成
|
||||
function loadmsg() {
|
||||
$.ajax({
|
||||
type: "GET",
|
||||
dataType: "json",
|
||||
url: "/getshop.php",
|
||||
timeout: 10000, //ajax请求超时时间10s
|
||||
data: {type: "wxpay", trade_no: "<?php echo TRADE_NO?>"}, //post数据
|
||||
success: function (data, textStatus) {
|
||||
//从服务器得到数据,显示数据并继续查询
|
||||
if (data.code == 1) {
|
||||
layer.msg('支付成功,正在跳转中...', {icon: 16,shade: 0.01,time: 15000});
|
||||
window.location.href=data.backurl;
|
||||
}else{
|
||||
setTimeout("loadmsg()", 3000);
|
||||
}
|
||||
},
|
||||
//Ajax请求超时,继续查询
|
||||
error: function (XMLHttpRequest, textStatus, errorThrown) {
|
||||
if (textStatus == "timeout") {
|
||||
setTimeout("loadmsg()", 1000);
|
||||
} else { //异常
|
||||
setTimeout("loadmsg()", 4000);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
window.onload = loadmsg();
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
25
plugins/wxpay/submit.php
Normal file
25
plugins/wxpay/submit.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
if(!defined('IN_PLUGIN'))exit();
|
||||
|
||||
if(strpos($_SERVER['HTTP_USER_AGENT'], 'MicroMessenger')!==false){
|
||||
if(!empty($conf['localurl_wxpay']) && !strpos($conf['localurl_wxpay'],$_SERVER['HTTP_HOST'])){
|
||||
echo "<script>window.location.href='{$conf['localurl_alipay']}pay/wxpay/jspay/{$trade_no}/?d=1';</script>";exit;
|
||||
}
|
||||
echo "<script>window.location.href='/pay/wxpay/jspay/{$trade_no}/?d=1';</script>";
|
||||
}elseif(checkmobile()==true){
|
||||
if(in_array('3',$channel['apptype'])){
|
||||
if(!empty($conf['localurl_wxpay']) && !strpos($conf['localurl_wxpay'],$_SERVER['HTTP_HOST'])){
|
||||
echo "<script>window.location.href='{$conf['localurl_alipay']}pay/wxpay/h5/{$trade_no}/';</script>";exit;
|
||||
}
|
||||
echo "<script>window.location.href='/pay/wxpay/h5/{$trade_no}/';</script>";
|
||||
}elseif(in_array('2',$channel['apptype'])){
|
||||
if(!empty($conf['localurl_wxpay']) && !strpos($conf['localurl_wxpay'],$_SERVER['HTTP_HOST'])){
|
||||
echo "<script>window.location.href='{$conf['localurl_alipay']}pay/wxpay/wap/{$trade_no}/';</script>";exit;
|
||||
}
|
||||
echo "<script>window.location.href='/pay/wxpay/wap/{$trade_no}/?sitename={$sitename}';</script>";
|
||||
}else{
|
||||
echo "<script>window.location.href='/pay/wxpay/qrcode/{$trade_no}/?sitename={$sitename}';</script>";
|
||||
}
|
||||
}else{
|
||||
echo "<script>window.location.href='/pay/wxpay/qrcode/{$trade_no}/?sitename={$sitename}';</script>";
|
||||
}
|
||||
111
plugins/wxpay/wap.php
Normal file
111
plugins/wxpay/wap.php
Normal file
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
/*
|
||||
* 微信手机扫码支付
|
||||
*/
|
||||
if(!defined('IN_PLUGIN'))exit();
|
||||
|
||||
@header('Content-Type: text/html; charset=UTF-8');
|
||||
|
||||
$sitename=htmlspecialchars(base64_decode($_GET['sitename']));
|
||||
|
||||
$target_url = $siteurl.'pay/wxpay/jspay/'.TRADE_NO.'/';
|
||||
?>
|
||||
<html lang="zh-cn">
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||
<title>微信支付</title>
|
||||
<link href="//cdn.staticfile.org/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="col-xs-12 col-sm-10 col-md-8 col-lg-6 center-block" style="float: none;">
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-heading" style="text-align: center;"><h3 class="panel-title">
|
||||
<img src="/assets/icon/wechat.ico">微信支付手机版
|
||||
</div>
|
||||
<div class="list-group" style="text-align: center;">
|
||||
<div class="list-group-item list-group-item-info">长按保存到相册使用扫码扫码完成支付</div>
|
||||
<div class="list-group-item">
|
||||
<div class="qr-image" id="qrcode"></div>
|
||||
</div>
|
||||
<div class="list-group-item list-group-item-info">或复制以下链接到微信打开:</div>
|
||||
<div class="list-group-item">
|
||||
<a href="<?php echo $target_url?>"><?php echo $target_url?></a><br/><button id="copy-btn" data-clipboard-text="<?php echo $target_url?>" class="btn btn-info btn-sm">一键复制</button>
|
||||
</div>
|
||||
<div class="list-group-item"><small>提示:你可以将以上链接发到自己微信的聊天框(在微信顶部搜索框可以搜到自己的微信),即可点击进入支付</small></div>
|
||||
<div class="list-group-item"><a href="weixin://" class="btn btn-primary">打开微信</a> <a href="#" onclick="checkresult()" class="btn btn-success">检测支付状态</a></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="//cdn.staticfile.org/jquery/1.12.4/jquery.min.js"></script>
|
||||
<script src="/assets/js/jquery-qrcode.min.js"></script>
|
||||
<script src="//cdn.staticfile.org/layer/2.3/layer.js"></script>
|
||||
<script src="//cdn.staticfile.org/clipboard.js/1.7.1/clipboard.min.js"></script>
|
||||
<script>
|
||||
var clipboard = new Clipboard('#copy-btn');
|
||||
clipboard.on('success', function(e) {
|
||||
layer.msg('复制成功,请到微信里面粘贴');
|
||||
});
|
||||
clipboard.on('error', function(e) {
|
||||
layer.msg('复制失败,请长按链接后手动复制');
|
||||
});
|
||||
$('#qrcode').qrcode({
|
||||
text: "<?php echo $target_url?>",
|
||||
width: 230,
|
||||
height: 230,
|
||||
foreground: "#000000",
|
||||
background: "#ffffff",
|
||||
typeNumber: -1
|
||||
});
|
||||
// 检查是否支付完成
|
||||
function loadmsg() {
|
||||
$.ajax({
|
||||
type: "GET",
|
||||
dataType: "json",
|
||||
url: "/getshop.php",
|
||||
timeout: 10000, //ajax请求超时时间10s
|
||||
data: {type: "wxpay", trade_no: "<?php echo $order['trade_no']?>"}, //post数据
|
||||
success: function (data, textStatus) {
|
||||
//从服务器得到数据,显示数据并继续查询
|
||||
if (data.code == 1) {
|
||||
layer.msg('支付成功,正在跳转中...', {icon: 16,shade: 0.01,time: 15000});
|
||||
setTimeout(window.location.href=data.backurl, 1000);
|
||||
}else{
|
||||
setTimeout("loadmsg()", 4000);
|
||||
}
|
||||
},
|
||||
//Ajax请求超时,继续查询
|
||||
error: function (XMLHttpRequest, textStatus, errorThrown) {
|
||||
if (textStatus == "timeout") {
|
||||
setTimeout("loadmsg()", 1000);
|
||||
} else { //异常
|
||||
setTimeout("loadmsg()", 4000);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
function checkresult() {
|
||||
$.ajax({
|
||||
type: "GET",
|
||||
dataType: "json",
|
||||
url: "/getshop.php",
|
||||
timeout: 10000, //ajax请求超时时间10s
|
||||
data: {type: "wxpay", trade_no: "<?php echo $order['trade_no']?>"}, //post数据
|
||||
success: function (data, textStatus) {
|
||||
//从服务器得到数据,显示数据并继续查询
|
||||
if (data.code == 1) {
|
||||
layer.msg('支付成功,正在跳转中...', {icon: 16,shade: 0.01,time: 15000});
|
||||
setTimeout(window.location.href=data.backurl, 1000);
|
||||
}
|
||||
},
|
||||
//Ajax请求超时,继续查询
|
||||
error: function (XMLHttpRequest, textStatus, errorThrown) {
|
||||
layer.msg('服务器错误');
|
||||
}
|
||||
});
|
||||
}
|
||||
window.onload = loadmsg();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user