This commit is contained in:
Your Name
2026-03-11 14:33:49 +08:00
parent 38ad60f4bb
commit 08dd9cd307
57 changed files with 9547 additions and 379 deletions
@@ -0,0 +1,128 @@
<?php
declare(strict_types=1);
namespace app\adminapi\controller\order;
use app\common\model\Order;
use think\response\Xml;
/**
* 微信支付回调控制器
* Class WechatNotifyController
* @package app\adminapi\controller\order
*/
class WechatNotifyController
{
/**
* @notes 微信异步通知
* @return Xml
*/
public function notify()
{
try {
// 获取微信配置
$wechatConfig = config('pay.wechat');
// 获取XML数据
$xmlData = file_get_contents('php://input');
$data = $this->xmlToArray($xmlData);
// 验证签名
if (!$this->verifyWechatSign($data, $wechatConfig['api_key'])) {
return $this->xmlResponse('FAIL', '签名验证失败');
}
// 验证金额
$order = Order::where('order_no', $data['out_trade_no'])->find();
if (!$order) {
return $this->xmlResponse('FAIL', '订单不存在');
}
if ((int)$data['total_fee'] != (int)($order->amount * 100)) {
return $this->xmlResponse('FAIL', '金额不匹配');
}
// 验证交易状态
if ($data['result_code'] == 'SUCCESS') {
// 更新订单状态
if ($order->status == 1) { // 只有待支付的订单才能更新
$order->status = 2; // 已支付
$order->payment_method = 'wechat';
$order->payment_time = date('Y-m-d H:i:s');
$order->trade_no = $data['transaction_id'];
$order->save();
}
}
return $this->xmlResponse('SUCCESS', '支付成功');
} catch (\Exception $e) {
return $this->xmlResponse('FAIL', $e->getMessage());
}
}
/**
* @notes 验证微信签名
* @param array $data
* @param string $apiKey
* @return bool
*/
private function verifyWechatSign(array $data, string $apiKey): bool
{
try {
// 获取签名
$sign = $data['sign'] ?? '';
unset($data['sign']);
// 按键排序
ksort($data);
// 构建签名字符串
$signStr = '';
foreach ($data as $key => $value) {
if ($value !== '' && $value !== null) {
$signStr .= $key . '=' . $value . '&';
}
}
$signStr .= 'key=' . $apiKey;
// MD5签名
$computedSign = strtoupper(md5($signStr));
return $computedSign === $sign;
} catch (\Exception $e) {
return false;
}
}
/**
* @notes XML转数组
* @param string $xml
* @return array
*/
private function xmlToArray(string $xml): array
{
try {
$data = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
return is_array($data) ? $data : [];
} catch (\Exception $e) {
return [];
}
}
/**
* @notes 返回XML响应
* @param string $returnCode
* @param string $returnMsg
* @return Xml
*/
private function xmlResponse(string $returnCode, string $returnMsg): Xml
{
$xml = '<xml>';
$xml .= '<return_code><![CDATA[' . $returnCode . ']]></return_code>';
$xml .= '<return_msg><![CDATA[' . $returnMsg . ']]></return_msg>';
$xml .= '</xml>';
return response($xml, 200, ['Content-Type' => 'application/xml']);
}
}