| Server IP : 156.238.232.47 / Your IP : 216.73.216.150 Web Server : nginx/1.25.3 System : Linux C202504152095410 3.10.0-1160.119.1.el7.x86_64 #1 SMP Tue Jun 4 14:43:51 UTC 2024 x86_64 User : www ( 1000) PHP Version : 8.3.25 Disable Function : passthru,exec,system,putenv,chroot,chgrp,chown,shell_exec,popen,proc_open,pcntl_exec,ini_alter,ini_restore,dl,openlog,syslog,readlink,symlink,popepassthru,pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,imap_open,apache_setenv MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : ON | Pkexec : ON Directory : /www/data/wwwroot/2025_04_20_01-副本/application/admin/model/ |
Upload File : |
<?php
/**
* 易优CMS
* ============================================================================
* 版权所有 2016-2028 海南赞赞网络科技有限公司,并保留所有权利。
* 网站地址: http://www.eyoucms.com
* ----------------------------------------------------------------------------
* 如果商业用途务必到官方购买正版授权, 以免引起不必要的法律纠纷.
* ============================================================================
* Author: 陈风任 <491085389@qq.com>
* Date: 2020-05-22
*/
namespace app\admin\model;
use think\Model;
use think\Config;
use think\Db;
/**
* 支付接口模型
*/
load_trait('controller/Jump');
class PayApi extends Model
{
use \traits\controller\Jump;
private $key = ''; // key密钥
//初始化
protected function initialize()
{
// 需要调用`Model`的`initialize`方法
parent::initialize();
}
/*
* 验证微信支付配置信息是否正确
*/
public function VerifyWeChatConfig($wechat = [])
{
if (empty($wechat)) return false;
$this->key = $wechat['key'];
// 支付备注
$body = "验证支付";
if (1 == config('global.opencodetype')) {
$web_name = tpCache('web.web_name');
$web_name = !empty($web_name) ? "[{$web_name}]" : "";
$body = $web_name.$body;
}
// 支付数据
$out_trade_no = getTime();
$data['out_trade_no'] = $out_trade_no;
$data['total_fee'] = '1';
$data['spbill_create_ip'] = $this->get_client_ip();
$data['attach'] = '微信扫码支付';
$data['body'] = $body."订单号:{$out_trade_no}";
$data['appid'] = $wechat['appid'];
$data['mch_id'] = $wechat['mchid'];
$data['nonce_str'] = getTime();
$data['trade_type'] = "JSAPI";
$data['notify_url'] = url('user/Pay/pay_deal_with');
$data['openid'] = getTime();
// 签名加密
$sign = $this->getParam($data);
// 转化XML格式
$dataXML = "<xml>
<appid>".$data['appid']."</appid>
<attach>".$data['attach']."</attach>
<body>".$data['body']."</body>
<mch_id>".$data['mch_id']."</mch_id>
<nonce_str>".$data['nonce_str']."</nonce_str>
<notify_url>".$data['notify_url']."</notify_url>
<out_trade_no>".$data['out_trade_no']."</out_trade_no>
<openid>".$data['openid']."</openid>
<spbill_create_ip>".$data['spbill_create_ip']."</spbill_create_ip>
<total_fee>".$data['total_fee']."</total_fee>
<trade_type>".$data['trade_type']."</trade_type>
<sign>".$sign."</sign>
</xml>";
// 调用接口,转换回数组格式
$result = $this->xmlToArray($this->httpsPost('https://api.mch.weixin.qq.com/pay/unifiedorder', $dataXML));
// 请求接口成功
if (!empty($result['return_code']) && $result['return_code'] == 'SUCCESS' && $result['return_msg'] == 'OK') {
if ('FAIL' == $result['result_code'] && !empty($result['err_code']) && !empty($result['err_code_des'])) {
if (stristr($result['err_code_des'], 'openid')) {
return true;
} else {
$result['return_code'] = 'FAIL';
$result['return_msg'] = $result['err_code_des'];
return $result;
}
} else {
return true;
}
}
// 请求接口失败
else if (!empty($result['return_code']) && $result['return_code'] == 'FAIL') {
if (stristr($result['return_msg'], '签名错误')) {
$result['return_msg'] = '微信支付KEY密钥不正确';
} else if (stristr($result['return_msg'], 'mch_id')) {
$result['return_msg'] = '微信支付商户号配置不正确';
} else if (stristr($result['return_msg'], 'appid')) {
$result['return_msg'] = '微信支付AppID配置不正确';
}
return $result;
}
}
// 验证支付宝支付配置是否正确
public function VerifyAliPayConfig($alipay = [])
{
if (!empty($alipay)) {
// 时间戳当订单号
$order_number = getTime();
// 引入文件
vendor('alipay.pagepay.service.AlipayTradeService');
vendor('alipay.pagepay.buildermodel.AlipayTradeQueryContentBuilder');
// 实例化加载订单号
$RequestBuilder = new \AlipayTradeQueryContentBuilder;
$out_trade_no = trim($order_number);
$RequestBuilder->setOutTradeNo($out_trade_no);
// 处理支付宝配置数据
$config['app_id'] = $alipay['app_id'];
$config['merchant_private_key'] = $alipay['merchant_private_key'];
$config['charset'] = 'UTF-8';
$config['sign_type'] = 'RSA2';
$config['gatewayUrl'] = 'https://openapi.alipay.com/gateway.do';
$config['alipay_public_key'] = $alipay['alipay_public_key'];
// 实例化支付宝配置
$aop = new \AlipayTradeService($config);
// 返回结果
$result = $aop->IsQuery($RequestBuilder, 'admin_pay');
$result = json_decode(json_encode($result), true);
// 判断结果
if ('40004' == $result['code'] && 'Business Failed' == $result['msg']) {
// 用于支付宝支付配置验证
return 'ok';
} else if ('40001' == $result['code'] && 'Missing Required Arguments' == $result['msg']) {
return '商户私钥错误!';
} else if (is_array($result)) {
$msg = !empty($result['sub_msg']) ? $result['sub_msg'] : '请确保配置正确,且检查支付宝平台的权限';
return $msg;
} else {
return $result;
}
}
}
// 获取客户端IP
private function get_client_ip()
{
if(getenv('HTTP_CLIENT_IP') && strcasecmp(getenv('HTTP_CLIENT_IP'), 'unknown')) {
$ip = getenv('HTTP_CLIENT_IP');
} elseif(getenv('HTTP_X_FORWARDED_FOR') && strcasecmp(getenv('HTTP_X_FORWARDED_FOR'), 'unknown')) {
$ip = getenv('HTTP_X_FORWARDED_FOR');
} elseif(getenv('REMOTE_ADDR') && strcasecmp(getenv('REMOTE_ADDR'), 'unknown')) {
$ip = getenv('REMOTE_ADDR');
} elseif(isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'], 'unknown')) {
$ip = $_SERVER['REMOTE_ADDR'];
}
return preg_match ( '/[\d\.]{7,15}/', $ip, $matches ) ? $matches [0] : '';
}
// 对参数排序,生成MD5加密签名
private function getParam($paramArray, $isencode=false)
{
$paramStr = '';
ksort($paramArray);
$i = 0;
foreach ($paramArray as $key => $value)
{
if ($key == 'Signature'){
continue;
}
if ($i == 0){
$paramStr .= '';
}else{
$paramStr .= '&';
}
$paramStr .= $key . '=' . ($isencode ? urlencode($value) : $value);
++$i;
}
$stringSignTemp=$paramStr."&key=".$this->key;
$sign=strtoupper(md5($stringSignTemp));
return $sign;
}
// POST提交数据
private function httpsPost($url = '', $paramsXml = [], $ssl = false, $payConfig = [])
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
if (!empty($ssl)) {
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_SSLKEYTYPE, 'PEM');
curl_setopt($ch, CURLOPT_SSLCERTTYPE, 'PEM');
curl_setopt($ch, CURLOPT_SSLKEY, ROOT_PATH . $payConfig['apiclient_key']);
curl_setopt($ch, CURLOPT_SSLCERT, ROOT_PATH . $payConfig['apiclient_cert']);
} else {
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
}
curl_setopt($ch, CURLOPT_AUTOREFERER, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $paramsXml);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($ch);
// 返回错误提示
if (curl_errno($ch)) return 'Errno: ' . curl_error($ch);
// 返回成功数据
curl_close($ch);
return $result;
}
// XML转array
private function xmlToArray($xml = '')
{
@libxml_disable_entity_loader(true);
$xmlstring = (array)simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
$val = json_decode(json_encode($xmlstring),true);
return $val;
}
// 申请微信支付订单退款
public function applyWeChatPayOrderRefund($data = [], $action = '')
{
// 是否允许微信申请退款
if ('verify' == $action) {
// 查询系统订单信息
$where = [
'users_id' => intval($data['users_id']),
'order_id' => intval($data['order_id']),
];
$shopOrder = Db::name('shop_order')->where($where)->find();
if (empty($shopOrder)) $this->error('订单不存在');
if (!empty($shopOrder['pay_name']) && 'wechat' != $shopOrder['pay_name']) $this->error('订单非微信支付,不可申请');
// 查询支付配置
$payConfig = 3 === intval($shopOrder['order_terminal']) ? getOpenMiniCodeConfig('weixin') : getPayApiConfig(1, 'wechat');
if (empty($payConfig)) {
// 小程序配置
$diyminiproMallModel = new \app\plugins\model\DiyminiproMall;
$payConfig = $diyminiproMallModel->detail();
$diyminiproMallSettingModel = new \weapp\DiyminiproMall\model\DiyminiproMallSettingModel;
$setting = $diyminiproMallSettingModel->getSettingValue('setting');
if (!empty($setting['appId'])) $payConfig['appid'] = $setting['appId'];
}
$shopPayConfig = getUsersConfigData('pay');
if (empty($shopPayConfig['pay_original_refund'])) $this->error('请开启【商城中心】-【商城配置】-【基本设置】-【原路退回】功能');
if (empty($shopPayConfig['pay_wechat_apiclient_key'])) $this->error('请上传【商城中心】-【商城配置】-【基本设置】-【apiclient_key】文件');
if (empty($shopPayConfig['pay_wechat_apiclient_cert'])) $this->error('请上传【商城中心】-【商城配置】-【基本设置】-【apiclient_cert】文件');
$payConfig['apiclient_key'] = trim($shopPayConfig['pay_wechat_apiclient_key']);
$payConfig['apiclient_cert'] = trim($shopPayConfig['pay_wechat_apiclient_cert']);
// 查询微信订单信息
$userPayApi = new \app\user\model\PayApi();
$payResult = $userPayApi->getWeChatPayResult($shopOrder['users_id'], $shopOrder['order_code'], $payConfig);
if (empty($payResult)) $this->error('未查询到相关的微信订单,请核实再提交');
if ('NOTPAY' == $payResult['trade_state'] || empty($payResult['transaction_id'])) $this->error('微信订单尚未支付,不可申请');
if (floatval($data['actual_price']) > (floatval($payResult['total_fee']) / 100)) $this->error('退款金额超过订单金额,不可申请');
// 返回信息
$result = [
'shopOrder' => $shopOrder,
'payConfig' => $payConfig,
'payResult' => $payResult,
'refundCode' => trim($data['refund_code']),
'actualPrice' => floatval($data['actual_price']),
];
return ['code' => 1, 'data' => $result];
}
// 提交允许微信申请退款
else if ('submit' == $action) {
// 订单及支付信息
$shopOrder = !empty($data['shopOrder']) ? $data['shopOrder'] : [];
$payConfig = !empty($data['payConfig']) ? $data['payConfig'] : [];
$payResult = !empty($data['payResult']) ? $data['payResult'] : [];
$refundCode = !empty($data['refundCode']) ? trim($data['refundCode']) : '';
$actualPrice = !empty($data['actualPrice']) ? floatval($data['actualPrice']) : 0;
// 使用配置key
if (!empty($payConfig['key'])) {
$this->key = $payConfig['key'];
}
else if (!empty($payConfig['apikey'])) {
$this->key = $payConfig['apikey'];
}
// 调用微信申请退款接口
$post = [
'appid' => $payConfig['appid'],
'mch_id' => $payConfig['mchid'],
'nonce_str' => $this->createNonceStr(),
'total_fee' => floatval($payResult['total_fee']),
'refund_fee' => floatval($actualPrice) * 100,
'sign_type' => 'MD5',
'transaction_id' => $payResult['transaction_id'],
'out_trade_no' => $shopOrder['order_code'],
'out_refund_no' => $refundCode,
'refund_desc' => '商品已售完',
];
$post['sign'] = $this->getParam($post);
// 请求接口
$result = $this->xmlToArray($this->httpsPost('https://api.mch.weixin.qq.com/secapi/pay/refund', $this->arrayToXml($post), true, $payConfig));
// 请求接口成功
if (!empty($result['return_code']) && $result['return_code'] == 'SUCCESS' && $result['return_msg'] == 'OK') {
// 申请成功
if (!empty($result['result_code']) && $result['result_code'] == 'SUCCESS') {
return $result;
}
// 申请失败
else if (!empty($result['result_code']) && $result['result_code'] == 'FAIL') {
$result['return_msg'] = $result['err_code_des'];
$result['return_code'] = $result['result_code'];
}
}
// 请求接口失败
else if (!empty($result['return_code']) && $result['return_code'] == 'FAIL') {
if (stristr($result['return_msg'], '签名错误')) {
$result['return_msg'] = '微信支付KEY密钥不正确';
} else if (stristr($result['return_msg'], 'mch_id')) {
$result['return_msg'] = '微信支付商户号配置不正确';
} else if (stristr($result['return_msg'], 'appid')) {
$result['return_msg'] = '微信支付AppID配置不正确';
}
}
if (isset($result[0]) && false === $result[0]) {
$result['return_msg'] = '请检查微信支付证书是否过期或未上传';
$result['return_code'] = 'FAIL';
}
return ['return_code' => $result['return_code'], 'return_msg' => $result['return_msg']];
}
// 报错提示
else {
$this->error('请执行验证或提交操作');
}
}
// 查询微信退款信息
public function inquireWeChatPayOrderRefund($service = [], $orderTerminal = 0)
{
// 查询支付配置
$payConfig = 3 === intval($orderTerminal) ? getOpenMiniCodeConfig('weixin') : getPayApiConfig(1, 'wechat');
if (empty($payConfig)) {
// 小程序配置
$diyminiproMallModel = new \app\plugins\model\DiyminiproMall;
$payConfig = $diyminiproMallModel->detail();
$diyminiproMallSettingModel = new \weapp\DiyminiproMall\model\DiyminiproMallSettingModel;
$setting = $diyminiproMallSettingModel->getSettingValue('setting');
if (!empty($setting['appId'])) $payConfig['appid'] = $setting['appId'];
}
$shopPayConfig = getUsersConfigData('pay');
if (empty($shopPayConfig['pay_original_refund'])) $this->error('请开启【商城中心】-【商城配置】-【基本设置】-【原路退回】功能');
if (empty($shopPayConfig['pay_wechat_apiclient_key'])) $this->error('请上传【商城中心】-【商城配置】-【基本设置】-【apiclient_key】文件');
if (empty($shopPayConfig['pay_wechat_apiclient_cert'])) $this->error('请上传【商城中心】-【商城配置】-【基本设置】-【apiclient_cert】文件');
$payConfig['apiclient_key'] = trim($shopPayConfig['pay_wechat_apiclient_key']);
$payConfig['apiclient_cert'] = trim($shopPayConfig['pay_wechat_apiclient_cert']);
// 使用配置key
if (!empty($payConfig['key'])) {
$this->key = $payConfig['key'];
}
else if (!empty($payConfig['apikey'])) {
$this->key = $payConfig['apikey'];
}
// 调用微信申请退款接口
$post = [
'appid' => $payConfig['appid'],
'mch_id' => $payConfig['mchid'],
'nonce_str' => $this->createNonceStr(),
'sign_type' => 'MD5',
'out_refund_no' => $service['refund_code'],
];
$post['sign'] = $this->getParam($post);
// 请求接口
$result = $this->xmlToArray($this->httpsPost('https://api.mch.weixin.qq.com/pay/refundquery', $this->arrayToXml($post)));
if (empty($result)) $this->error('未查询到相关的微信退款订单,请核实再查询');
// 处理显示数据
$result['total_fee'] = floatval(floatval($result['total_fee']) / floatval(100));
$result['refund_fee'] = floatval(floatval($result['refund_fee']) / floatval(100));
$result['refund_fee_0'] = floatval(floatval($result['refund_fee_0']) / floatval(100));
$result['refund_remark'] = !empty($service['refund_remark']) ? $service['refund_remark'] : '-';
$result['update_time'] = !empty($service['update_time']) ? date('Y-m-d H:i:s', $service['update_time']) : '-';
// 退款状态
if (!empty($result['refund_status_0']) && 'SUCCESS' == $result['refund_status_0']) {
$result['refund_status_0'] = '退款成功';
}
else if (!empty($result['refund_status_0']) && 'REFUNDCLOSE' == $result['refund_status_0']) {
$result['refund_status_0'] = '退款关闭,商户发起退款失败';
}
else if (!empty($result['refund_status_0']) && 'PROCESSING' == $result['refund_status_0']) {
$result['refund_status_0'] = '退款处理中';
}
else if (!empty($result['refund_status_0']) && 'CHANGE' == $result['refund_status_0']) {
$result['refund_status_0'] = '退款异常,退款到银行发现用户的卡作废或者冻结了,导致原路退款银行卡失败,可前往商户平台(pay.weixin.qq.com)-交易中心,手动处理此笔退款';
}
// 退款方式
if (!empty($result['refund_channel_0']) && 'ORIGINAL' == $result['refund_channel_0']) {
$result['refund_channel_0'] = '原路退款';
}
else if (!empty($result['refund_channel_0']) && 'BALANCE' == $result['refund_channel_0']) {
$result['refund_channel_0'] = '退回到余额';
}
else if (!empty($result['refund_channel_0']) && 'OTHER_BALANCE' == $result['refund_channel_0']) {
$result['refund_channel_0'] = '原账户异常退到其他余额账户';
}
else if (!empty($result['refund_channel_0']) && 'OTHER_BANKCARD' == $result['refund_channel_0']) {
$result['refund_channel_0'] = '原银行卡异常退到其他银行卡';
}
// 退款资金来源
if (!empty($result['refund_account_0']) && 'REFUND_SOURCE_RECHARGE_FUNDS' == $result['refund_account_0']) {
$result['refund_account_0'] = '可用余额退款/基本账户';
}
else if (!empty($result['refund_account_0']) && 'REFUND_SOURCE_UNSETTLED_FUNDS' == $result['refund_account_0']) {
$result['refund_account_0'] = '未结算资金退款';
}
return $result;
}
// 获取系统唯一系列号
public function getEyouCmsSerialNumber()
{
// 序列号提取
$serial_number = DEFAULT_SERIALNUMBER;
$constsant_path = APP_PATH . MODULE_NAME . '/conf/constant.php';
if (file_exists($constsant_path)) {
require_once($constsant_path);
defined('SERIALNUMBER') && $serial_number = SERIALNUMBER;
}
return $serial_number;
}
// 获取指定数量随机数
private function createNonceStr($length = 16)
{
$chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
$str = '';
for ($i = 0; $i < $length; $i++) {
$str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
}
return $str;
}
private function arrayToXml($arr = [])
{
$xml = "<xml>";
foreach ($arr as $key => $val) {
if (is_numeric($val)) {
$xml .= "<" . $key . ">" . $val . "</" . $key . ">";
} else {
$xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">";
}
}
$xml .= "</xml>";
return $xml;
}
}