Files
SoonDesign/backend-web/public/index.php
T
24kycj 152228d41f 前端配置迁至 config/local.js,完善支付、模板库与部署脚本
- 页面直接引用 local.js 设置 SOON_DEPLOY_CONFIG,移除 deploy-config
- Docker sync-config 生成 local.js;更新 README 与 agent-core 说明
- 模板库自动扫描 .soon;新增后端部署/种子/排查脚本
- 完善支付配置、订阅弹窗与后台支付管理页

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-08 20:48:51 +08:00

103 lines
4.2 KiB
PHP

<?php
declare(strict_types=1);
require __DIR__ . '/../src/bootstrap.php';
use Soon\Api\Controllers\AuthController;
use Soon\Api\Controllers\FileController;
use Soon\Api\Controllers\PayController;
use Soon\Api\Controllers\PlanController;
use Soon\Api\Controllers\SettingsController;
use Soon\Api\Controllers\SoonModelController;
use Soon\Api\Core\Config;
use Soon\Api\Core\Json;
use Soon\Api\Core\Router;
use Soon\Api\Middleware\Auth;
use Soon\Api\Middleware\RateLimit;
$origin = $_SERVER['HTTP_ORIGIN'] ?? '';
$allowed = (array)Config::get('app.cors_origins', []);
if ($origin !== '' && in_array($origin, $allowed, true)) {
header('Access-Control-Allow-Origin: ' . $origin);
header('Vary: Origin');
header('Access-Control-Allow-Credentials: true');
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
header('Access-Control-Allow-Headers: Authorization, Content-Type, If-Match, Range');
header('Access-Control-Expose-Headers: ETag, Content-Range, Content-Length');
}
header('X-Content-Type-Options: nosniff');
header('X-Frame-Options: DENY');
header('Referrer-Policy: no-referrer');
header('Strict-Transport-Security: max-age=31536000; includeSubDomains');
if (($_SERVER['REQUEST_METHOD'] ?? '') === 'OPTIONS') {
http_response_code(204);
exit;
}
$path = parse_url($_SERVER['REQUEST_URI'] ?? '/', PHP_URL_PATH) ?: '/';
$method = $_SERVER['REQUEST_METHOD'] ?? 'GET';
Router::post('/api/v1/auth/register', [AuthController::class, 'register']);
Router::post('/api/v1/auth/login', [AuthController::class, 'login']);
Router::post('/api/v1/auth/refresh', [AuthController::class, 'refresh']);
Router::get('/api/v1/auth/me', [AuthController::class, 'me']);
Router::get('/api/v1/files', [FileController::class, 'index']);
Router::post('/api/v1/files', [FileController::class, 'create']);
Router::put('/api/v1/files/{id}', [FileController::class, 'update']);
Router::delete('/api/v1/files/{id}', [FileController::class, 'delete']);
Router::get('/api/v1/files/{id}/download', [FileController::class, 'download']);
Router::get('/api/v1/plans', [PlanController::class, 'index']);
Router::get('/api/v1/plans/me', [PlanController::class, 'myPlan']);
Router::get('/api/v1/pay/orders', [PayController::class, 'listMyOrders']);
Router::post('/api/v1/pay/orders', [PayController::class, 'createOrder']);
Router::get('/api/v1/pay/orders/{order_no}', [PayController::class, 'showOrder']);
Router::post('/api/v1/pay/orders/{order_no}/checkout', [PayController::class, 'checkoutOrder']);
Router::post('/api/v1/pay/orders/{order_no}/cancel', [PayController::class, 'cancelOrder']);
Router::post('/api/v1/pay/orders/{order_no}/refund-request', [PayController::class, 'requestRefund']);
Router::post('/api/v1/pay/alipay/notify', [PayController::class, 'alipayNotify']);
Router::post('/api/v1/pay/wechat/notify', [PayController::class, 'wechatNotify']);
Router::get('/api/v1/soon-models/files/{name}', [SoonModelController::class, 'download']);
Router::get('/api/v1/soon-models', [SoonModelController::class, 'index']);
Router::get('/api/v1/settings', [SettingsController::class, 'publicSettings']);
if (str_starts_with($path, '/api/v1/')) {
$routeKey = $method . ' ' . $path;
if (str_starts_with($path, '/api/v1/auth/login') || str_starts_with($path, '/api/v1/auth/register') || str_starts_with($path, '/api/v1/auth/refresh')) {
RateLimit::check($routeKey, $method, $path, null);
} elseif (str_starts_with($path, '/api/v1/pay/') && str_contains($path, '/notify')) {
// 通知不进限速
} else {
$uid = null;
$tok = Auth::bearerFromGlobals();
if ($tok !== '') {
$payload = \Soon\Api\Core\Jwt::decode($tok);
if ($payload !== null) $uid = (int)($payload['sub'] ?? 0) ?: null;
}
RateLimit::check($routeKey, $method, $path, $uid);
}
}
$match = Router::dispatch($method, $path);
if ($match === null) {
Json::fail('not_found', '接口不存在', 404);
}
[$handler, $params] = $match;
foreach ($params as $k => $v) {
if ($k === 'id' && is_string($v) && ctype_digit($v)) {
$params[$k] = (int)$v;
}
}
if (is_array($handler)) {
[$class, $action] = $handler;
$instance = new $class();
$args = array_values($params);
$instance->$action(...$args);
} else {
($handler)($params);
}