SubscribeController.php 3.9 KB

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