You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

100 lines
2.8 KiB

  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
  5. * SPDX-License-Identifier: AGPL-3.0-or-later
  6. */
  7. namespace OC\Core\Command\Router;
  8. use OC\Core\Command\Base;
  9. use OC\Route\Router;
  10. use OCP\App\IAppManager;
  11. use OCP\Server;
  12. use Symfony\Component\Console\Input\InputArgument;
  13. use Symfony\Component\Console\Input\InputInterface;
  14. use Symfony\Component\Console\Input\InputOption;
  15. use Symfony\Component\Console\Output\OutputInterface;
  16. use Symfony\Component\Routing\Exception\MethodNotAllowedException;
  17. use Symfony\Component\Routing\Exception\ResourceNotFoundException;
  18. use Symfony\Component\Routing\RequestContext;
  19. class MatchRoute extends Base {
  20. public function __construct(
  21. private Router $router,
  22. ) {
  23. parent::__construct();
  24. }
  25. protected function configure(): void {
  26. parent::configure();
  27. $this
  28. ->setName('router:match')
  29. ->setDescription('Match a URL to the target route')
  30. ->addArgument(
  31. 'path',
  32. InputArgument::REQUIRED,
  33. 'Path of the request',
  34. )
  35. ->addOption(
  36. 'method',
  37. null,
  38. InputOption::VALUE_REQUIRED,
  39. 'HTTP method',
  40. 'GET',
  41. )
  42. ;
  43. }
  44. protected function execute(InputInterface $input, OutputInterface $output): int {
  45. $context = new RequestContext(method: strtoupper($input->getOption('method')));
  46. $this->router->setContext($context);
  47. $path = $input->getArgument('path');
  48. if (str_starts_with($path, '/index.php/')) {
  49. $path = substr($path, 10);
  50. }
  51. if (str_starts_with($path, '/ocs/v1.php/') || str_starts_with($path, '/ocs/v2.php/')) {
  52. $path = '/ocsapp' . substr($path, strlen('/ocs/v2.php'));
  53. }
  54. try {
  55. $route = $this->router->findMatchingRoute($path);
  56. } catch (MethodNotAllowedException) {
  57. $output->writeln('<error>Method not allowed on this path</error>');
  58. return self::FAILURE;
  59. } catch (ResourceNotFoundException) {
  60. $output->writeln('<error>Path not matched</error>');
  61. if (preg_match('/\/apps\/([^\/]+)\//', $path, $matches)) {
  62. $appManager = Server::get(IAppManager::class);
  63. if (!$appManager->isEnabledForAnyone($matches[1])) {
  64. $output->writeln('');
  65. $output->writeln('<comment>App ' . $matches[1] . ' is not enabled</comment>');
  66. }
  67. }
  68. return self::FAILURE;
  69. }
  70. $row = [
  71. 'route' => $route['_route'],
  72. 'appid' => $route['caller'][0] ?? null,
  73. 'controller' => $route['caller'][1] ?? null,
  74. 'method' => $route['caller'][2] ?? null,
  75. ];
  76. if ($output->isVerbose()) {
  77. $route = $this->router->getRouteCollection()->get($row['route']);
  78. $row['path'] = $route->getPath();
  79. if (str_starts_with($row['path'], '/ocsapp/')) {
  80. $row['path'] = '/ocs/v2.php/' . substr($row['path'], strlen('/ocsapp/'));
  81. }
  82. $row['requirements'] = json_encode($route->getRequirements());
  83. }
  84. $this->writeTableInOutputFormat($input, $output, [$row]);
  85. return self::SUCCESS;
  86. }
  87. }