SubscribeController.php 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. <?php
  2. namespace App\Http\Controllers\User;
  3. use App\Http\Controllers\Controller;
  4. use App\Models\UserSubscribe;
  5. use App\Models\UserSubscribeLog;
  6. use App\Services\ProxyService;
  7. use App\Services\UserService;
  8. use App\Utils\IP;
  9. use Illuminate\Contracts\View\View;
  10. use Illuminate\Http\RedirectResponse;
  11. use Illuminate\Http\Request;
  12. class SubscribeController extends Controller
  13. {
  14. private static ?int $subType = null;
  15. private ?string $target;
  16. private ProxyService $proxyService;
  17. public function __construct(ProxyService $proxyService)
  18. {
  19. $this->proxyService = $proxyService;
  20. }
  21. public function index(Request $request, string $code): RedirectResponse|View
  22. {
  23. // 检查订阅码格式
  24. if (! preg_match('/^[0-9A-Za-z]+$/', $code)) {
  25. return redirect()->route('login');
  26. }
  27. // 检查订阅码是否有效
  28. $subscribe = UserSubscribe::whereCode($code)->firstOrFail();
  29. $user = $subscribe->user;
  30. $userService = new UserService($user);
  31. return view('user.subscribe', [
  32. 'remainDays' => $userService->getRemainingDays(),
  33. 'unusedPercent' => $userService->getUnusedTrafficPercent(),
  34. 'user' => $user,
  35. 'subscribe' => $subscribe,
  36. ]);
  37. }
  38. public function getSubscribeByCode(Request $request, string $code): string
  39. { // 通过订阅码获取订阅信息
  40. if (is_numeric($request->input('type'))) {
  41. self::$subType = (int) $request->input('type');
  42. }
  43. $this->target = strtolower($request->userAgent());
  44. if ($request->has('target')) {
  45. $this->target = strtolower($request->input('target')).'/'.$this->target;
  46. }
  47. // 检查订阅码格式
  48. if (! preg_match('/^[0-9A-Za-z]+$/', $code)) {
  49. return $this->failed(trans('errors.subscribe.unknown'));
  50. }
  51. // 检查订阅是否存在
  52. $subscribe = UserSubscribe::whereCode($code)->first();
  53. if (! $subscribe) {
  54. return $this->failed(trans('errors.subscribe.unknown'));
  55. }
  56. // 检查订阅状态
  57. if ($subscribe->status !== 1) {
  58. return $this->failed(trans('errors.subscribe.sub_banned'));
  59. }
  60. // 检查用户是否有效
  61. $user = $subscribe->user;
  62. if (! $user) {
  63. return $this->failed(trans('errors.subscribe.user'));
  64. }
  65. // 检查用户状态
  66. if ($user->status === -1) {
  67. return $this->failed(trans('errors.subscribe.user_disabled'));
  68. }
  69. if ($user->enable !== 1) {
  70. if ($user->ban_time) {
  71. return $this->failed(trans('errors.subscribe.banned_until', ['time' => $user->ban_time]));
  72. }
  73. if ($user->unused_traffic <= 0) {
  74. return $this->failed(trans('errors.subscribe.out'));
  75. }
  76. if ($user->expiration_date < now()->toDateString()) {
  77. return $this->failed(trans('errors.subscribe.expired'));
  78. }
  79. return $this->failed(trans('errors.subscribe.question'));
  80. }
  81. // 设置用户并更新订阅信息
  82. $this->proxyService->setUser($user);
  83. $subscribe->increment('times'); // 更新访问次数
  84. // 记录订阅日志
  85. $this->subscribeLog($subscribe->id, IP::getClientIp(), json_encode([
  86. 'Host' => $request->getHost(),
  87. 'User-Agent' => $request->userAgent(),
  88. ], JSON_THROW_ON_ERROR));
  89. // 返回订阅内容
  90. return $this->proxyService->buildClientConfig($this->target, self::$subType);
  91. }
  92. private function failed(string $text): string
  93. { // 抛出错误的节点信息,用于兼容防止客户端订阅失败
  94. $this->proxyService->failedProxyReturn($text, self::$subType ?? 0);
  95. // 返回错误配置而不是空字符串,以确保客户端收到有效内容
  96. return $this->proxyService->buildClientConfig($this->target, self::$subType);
  97. }
  98. private function subscribeLog(int $subscribeId, ?string $ip, string $headers): void
  99. { // 写入订阅访问日志
  100. UserSubscribeLog::create([
  101. 'user_subscribe_id' => $subscribeId,
  102. 'request_ip' => $ip,
  103. 'request_time' => now(),
  104. 'request_header' => $headers,
  105. ]);
  106. }
  107. }