baji/app/api/controller/Pay.php
2025-03-03 14:47:45 +08:00

483 lines
16 KiB
PHP
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
declare(strict_types=1);
namespace app\api\controller;
use app\common\model\Order as OrderModel;
use app\common\model\ProductOrder;
use app\common\model\UserRecharge;
use think\App;
use think\facade\Db;
use app\common\model\User;
class Pay extends Base
{
public function __construct()
{
if ($this->ish5()) {
$config = getConfig('wechatofficialaccount');
$this->appid = $config['appid'];
$this->merchant = $config['mch_id'];
$this->secretKey = $config['keys'];
} else {
$config = getConfig('weixinpay');
$this->appid = $config['appid'];
$this->merchant = $config['mch_id'];
$this->secretKey = $config['keys'];
}
$this->noticeurl = request()->domain() . '/api/notify/order_notify';#订单回调URL
}
//支付
/**
* [pay description]
* @param [type] $uid [用户 的id]
* @param [type] $order_num [订单号]
* @param [pay_type] [支付类型 1 微信 ]
* @return [type] [支付来源 1 盲盒订单 2运费 3 余额充值 4 积分商城支付]
*/
public function pay($order_num, $title, $openid, $type)
{
if ($type == 1) {
$order = OrderModel::getInfo(['order_num' => $order_num]);
if ($order['status'] != 1) {
return $this->renderError("参数错误");
}
$total = $order['total_price'];
if ($total > 0) {
$notify = 'https://' . $_SERVER['HTTP_HOST'] . '/api/notify/order_notify1';
return $this->wxpay($order_num, $total, "支付订单-" . $title, $openid, $notify);
} else {
// if($order['money'] > 0){
// User::changeMoney($order['user_id'],'-'.$order['money'],3);
// }
// if($order['integral'] > 0){
// User::changeIntegral($order['user_id'],'-'.$order['integral'],3);
// }
$notify = new \app\api\controller\Notify($this->app);
$data = $notify->order_update($order_num, 1);
if ($data == 1) {
$data = [];
$data['is_weixin'] = 2;
return json_encode($data);
}
}
} elseif ($type == 2) {
//发货订单支付运费
$config = getConfig("base");
$total = $config['post_money']; //邮费
$notify = 'https://' . $_SERVER['HTTP_HOST'] . '/api/notify/order_notify2';
return $this->wxpay($order_num, $total, $title, $openid, $notify);
} elseif ($type == 3) {
//余额充值
$order = UserRecharge::getInfo(['order_num' => $order_num]);
$total = $order['money'];
$notify = 'https://' . $_SERVER['HTTP_HOST'] . '/api/notify/order_notify3';
return $this->wxpay($order_num, $total, $title, $openid, $notify);
} elseif ($type == 4) {
//积分 商城购买
$order = ProductOrder::getInfo(['order_num' => $order_num]);
$total = $order['total_money'];
$notify = 'https://' . $_SERVER['HTTP_HOST'] . '/api/notify/order_notify4';
return $this->wxpay($order_num, $total, $title, $openid, $notify);
} elseif ($type == 5) {
} elseif ($type == 6) {
$order = OrderModel::getInfo(['order_num' => $order_num]);
if ($order['status'] != 1) {
return $this->renderError("参数错误");
}
$total = $order['total_price'];
if ($total > 0) {
$notify = 'https://' . $_SERVER['HTTP_HOST'] . '/api/notify/order_notify6';
return $this->wxpay($order_num, $total, "支付订单-" . $title, $openid, $notify);
} else {
$notify = new \app\api\controller\Notify($this->app);
$data = $notify->order_update($order_num, 6);
if ($data == 1) {
$data = [];
$data['is_weixin'] = 2;
return json_encode($data);
}
}
} elseif ($type == 7) {
$order = Db::name('kk_order')->where('order_no', $order_num)->find();
if ($order['status'] !== 0) {
return $this->renderError("参数错误");
}
$total = $order['price'];
if ($total > 0) {
$notify = 'https://' . $_SERVER['HTTP_HOST'] . '/api/notify/order_notify7';
return $this->wxpay($order_num, $total, "秒杀商城订单-" . $title, $openid, $notify);
} else {
// dd($this->app);
// $notify = new Notify($this->app);
$res = Notify::order_update($order_num, 7);
$data['res'] = $res;
$data['is_weixin'] = 2;
return json_encode($data);
}
}
}
//支付
public function wxpay($order_num, $money, $title, $openid, $notify)
{
$openidx = $openid;
if ($this->ish5()) {
$user = User::getInfo(['openid' => $openidx]);
if ($user != null && $user['gzh_openid'] != null && $user['gzh_openid'] != "") {
$openidx = $user['gzh_openid'];
}
}
// $weixinpay = getConfig('weixinpay');
// //支付代码
// $url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
// $data['openid']=$openid;
// $data['appid']= $this->appid;
// $data['mch_id']= $this->merchant;
// $data['nonce_str']=$this->genRandomString();
// $data['body']=$title;
// $data['out_trade_no']=$order_num;
// $data['total_fee'] = $money*100;
// $data['spbill_create_ip'] = '127.0.0.1';
// $data['notify_url'] = $notify;
// $data['time_expire'] = date('YmdHis',time()+60);
// $data['trade_type'] = 'JSAPI';
// $sign = $this->MakeSign($data);
// $data['sign']=$sign;
// // dd($data);
// $dataxml = $this->data_to_xml($data);
// $resXml = $this->postXmlCurl($url,$dataxml);
// $resData = $this->xml_to_data($resXml);
$body = mb_substr($title, 0, 30);
// $notifyUrl = $this->noticeurl;
$nonce_str = $this->genRandomString();
$params['appid'] = $this->appid;
$params['mch_id'] = $this->merchant;
$params['nonce_str'] = $this->genRandomString();
$params['body'] = $body;
$params['attach'] = 'order_ckj';
$params['out_trade_no'] = $order_num;
$params['notify_url'] = $notify;
// $params['total_fee'] = round($money * 100, 2);
$params['total_fee'] = 1;
$params['spbill_create_ip'] = $this->get_client_ip();
$params['trade_type'] = 'JSAPI';
$params['openid'] = $openidx;
$params['sign'] = $this->MakeSign($params);
// dd($params);
$xml = $this->data_to_xml($params);
$url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
$response = $this->postXmlCurl($xml, $url);
$resData = $this->xml_to_data($response);
// p($resData);
if (!$resData || $resData['return_code'] != 'SUCCESS' || $resData['result_code'] != 'SUCCESS') {
$return['status'] = 0;
$return['msg'] = "网络故障,请稍后重试(支付参数错误)";
return json_encode($return);
} else {
$return['appId'] = $resData['appid'];
$return['nonceStr'] = $this->genRandomString();
$return['package'] = 'prepay_id=' . $resData['prepay_id'];
$return['signType'] = 'MD5';
$return['timeStamp'] = (string) time();
$return['paySign'] = $this->MakeSign($return);
$return['is_weixin'] = 1;
return json_encode($return);
}
}
/**
* 微信小程序下单方法
* @param $params 下单参数
*/
public function wxCreateOrder($order_no, $price, $openid, $body, $attach)
{
$openidx = $openid;
if ($this->ish5()) {
$user = User::getInfo(['openid' => $openidx]);
if ($user != null && $user['gzh_openid'] != null && $user['gzh_openid'] != "") {
$openidx = $user['gzh_openid'];
}
}
$body = mb_substr($body, 0, 30);
$notifyUrl = $this->noticeurl;
$nonce_str = $this->genRandomString();
$params['appid'] = $this->appid;
$params['mch_id'] = $this->merchant;
$params['nonce_str'] = $this->genRandomString();
$params['body'] = $body;
$params['attach'] = $attach;
$params['out_trade_no'] = $order_no;
$params['notify_url'] = $notifyUrl;
$params['total_fee'] = round($price * 100, 2);
$params['spbill_create_ip'] = $this->get_client_ip();
$params['trade_type'] = 'JSAPI';
$params['openid'] = $openidx ;
$params['sign'] = $this->MakeSign($params);
$xml = $this->data_to_xml($params);
$url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
$response = $this->postXmlCurl($xml, $url);
$result = $this->xml_to_data($response);
if ($result['return_code'] === 'SUCCESS' && $result['result_code'] === 'SUCCESS') {
$time = time();
$res['appId'] = $this->appid;
$res["timeStamp"] = (string) $time;
$res["nonceStr"] = $nonce_str;
$res["package"] = "prepay_id=" . $result['prepay_id'];
$res["signType"] = 'MD5';
$res["paySign"] = $this->MakeSign($res);
return ['status' => 1, 'data' => $res];
} else {
return ['status' => 0, 'msg' => '支付失败'];
}
}
/**
* 生成签名
* @return 签名
*/
public function MakeSign($params)
{
//签名步骤一:按字典序排序数组参数
ksort($params);
$string = $this->ToUrlParams($params);
//签名步骤二在string后加入KEY
$string = $string . "&key=" . $this->secretKey;
//签名步骤三MD5加密
$string = md5($string);
//签名步骤四:所有字符转为大写
$result = strtoupper($string);
return $result;
}
/**
* 将参数拼接为url: key=value&key=value
* @param $params
* @return string
*/
public function ToUrlParams($params)
{
$string = '';
if (!empty($params)) {
$array = array();
foreach ($params as $key => $value) {
$array[] = $key . '=' . $value;
}
$string = implode("&", $array);
}
return $string;
}
/**
* 输出xml字符
* @param $params 参数名称
* return string 返回组装的xml
**/
public function data_to_xml($params)
{
if (!is_array($params) || count($params) <= 0) {
return false;
}
$xml = "<xml>";
foreach ($params as $key => $val) {
if (is_numeric($val)) {
$xml .= "<" . $key . ">" . $val . "</" . $key . ">";
} else {
$xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">";
}
}
$xml .= "</xml>";
return $xml;
}
/**
* 将xml转为array
* @param string $xml
* return array
*/
public function xml_to_data($xml)
{
if (!$xml) {
return false;
}
//将XML转为array
//禁止引用外部xml实体
libxml_disable_entity_loader(true);
$data = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
return $data;
}
/**
* 产生一个指定长度的随机字符串,并返回给用户
* @param type $len 产生字符串的长度
* @return string 随机字符串
*/
private function genRandomString($len = 32)
{
$chars = array(
"a",
"b",
"c",
"d",
"e",
"f",
"g",
"h",
"i",
"j",
"k",
"l",
"m",
"n",
"o",
"p",
"q",
"r",
"s",
"t",
"u",
"v",
"w",
"x",
"y",
"z",
"A",
"B",
"C",
"D",
"E",
"F",
"G",
"H",
"I",
"J",
"K",
"L",
"M",
"N",
"O",
"P",
"Q",
"R",
"S",
"T",
"U",
"V",
"W",
"X",
"Y",
"Z",
"0",
"1",
"2",
"3",
"4",
"5",
"6",
"7",
"8",
"9"
);
$charsLen = count($chars) - 1;
// 将数组打乱
shuffle($chars);
$output = "";
for ($i = 0; $i < $len; $i++) {
$output .= $chars[mt_rand(0, $charsLen)];
}
return $output;
}
/**
* 以post方式提交xml到对应的接口url
*
* @param string $xml 需要post的xml数据
* @param string $url url
* @param bool $useCert 是否需要证书,默认不需要
* @param int $second url执行超时时间默认30s
* @throws WxPayException
*/
private function postXmlCurl($xml, $url, $second = 30)
{
$ch = curl_init();
//设置超时
curl_setopt($ch, CURLOPT_TIMEOUT, $second);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
//设置header
curl_setopt($ch, CURLOPT_HEADER, FALSE);
//要求结果为字符串且输出到屏幕上
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
//post提交方式
curl_setopt($ch, CURLOPT_POST, TRUE);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
//运行curl
$data = curl_exec($ch);
//返回结果
if ($data) {
curl_close($ch);
return $data;
} else {
$error = curl_errno($ch);
curl_close($ch);
return false;
}
}
/**
* 错误代码
* @param $code 服务器输出的错误代码
* return string
*/
public function error_code($code)
{
$errList = array(
'NOAUTH' => '商户未开通此接口权限',
'NOTENOUGH' => '用户帐号余额不足',
'ORDERNOTEXIST' => '订单号不存在',
'ORDERPAID' => '商户订单已支付,无需重复操作',
'ORDERCLOSED' => '当前订单已关闭,无法支付',
'SYSTEMERROR' => '系统错误!系统超时',
'APPID_NOT_EXIST' => '参数中缺少APPID',
'MCHID_NOT_EXIST' => '参数中缺少MCHID',
'APPID_MCHID_NOT_MATCH' => 'appid和mch_id不匹配',
'LACK_PARAMS' => '缺少必要的请求参数',
'OUT_TRADE_NO_USED' => '同一笔交易不能多次提交',
'SIGNERROR' => '参数签名结果不正确',
'XML_FORMAT_ERROR' => 'XML格式错误',
'REQUIRE_POST_METHOD' => '未使用post传递参数 ',
'POST_DATA_EMPTY' => 'post数据不能为空',
'NOT_UTF8' => '未使用指定编码格式',
);
if (array_key_exists($code, $errList)) {
return $errList[$code];
}
}
function get_client_ip()
{
if (isset($_SERVER['REMOTE_ADDR'])) {
$cip = $_SERVER['REMOTE_ADDR'];
} elseif (getenv("REMOTE_ADDR")) {
$cip = getenv("REMOTE_ADDR");
} elseif (getenv("HTTP_CLIENT_IP")) {
$cip = getenv("HTTP_CLIENT_IP");
} else {
$cip = "127.0.0.1";
}
return $cip;
}
}