更新数据库结构

This commit is contained in:
技术老胡
2026-03-10 13:47:28 +08:00
parent 54ad21ac8f
commit 9de902231f
54 changed files with 5070 additions and 501 deletions

View File

@@ -0,0 +1,132 @@
<?php
namespace app\http\api\controller;
use app\common\base\BaseController;
use app\services\api\EpayService;
use app\validation\EpayValidator;
use support\Request;
use support\Response;
/**
* 易支付控制器
*/
class EpayController extends BaseController
{
public function __construct(
protected EpayService $epayService
) {}
/**
* 页面跳转支付
*/
public function submit(Request $request)
{
$data = array_merge($request->get(), $request->post());
try {
// 参数校验(使用自定义 Validator + 场景)
$params = EpayValidator::make($data)
->withScene('submit')
->validate();
// 业务处理:创建订单并获取支付参数
$result = $this->epayService->submit($params, $request);
$payParams = $result['pay_params'] ?? [];
// 根据支付参数类型返回响应
if (($payParams['type'] ?? '') === 'redirect' && !empty($payParams['url'])) {
return redirect($payParams['url']);
}
if (($payParams['type'] ?? '') === 'form') {
return $this->renderForm($payParams);
}
// 如果没有匹配的类型,返回错误
return $this->fail('支付参数生成失败');
} catch (\Throwable $e) {
return $this->fail($e->getMessage());
}
}
/**
* API接口支付
*/
public function mapi(Request $request)
{
$data = $request->post();
try {
$params = EpayValidator::make($data)
->withScene('mapi')
->validate();
$result = $this->epayService->mapi($params, $request);
return json($result);
} catch (\Throwable $e) {
return json([
'code' => 0,
'msg' => $e->getMessage(),
]);
}
}
/**
* API接口
*/
public function api(Request $request)
{
$data = array_merge($request->get(), $request->post());
try {
$act = strtolower($data['act'] ?? '');
if ($act === 'order') {
$params = EpayValidator::make($data)
->withScene('api_order')
->validate();
$result = $this->epayService->api($params);
} elseif ($act === 'refund') {
$params = EpayValidator::make($data)
->withScene('api_refund')
->validate();
$result = $this->epayService->api($params);
} else {
$result = [
'code' => 0,
'msg' => '不支持的操作类型',
];
}
return json($result);
} catch (\Throwable $e) {
return json([
'code' => 0,
'msg' => $e->getMessage(),
]);
}
}
/**
* 渲染表单提交 HTML用于页面跳转支付
*/
private function renderForm(array $formParams): Response
{
$html = '<!DOCTYPE html><html><head><meta charset="UTF-8"><title>跳转支付</title></head><body>';
$html .= '<form id="payForm" method="' . htmlspecialchars($formParams['method'] ?? 'POST') . '" action="' . htmlspecialchars($formParams['action'] ?? '') . '">';
if (isset($formParams['fields']) && is_array($formParams['fields'])) {
foreach ($formParams['fields'] as $name => $value) {
$html .= '<input type="hidden" name="' . htmlspecialchars($name) . '" value="' . htmlspecialchars((string)$value) . '">';
}
}
$html .= '</form>';
$html .= '<script>document.getElementById("payForm").submit();</script>';
$html .= '</body></html>';
return response($html)->withHeaders(['Content-Type' => 'text/html; charset=UTF-8']);
}
}

View File

@@ -0,0 +1,41 @@
<?php
namespace app\http\api\controller;
use app\common\base\BaseController;
use app\services\PayOrderService;
use support\Request;
/**
* 支付控制器OpenAPI
*/
class PayController extends BaseController
{
public function __construct(
protected PayOrderService $payOrderService
) {}
/**
* 创建订单
*/
public function create(Request $request) {}
/**
* 查询订单
*/
public function query(Request $request) {}
/**
* 关闭订单
*/
public function close(Request $request) {}
/**
* 订单退款
*/
public function refund(Request $request) {}
/**
* 异步通知
*/
public function notify(Request $request) {}
}

View File

@@ -0,0 +1,69 @@
<?php
namespace app\http\api\middleware;
use Webman\MiddlewareInterface;
use Webman\Http\Request;
use Webman\Http\Response;
use app\exceptions\UnauthorizedException;
use app\repositories\MerchantAppRepository;
/**
* OpenAPI 签名认证中间件
*
* 验证 AppId + 签名
*/
class EpayAuthMiddleware implements MiddlewareInterface
{
protected MerchantAppRepository $merchantAppRepository;
public function __construct()
{
// 延迟加载,避免循环依赖
$this->merchantAppRepository = new MerchantAppRepository();
}
public function process(Request $request, callable $handler): Response
{
$appId = $request->header('X-App-Id', '') ?: ($request->post('app_id', '') ?: $request->get('app_id', ''));
$timestamp = $request->header('X-Timestamp', '') ?: ($request->post('timestamp', '') ?: $request->get('timestamp', ''));
$nonce = $request->header('X-Nonce', '') ?: ($request->post('nonce', '') ?: $request->get('nonce', ''));
$signature = $request->header('X-Signature', '') ?: ($request->post('signature', '') ?: $request->get('signature', ''));
if (empty($appId) || empty($timestamp) || empty($nonce) || empty($signature)) {
throw new UnauthorizedException('缺少认证参数');
}
// 验证时间戳5分钟内有效
if (abs(time() - (int)$timestamp) > 300) {
throw new UnauthorizedException('请求已过期');
}
// 查询应用
$app = $this->merchantAppRepository->findByAppId($appId);
if (!$app) {
throw new UnauthorizedException('应用不存在或已禁用');
}
// 验证签名
$method = $request->method();
$path = $request->path();
$body = $request->rawBody();
$bodySha256 = hash('sha256', $body);
$signString = "app_id={$appId}&timestamp={$timestamp}&nonce={$nonce}&method={$method}&path={$path}&body_sha256={$bodySha256}";
$expectedSignature = hash_hmac('sha256', $signString, $app->app_secret);
if (!hash_equals($expectedSignature, $signature)) {
throw new UnauthorizedException('签名验证失败');
}
// 将应用信息注入到请求对象
$request->app = $app;
$request->merchantId = $app->merchant_id;
$request->appId = $app->id;
return $handler($request);
}
}

View File

@@ -0,0 +1,69 @@
<?php
namespace app\http\api\middleware;
use Webman\MiddlewareInterface;
use Webman\Http\Request;
use Webman\Http\Response;
use app\exceptions\UnauthorizedException;
use app\repositories\MerchantAppRepository;
/**
* OpenAPI 签名认证中间件
*
* 验证 AppId + 签名
*/
class OpenApiAuthMiddleware implements MiddlewareInterface
{
protected MerchantAppRepository $merchantAppRepository;
public function __construct()
{
// 延迟加载,避免循环依赖
$this->merchantAppRepository = new MerchantAppRepository();
}
public function process(Request $request, callable $handler): Response
{
$appId = $request->header('X-App-Id', '') ?: ($request->post('app_id', '') ?: $request->get('app_id', ''));
$timestamp = $request->header('X-Timestamp', '') ?: ($request->post('timestamp', '') ?: $request->get('timestamp', ''));
$nonce = $request->header('X-Nonce', '') ?: ($request->post('nonce', '') ?: $request->get('nonce', ''));
$signature = $request->header('X-Signature', '') ?: ($request->post('signature', '') ?: $request->get('signature', ''));
if (empty($appId) || empty($timestamp) || empty($nonce) || empty($signature)) {
throw new UnauthorizedException('缺少认证参数');
}
// 验证时间戳5分钟内有效
if (abs(time() - (int)$timestamp) > 300) {
throw new UnauthorizedException('请求已过期');
}
// 查询应用
$app = $this->merchantAppRepository->findByAppId($appId);
if (!$app) {
throw new UnauthorizedException('应用不存在或已禁用');
}
// 验证签名
$method = $request->method();
$path = $request->path();
$body = $request->rawBody();
$bodySha256 = hash('sha256', $body);
$signString = "app_id={$appId}&timestamp={$timestamp}&nonce={$nonce}&method={$method}&path={$path}&body_sha256={$bodySha256}";
$expectedSignature = hash_hmac('sha256', $signString, $app->app_secret);
if (!hash_equals($expectedSignature, $signature)) {
throw new UnauthorizedException('签名验证失败');
}
// 将应用信息注入到请求对象
$request->app = $app;
$request->merchantId = $app->merchant_id;
$request->appId = $app->id;
return $handler($request);
}
}