Initial project files: BESCMS full source

This commit is contained in:
bes
2026-08-13 23:37:46 +08:00
parent fa6cddb540
commit 2e26f85723
2166 changed files with 396625 additions and 0 deletions
+591
View File
@@ -0,0 +1,591 @@
<?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()) {
return dr_return_data(0, "缺少统一支付接口必填参数out_trade_no");
}else if(!$inputObj->IsBodySet()){
return dr_return_data(0, "缺少统一支付接口必填参数body");
}else if(!$inputObj->IsTotal_feeSet()) {
return dr_return_data(0, "缺少统一支付接口必填参数total_fee!");
}else if(!$inputObj->IsTrade_typeSet()) {
return dr_return_data(0, "缺少统一支付接口必填参数trade_type!");
}
//关联参数
if($inputObj->GetTrade_type() == "JSAPI" && !$inputObj->IsOpenidSet()){
return dr_return_data(0, "统一支付接口中,缺少必填参数openidtrade_type为JSAPI时,openid为必填参数!");
}
if($inputObj->GetTrade_type() == "NATIVE" && !$inputObj->IsProduct_idSet()){
return dr_return_data(0, "统一支付接口中,缺少必填参数product_idtrade_type为JSAPI时,product_id为必填参数!");
}
//异步通知url未设置,则使用配置文件中的url
if(!$inputObj->IsNotify_urlSet()){
$inputObj->SetNotify_url(NOTIFY_URL);//异步通知url
}
$inputObj->SetAppid(APPID);//公众账号ID
$inputObj->SetMch_id(MCHID);//商户号
$inputObj->SetSpbill_create_ip($_SERVER['REMOTE_ADDR']);//终端ip
//$inputObj->SetSpbill_create_ip("1.1.1.1");
$inputObj->SetNonce_str(self::getNonceStr());//随机字符串
//签名
$inputObj->SetSign();
$xml = $inputObj->ToXml();
$startTimeStamp = self::getMillisecond();//请求开始时间
$response = self::postXmlCurl($xml, $url, false, $timeOut);
if (isset($response['code']) && $response['code']==0) {
return $response;
}
$result = WxPayResults::Init($response);
if (isset($result['code']) && $result['code']==0) {
return $result;
} elseif (isset($result['return_code']) && $result['return_code']=='FAIL') {
return dr_return_data(0, $result['return_msg']);
}
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()) {
return dr_return_data(0, "订单查询接口中,out_trade_no、transaction_id至少填一个!");
}
$inputObj->SetAppid(APPID);//公众账号ID
$inputObj->SetMch_id(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()) {
return dr_return_data(0, "订单查询接口中,out_trade_no必填!");
}
$inputObj->SetAppid(APPID);//公众账号ID
$inputObj->SetMch_id(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()) {
return dr_return_data(0, "退款申请接口中,out_trade_no、transaction_id至少填一个!");
}else if(!$inputObj->IsOut_refund_noSet()){
return dr_return_data(0, "退款申请接口中,缺少必填参数out_refund_no");
}else if(!$inputObj->IsTotal_feeSet()){
return dr_return_data(0, "退款申请接口中,缺少必填参数total_fee!");
}else if(!$inputObj->IsRefund_feeSet()){
return dr_return_data(0, "退款申请接口中,缺少必填参数refund_fee!");
}else if(!$inputObj->IsOp_user_idSet()){
return dr_return_data(0, "退款申请接口中,缺少必填参数op_user_id!");
}
$inputObj->SetAppid(APPID);//公众账号ID
$inputObj->SetMch_id(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()) {
return dr_return_data(0, "退款查询接口中,out_refund_no、out_trade_no、transaction_id、refund_id四个参数必填一个!");
}
$inputObj->SetAppid(APPID);//公众账号ID
$inputObj->SetMch_id(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()) {
return dr_return_data(0, "对账单接口中,缺少必填参数bill_date!");
}
$inputObj->SetAppid(APPID);//公众账号ID
$inputObj->SetMch_id(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()) {
return dr_return_data(0, "提交被扫支付API接口中,缺少必填参数body!");
} else if(!$inputObj->IsOut_trade_noSet()) {
return dr_return_data(0, "提交被扫支付API接口中,缺少必填参数out_trade_no");
} else if(!$inputObj->IsTotal_feeSet()) {
return dr_return_data(0, "提交被扫支付API接口中,缺少必填参数total_fee!");
} else if(!$inputObj->IsAuth_codeSet()) {
return dr_return_data(0, "提交被扫支付API接口中,缺少必填参数auth_code!");
}
$inputObj->SetSpbill_create_ip($_SERVER['REMOTE_ADDR']);//终端ip
$inputObj->SetAppid(APPID);//公众账号ID
$inputObj->SetMch_id(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()) {
return dr_return_data(0, "撤销订单API接口中,参数out_trade_no和transaction_id必须填写一个!");
}
$inputObj->SetAppid(APPID);//公众账号ID
$inputObj->SetMch_id(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;
}
/**
*
* 测速上报,该方法内部封装在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()) {
return dr_return_data(0, "接口URL,缺少必填参数interface_url");
} if(!$inputObj->IsReturn_codeSet()) {
return dr_return_data(0, "返回状态码,缺少必填参数return_code");
} if(!$inputObj->IsResult_codeSet()) {
return dr_return_data(0, "业务结果,缺少必填参数result_code");
} if(!$inputObj->IsUser_ipSet()) {
return dr_return_data(0, "访问接口IP,缺少必填参数user_ip!");
} if(!$inputObj->IsExecute_time_Set()) {
return dr_return_data(0, "接口耗时,缺少必填参数execute_time_");
}
$inputObj->SetAppid(APPID);//公众账号ID
$inputObj->SetMch_id(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()){
return dr_return_data(0, "生成二维码,缺少必填参数product_id!");
}
$inputObj->SetAppid(APPID);//公众账号ID
$inputObj->SetMch_id(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()) {
return dr_return_data(0, "需要转换的URL,签名用原串,传输需URL encode!");
}
$inputObj->SetAppid(APPID);//公众账号ID
$inputObj->SetMch_id(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(REPORT_LEVENL == 0){
return;
}
//如果仅失败上报
if(REPORT_LEVENL == 1 &&
wx_array_key_exists("return_code", $data) &&
$data["return_code"] == "SUCCESS" &&
wx_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(wx_array_key_exists("return_code", $data)){
$objInput->SetReturn_code($data["return_code"]);
}
//返回信息
if(wx_array_key_exists("return_msg", $data)){
$objInput->SetReturn_msg($data["return_msg"]);
}
//业务结果
if(wx_array_key_exists("result_code", $data)){
$objInput->SetResult_code($data["result_code"]);
}
//错误代码
if(wx_array_key_exists("err_code", $data)){
$objInput->SetErr_code($data["err_code"]);
}
//错误代码描述
if(wx_array_key_exists("err_code_des", $data)){
$objInput->SetErr_code_des($data["err_code_des"]);
}
//商户订单号
if(wx_array_key_exists("out_trade_no", $data)){
$objInput->SetOut_trade_no($data["out_trade_no"]);
}
//设备号
if(wx_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(CURL_PROXY_HOST != "0.0.0.0"
&& CURL_PROXY_PORT != 0){
curl_setopt($ch,CURLOPT_PROXY, CURL_PROXY_HOST);
curl_setopt($ch,CURLOPT_PROXYPORT, 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, SSLCERT_PATH);
curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM');
curl_setopt($ch,CURLOPT_SSLKEY, 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);
return dr_return_data(0, "curl出错,错误码:$error");
}
}
/**
* 获取毫秒级别的时间戳
*/
private static function getMillisecond()
{
//获取毫秒的时间戳
$time = explode ( " ", microtime () );
$time = $time[1] . ($time[0] * 1000);
$time2 = explode( ".", $time );
$time = $time2[0];
return $time;
}
}
File diff suppressed because it is too large Load Diff
+213
View File
@@ -0,0 +1,213 @@
<?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((defined('SYS_HTTPS') && SYS_HTTPS ? 'https://' : 'http://').$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'].$_SERVER['QUERY_STRING']);
$url = $this->__CreateOauthUrlForCode($baseUrl);
Header("Location: $url");
exit();
} else {
//获取code码,以获取openid
$code = $_GET['code'];
$openid = $this->getOpenidFromMp($code);
return $openid;
}
}
/**
*
* 获取jsapi支付的参数
* @param array $UnifiedOrderResult 统一支付接口返回的数据
* @throws WxPayException
*
* @return json数据,可直接填入js函数作为参数
*/
public function GetJsApiParameters($UnifiedOrderResult)
{
if(!wx_array_key_exists("appid", $UnifiedOrderResult)
|| !wx_array_key_exists("prepay_id", $UnifiedOrderResult)
|| $UnifiedOrderResult['prepay_id'] == "")
{
return dr_return_data(0, "参数错误");
}
$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(CURL_PROXY_HOST != "0.0.0.0"
&& CURL_PROXY_PORT != 0){
curl_setopt($ch,CURLOPT_PROXY, CURL_PROXY_HOST);
curl_setopt($ch,CURLOPT_PROXYPORT, CURL_PROXY_PORT);
}*/
//运行curl,结果以jason形式返回
$res = curl_exec($ch);
curl_close($ch);
//取出openid
$data = json_decode($res,true);
$this->data = $data;
if (!$data) {
exit($res.' 不是一个有效的json数据');
} elseif (isset($data['errcode']) && $data['errcode']) {
exit('错误代码('.$data['errcode'].'):'.$data['errmsg']);
}
$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"] = 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" => 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"] = 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"] = APPID;
$urlObj["secret"] = APPSECRET;
$urlObj["code"] = $code;
$urlObj["grant_type"] = "authorization_code";
$bizString = $this->ToUrlParams($urlObj);
return "https://api.weixin.qq.com/sns/oauth2/access_token?".$bizString;
}
}
+56
View File
@@ -0,0 +1,56 @@
<?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)
{
if($input->GetTrade_type() == "NATIVE")
{
$result = WxPayApi::unifiedOrder($input);
return $result;
}
}
}
+85
View File
@@ -0,0 +1,85 @@
<?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
return true;
}
/**
*
* 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 public function ReplyNotify($needSign = true)
{
//如果需要签名
if($needSign == true &&
$this->GetReturn_code($return_code) == "SUCCESS")
{
$this->SetSign();
}
WxpayApi::replyNotify($this->ToXml());
}
}
+12
View File
@@ -0,0 +1,12 @@
<?php
/**
* 支付接口配置
*/
return [
'name' => '微信',
'icon' => '<i class="fa fa-weixin"></i>',
];
+62
View File
@@ -0,0 +1,62 @@
<?php
/**
* 微信支付回调接口
*/
define('APPID', $config['appid']);
define('MCHID', $config['mchid']);
define('KEY', $config['key']);
define('APPSECRET', $config['appsecret']);
define('REPORT_LEVENL', 0);
require "WxPay.Data.php";
require "WxPay.Api.php";
require "WxPay.Notify.php";
class PayNotifyCallBack extends WxPayNotify
{
//查询订单
public function Queryorder($transaction_id)
{
$input = new WxPayOrderQuery();
$input->SetTransaction_id($transaction_id);
$result = WxPayApi::orderQuery($input);
if(wx_array_key_exists("return_code", $result)
&& wx_array_key_exists("result_code", $result)
&& $result["return_code"] == "SUCCESS"
&& $result["result_code"] == "SUCCESS")
{
return true;
}
return false;
}
//重写回调处理函数
public function NotifyProcess($data, &$msg)
{
$notfiyOutput = array();
if(!wx_array_key_exists("transaction_id", $data)){
$msg = "输入参数不正确";
return false;
}
//查询订单,判断订单真实性
if(!$this->Queryorder($data["transaction_id"])){
$msg = "订单查询失败";
return false;
}
// 处理支付表状态
$rt = \Phpcmf\Service::M('Pay', 'pay')->paysuccess($data['out_trade_no'], $data["transaction_id"]);
//file_put_contents(WEBPATH."wx.txt", var_export($data, true));
return true;
}
}
$notify = new PayNotifyCallBack();
$notify->Handle(false);
+33
View File
@@ -0,0 +1,33 @@
<?php
/**
* 微信支付ajax实时监测状态接口
* $result // 支付记录表的回调详情
*/
define('APPID', $config['appid']);
define('MCHID', $config['mchid']);
define('KEY', $config['key']);
define('APPSECRET', $config['appsecret']);
define('REPORT_LEVENL', 0);
require "WxPay.Data.php";
require "WxPay.Api.php";
require "WxPay.Notify.php";
$sn = \Phpcmf\Service::C()->member_cache['pay']['prefix'].date('YmdHis', $data['inputtime']).'-'.$data['id'];
$input = new WxPayOrderQuery();
$input->SetOut_trade_no($sn);
$rt = WxPayApi::orderQuery($input);
// 判断支付成功
if ($rt['result_code'] == 'SUCCESS' && $rt['return_code'] == 'SUCCESS' && $rt['trade_state'] == 'SUCCESS') {
$rt = \Phpcmf\Service::M('Pay', 'pay')->paysuccess($rt['out_trade_no'], $rt["transaction_id"]);
$return = ['code' => 1, 'msg' => 'ok'];
} elseif ($rt['return_code'] == 'FAIL') {
$return = ['code' => 0, 'msg' => $rt['return_msg']];
} elseif (isset($rt['code']) && $rt['code'] == 0) {
$return = ['code' => 0, 'msg' => $rt['msg']];
} else {
$return = ['code' => 0, 'msg' => dr_lang('未付款')];
}
+9
View File
@@ -0,0 +1,9 @@
<?php
/**
* 支付回调接口URL
*/
define('IS_API', 'pay'); // 项目标识
define('SELF', pathinfo(__FILE__, PATHINFO_BASENAME)); // 该文件的名称
require('../../../index.php'); // 引入主文件
+240
View File
@@ -0,0 +1,240 @@
<?php
/**
* 微信支付发起接口
*/
if (IS_API_HTTP) {
define('APPID', \Phpcmf\Service::C()->get_cache('weixin', 'xcx', 'appid'));
define('APPSECRET', \Phpcmf\Service::C()->get_cache('weixin', 'xcx', 'appsecret'));
} else {
define('APPID', $config['appid']);
define('APPSECRET', $config['appsecret']);
}
define('MCHID', $config['mchid']);
define('KEY', $config['key']);
define('NOTIFY_URL', ROOT_URL."api/pay/".$data['type']."/notify_url.php");
define('NOTIFY_API_URL', ROOT_URL."index.php?s=pay&m=ajax&id=".$id);
define('REPORT_LEVENL', 0);
require "WxPay.Data.php";
require "WxPay.Api.php";
require "WxPay.JsApiPay.php";
require "WxPay.NativePay.php";
// 当前已经登录的用户
$member = \Phpcmf\Service::C()->member;
// 付款界面模板
$htmlfile = is_file(WEBPATH.'config/pay/payweixin.html') ? WEBPATH.'config/pay/payweixin.html' : CONFIGPATH.'pay/payweixin.html';
$data['title'] = dr_strcut($data['title'], 30);
if (IS_API_HTTP && dr_is_app('weixin')) {
// 微信插件:客户端小程序请求
//①、获取用户openid
$oauth = $this->table('member_oauth')->where('uid', $data['uid'])->where('oauth', 'wxxcx')->getRow();
if (!$oauth) {
$return = dr_return_data(0, '服务器没有此用户');
} else {
$input = new WxPayUnifiedOrder();
$input->SetBody($data['title']);
$input->SetOut_trade_no($sn);
$input->SetTotal_fee($data['value'] * 100); // 金额
$input->SetTime_start(date("YmdHis", SYS_TIME));
$input->SetTime_expire(date("YmdHis", SYS_TIME + 7200));
$input->SetNotify_url(NOTIFY_URL);
$input->SetTrade_type("JSAPI"); // JSAPINATIVEAPP
$input->SetProduct_id($pid);
$input->SetOpenid($oauth['oid']);
$order = WxPayApi::unifiedOrder($input);
if (isset($order['code']) && $order['code'] == 0) {
$return = dr_return_data(0, '微信服务端:'.$order['msg']);
} elseif ($order["err_code_des"]) {
$return = dr_return_data(0, '微信服务端:'.$order['err_code_des']);
} else {
// 存储支付结果
$order['sn'] = $sn;
$tools = new JsApiPay();
$param = $tools->GetJsApiParameters($order);
\Phpcmf\Service::C()->_json(1, 'ok', json_decode($param, true));
}
}
} elseif (dr_is_weixin_app()) {
// 手机微信客户端调用jsapi
//①、获取用户openid
$tools = new JsApiPay();
$openId = $tools->GetOpenid();
if (!$openId) {
$return = dr_return_data(0, 'openId获取失败');
} else {
// 统一下单
$input = new WxPayUnifiedOrder();
$input->SetBody($data['title']);
$input->SetOut_trade_no($sn);
$input->SetTotal_fee($data['value'] * 100); // 金额
$input->SetTime_start(date("YmdHis", SYS_TIME));
$input->SetTime_expire(date("YmdHis", SYS_TIME + 7200));
$input->SetNotify_url(NOTIFY_URL);
$input->SetTrade_type("JSAPI"); // JSAPINATIVEAPP
$input->SetProduct_id($pid);
$input->SetOpenid($openId);
$order = WxPayApi::unifiedOrder($input);
if (isset($order['code']) && $order['code'] == 0) {
$return = dr_return_data(0, '微信服务端:'.$order['msg']);
} elseif ($order["err_code_des"]) {
$return = dr_return_data(0, '微信服务端:'.$order['err_code_des']);
} else {
$jsApiParameters = $tools->GetJsApiParameters($order);
//获取共享收货地址js函数参数
$editAddress = $tools->GetEditAddressParameters();
// 存储支付结果
$order['sn'] = $sn;
$code = '
<script type="text/javascript">
//调用微信JS api 支付
function jsApiCall()
{
WeixinJSBridge.invoke(
\'getBrandWCPayRequest\',
' . $jsApiParameters . ',
function(res){
if (res.err_msg == "get_brand_wcpay_request:ok") {
// 付款成功
window.location.href = "'.PAY_URL.'index.php?s=pay&m=call&id='.$id.'";
} else if (res.err_msg == "get_brand_wcpay_request:cancel") {
dr_tips(0, "'.dr_lang('付款取消').'");
} else {
dr_tips(0, "'.dr_lang('服务端错误: ').'"+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();
}
}
</script>
<button class="fc-weixin-pay" type="button" onclick="callpay()" >立即支付</button>
';
// 获取付款界面代码
ob_start();
$file = \Phpcmf\Service::V()->code2php(file_get_contents($htmlfile));
require_once $file;
$html = ob_get_clean();
$return = dr_return_data(1, 'ok', $html);
}
}
} elseif (\Phpcmf\Service::IS_MOBILE_USER()) {
// 手机端H5支付
$input = new WxPayUnifiedOrder();
$input->SetBody($data['title']);
$input->SetOut_trade_no($sn);
$input->SetTotal_fee($data['value'] * 100); // 金额
$input->SetTime_start(date("YmdHis", SYS_TIME));
$input->SetTime_expire(date("YmdHis", SYS_TIME + 7200));
$input->SetNotify_url(NOTIFY_URL);
$input->SetTrade_type("MWEB"); // JSAPINATIVEAPP
$input->SetProduct_id($pid);
$input->SetOpenid($openId);
$order = WxPayApi::unifiedOrder($input);
if (isset($order['code']) && $order['code'] == 0) {
$return = dr_return_data(0, '微信服务端:'.$order['msg']);
} elseif ($order["err_code_des"]) {
$return = dr_return_data(0, '微信服务端:'.$order['err_code_des']);
} else {
// 存储支付结果
$order['sn'] = $sn;
$code = '
<a class="fc-weixin-pay" style="padding-top:10px;" href="'.$order['mweb_url'].'" >立即支付</a>
<script>
function dr_weixin_notify() {
$.ajax({
type : "post",
url : "'.NOTIFY_API_URL.'",
dataType : "jsonp",
jsonp: "callback",
jsonpCallback:"success_jsonpCallback",
success : function(html){
if (html.code == 1) {
window.location.href = "'.ROOT_URL.'index.php?s=pay&m=call&id='.$id.'";
}
},
error:function(){ }
});
}
$(function(){
setInterval(\'dr_weixin_notify()\', 1000);
});
</script>';
// 获取付款界面代码
ob_start();
$file = \Phpcmf\Service::V()->code2php(file_get_contents($htmlfile));
require_once $file;
$html = ob_get_clean();
$return = dr_return_data(1, 'ok', $html);
}
} else {
// 电脑扫码支付
$notify = new NativePay();
// 统一下单
$input = new WxPayUnifiedOrder();
$input->SetBody($data['title']);
$input->SetOut_trade_no($sn);
$input->SetTotal_fee($data['value'] * 100); // 金额
$input->SetTime_start(date("YmdHis", SYS_TIME));
$input->SetTime_expire(date("YmdHis", SYS_TIME + 7200));
$input->SetNotify_url(NOTIFY_URL);
$input->SetTrade_type("NATIVE"); // JSAPINATIVEAPP
$input->SetProduct_id($pid);
$result = $notify->GetPayUrl($input);
if (isset($result['code']) && $result['code'] == 0) {
$return = dr_return_data(0, '微信服务端:'.$result['msg']);
} elseif ($result["err_code_des"]) {
$return = dr_return_data(0, '微信服务端:'.$result['err_code_des']);
} else {
// 存储支付结果
$result['sn'] = $sn;
$code = '
<img class="wxpay" src="'.dr_qrcode($result["code_url"]).'"/>
<script>
function dr_weixin_notify() {
$.ajax({
type : "post",
url : "'.NOTIFY_API_URL.'",
dataType : "jsonp",
jsonp: "callback",
jsonpCallback:"success_jsonpCallback",
success : function(html){
if (html.code == 1) {
window.location.href = "'.PAY_URL.'index.php?s=pay&m=call&id='.$id.'";
}
},
error:function(){ }
});
}
$(function(){
setInterval(\'dr_weixin_notify()\', 1000);
});
</script>';
// 获取付款界面代码
ob_start();
$file = \Phpcmf\Service::V()->code2php(file_get_contents($htmlfile));
require_once $file;
$html = ob_get_clean();
$return = dr_return_data(1, 'ok', $html);
}
}
+94
View File
@@ -0,0 +1,94 @@
<?php
/**
* 微信退款接口
* 由 Pay::payrefund() require 调用
*
* 可用变量:$data 流水记录,$config 接口配置,$money 退款金额
* 须设置:$return = dr_return_data(...)
*
* 注意:退款需商户号配置 API 证书(apiclient_cert.pem / apiclient_key.pem
*/
$money = abs(isset($money) ? $money : $data['value']);
$transaction_id = trim((string)$data['result']); // 支付成功时写入的微信交易号
$out_trade_no = trim((string)\Phpcmf\Service::C()->member_cache['pay']['prefix'])
. date('YmdHis', (int)$data['inputtime']) . '00' . $data['id'];
$out_refund_no = 'RF' . $data['id'] . date('YmdHis');
$total_fee = (int)round($money * 100);
$refund_fee = $total_fee;
if (!$config || empty($config['appid']) || empty($config['mchid']) || empty($config['key'])) {
$return = dr_return_data(0, dr_lang('微信退款配置不完整'));
} elseif (!$transaction_id && !$out_trade_no) {
$return = dr_return_data(0, dr_lang('缺少微信交易号,无法退款'));
} else {
// API 证书路径(退款必填),默认放在 weixin 目录下
$cert = dirname(__FILE__) . '/cert/apiclient_cert.pem';
$key = dirname(__FILE__) . '/cert/apiclient_key.pem';
if (!empty($config['sslcert_path'])) {
$cert = $config['sslcert_path'];
}
if (!empty($config['sslkey_path'])) {
$key = $config['sslkey_path'];
}
if (!is_file($cert) || !is_file($key)) {
$return = dr_return_data(0, dr_lang('微信退款证书未配置(请放置 apiclient_cert.pem / apiclient_key.pem'));
} else {
if (!defined('APPID')) {
define('APPID', $config['appid']);
}
if (!defined('APPSECRET')) {
define('APPSECRET', isset($config['appsecret']) ? $config['appsecret'] : '');
}
if (!defined('MCHID')) {
define('MCHID', $config['mchid']);
}
if (!defined('KEY')) {
define('KEY', $config['key']);
}
if (!defined('NOTIFY_URL')) {
define('NOTIFY_URL', ROOT_URL . 'api/pay/' . $data['type'] . '/notify_url.php');
}
if (!defined('REPORT_LEVENL')) {
define('REPORT_LEVENL', 0);
}
if (!defined('SSLCERT_PATH')) {
define('SSLCERT_PATH', $cert);
}
if (!defined('SSLKEY_PATH')) {
define('SSLKEY_PATH', $key);
}
require_once dirname(__FILE__) . '/WxPay.Data.php';
require_once dirname(__FILE__) . '/WxPay.Api.php';
$input = new WxPayRefund();
if ($transaction_id) {
$input->SetTransaction_id($transaction_id);
} else {
$input->SetOut_trade_no($out_trade_no);
}
$input->SetTotal_fee($total_fee);
$input->SetRefund_fee($refund_fee);
$input->SetOut_refund_no($out_refund_no);
$input->SetOp_user_id(MCHID);
$result = WxPayApi::refund($input);
if (isset($result['code']) && (int)$result['code'] === 0) {
$return = $result;
} elseif (isset($result['return_code']) && $result['return_code'] == 'SUCCESS'
&& isset($result['result_code']) && $result['result_code'] == 'SUCCESS') {
$return = dr_return_data(1, dr_lang('退款成功'), $result);
} else {
$msg = isset($result['err_code_des']) && $result['err_code_des']
? $result['err_code_des']
: (isset($result['return_msg']) ? $result['return_msg'] : dr_lang('微信退款失败'));
if (isset($result['msg']) && $result['msg']) {
$msg = $result['msg'];
}
$return = dr_return_data(0, $msg, is_array($result) ? $result : []);
}
}
}
+65
View File
@@ -0,0 +1,65 @@
<?php if (!defined('BASEPATH')) exit('No direct script access allowed');
$weixin_cert_dir = ROOTPATH.'api/pay/weixin/cert/';
$weixin_cert_default = $weixin_cert_dir.'apiclient_cert.pem';
$weixin_key_default = $weixin_cert_dir.'apiclient_key.pem';
?>
<div class="form-group">
<label class="col-md-2 control-label">AppId</label>
<div class="col-md-9">
<input type="text" class="form-control input-large" name="data[<?php echo $dir;?>][appid]" value="<?php echo $data[$dir]['appid']?>" >
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">AppSecret</label>
<div class="col-md-9">
<input type="text" class="form-control input-large" name="data[<?php echo $dir;?>][appsecret]" value="<?php echo $data[$dir]['appsecret']?>" >
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">MCHID</label>
<div class="col-md-9">
<input type="text" class="form-control input-large" name="data[<?php echo $dir;?>][mchid]" value="<?php echo $data[$dir]['mchid']?>" >
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">KEY</label>
<div class="col-md-9">
<input type="text" class="form-control input-large" name="data[<?php echo $dir;?>][key]" value="<?php echo $data[$dir]['key']?>" >
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label"><?php echo dr_lang('退款API证书'); ?></label>
<div class="col-md-9">
<div class="alert alert-warning" style="margin-bottom:10px;">
<p><?php echo dr_lang('微信退款必须配置商户 API 证书,否则无法退款。'); ?></p>
<p><?php echo dr_lang('请在微信商户平台下载证书,将以下文件放到默认目录:'); ?></p>
<p><code><?php echo $weixin_cert_default; ?></code></p>
<p><code><?php echo $weixin_key_default; ?></code></p>
<p class="margin-top-10"><?php echo dr_lang('也可在下方填写自定义绝对路径(留空则使用默认路径)。'); ?></p>
</div>
<p>
<input type="text" class="form-control" name="data[<?php echo $dir;?>][sslcert_path]" id="dr_weixin_sslcert_path" value="<?php echo isset($data[$dir]['sslcert_path']) ? htmlspecialchars($data[$dir]['sslcert_path']) : '';?>" placeholder="<?php echo htmlspecialchars($weixin_cert_default); ?>">
<span class="help-block"><?php echo dr_lang('证书文件 apiclient_cert.pem 路径'); ?></span>
</p>
<p>
<input type="text" class="form-control" name="data[<?php echo $dir;?>][sslkey_path]" id="dr_weixin_sslkey_path" value="<?php echo isset($data[$dir]['sslkey_path']) ? htmlspecialchars($data[$dir]['sslkey_path']) : '';?>" placeholder="<?php echo htmlspecialchars($weixin_key_default); ?>">
<span class="help-block"><?php echo dr_lang('密钥文件 apiclient_key.pem 路径'); ?></span>
</p>
<p>
<button type="button" class="btn blue btn-sm" onclick="dr_weixin_check_cert()">
<i class="fa fa-check-circle"></i> <?php echo dr_lang('检测证书'); ?>
</button>
<span class="help-block"><?php echo dr_lang('检测证书文件是否存在、可读,以及 PEM 格式是否可用'); ?></span>
</p>
</div>
</div>
<script type="text/javascript">
function dr_weixin_check_cert() {
var cert = $('#dr_weixin_sslcert_path').val() || '';
var key = $('#dr_weixin_sslkey_path').val() || '';
var url = '<?php echo dr_url('pay/payapi/check_cert'); ?>';
url += '&sslcert_path=' + encodeURIComponent(cert);
url += '&sslkey_path=' + encodeURIComponent(key);
dr_ajax_url(url);
}
</script>