2020.02新版

This commit is contained in:
Blokura
2020-02-21 16:20:55 +08:00
parent 45e2415d71
commit a2f29a310b
755 changed files with 95144 additions and 0 deletions

View 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-----

View 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
View 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
View 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"]);
}
?>

View 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("统一支付接口中缺少必填参数openidtrade_type为JSAPI时openid为必填参数");
}
if($inputObj->GetTrade_type() == "JSAPI" && !$inputObj->IsProduct_idSet()){
throw new WxPayException("统一支付接口中缺少必填参数product_idtrade_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;
}
}

View 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;
}

File diff suppressed because it is too large Load Diff

View File

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

View 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;
}
}

View 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;
}
}

View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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>&nbsp;<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>