|
13 | 13 |
|
14 | 14 | use Closure;
|
15 | 15 | use CodeIgniter\Exceptions\PageNotFoundException;
|
| 16 | +use CodeIgniter\HTTP\Exceptions\BadRequestException; |
16 | 17 | use CodeIgniter\HTTP\Exceptions\RedirectException;
|
17 | 18 | use CodeIgniter\HTTP\Request;
|
18 | 19 | use CodeIgniter\HTTP\ResponseInterface;
|
@@ -120,11 +121,23 @@ class Router implements RouterInterface
|
120 | 121 |
|
121 | 122 | protected ?AutoRouterInterface $autoRouter = null;
|
122 | 123 |
|
| 124 | + /** |
| 125 | + * Permitted URI chars |
| 126 | + * |
| 127 | + * The default value is `''` (do not check) for backward compatibility. |
| 128 | + */ |
| 129 | + protected string $permittedURIChars = ''; |
| 130 | + |
123 | 131 | /**
|
124 | 132 | * Stores a reference to the RouteCollection object.
|
125 | 133 | */
|
126 | 134 | public function __construct(RouteCollectionInterface $routes, ?Request $request = null)
|
127 | 135 | {
|
| 136 | + $config = config(App::class); |
| 137 | + if (isset($config->permittedURIChars)) { |
| 138 | + $this->permittedURIChars = $config->permittedURIChars; |
| 139 | + } |
| 140 | + |
128 | 141 | $this->collection = $routes;
|
129 | 142 |
|
130 | 143 | // These are only for auto-routing
|
@@ -179,6 +192,8 @@ public function handle(?string $uri = null)
|
179 | 192 | // Decode URL-encoded string
|
180 | 193 | $uri = urldecode($uri);
|
181 | 194 |
|
| 195 | + $this->checkDisallowedChars($uri); |
| 196 | + |
182 | 197 | // Restart filterInfo
|
183 | 198 | $this->filterInfo = null;
|
184 | 199 | $this->filtersInfo = [];
|
@@ -433,7 +448,7 @@ protected function checkRoutes(string $uri): bool
|
433 | 448 | }, is_array($handler) ? key($handler) : $handler);
|
434 | 449 |
|
435 | 450 | throw new RedirectException(
|
436 |
| - preg_replace('#^' . $routeKey . '$#u', $redirectTo, $uri), |
| 451 | + preg_replace('#\A' . $routeKey . '\z#u', $redirectTo, $uri), |
437 | 452 | $this->collection->getRedirectCode($routeKey)
|
438 | 453 | );
|
439 | 454 | }
|
@@ -487,7 +502,7 @@ protected function checkRoutes(string $uri): bool
|
487 | 502 | }
|
488 | 503 |
|
489 | 504 | // Using back-references
|
490 |
| - $handler = preg_replace('#^' . $routeKey . '$#u', $handler, $uri); |
| 505 | + $handler = preg_replace('#\A' . $routeKey . '\z#u', $handler, $uri); |
491 | 506 | }
|
492 | 507 |
|
493 | 508 | $this->setRequest(explode('/', $handler));
|
@@ -676,4 +691,20 @@ protected function setMatchedRoute(string $route, $handler): void
|
676 | 691 |
|
677 | 692 | $this->matchedRouteOptions = $this->collection->getRoutesOptions($route);
|
678 | 693 | }
|
| 694 | + |
| 695 | + /** |
| 696 | + * Checks disallowed characters |
| 697 | + */ |
| 698 | + private function checkDisallowedChars(string $uri): void |
| 699 | + { |
| 700 | + foreach (explode('/', $uri) as $segment) { |
| 701 | + if ($segment !== '' && $this->permittedURIChars !== '' |
| 702 | + && preg_match('/\A[' . $this->permittedURIChars . ']+\z/iu', $segment) !== 1 |
| 703 | + ) { |
| 704 | + throw new BadRequestException( |
| 705 | + 'The URI you submitted has disallowed characters: "' . $segment . '"' |
| 706 | + ); |
| 707 | + } |
| 708 | + } |
| 709 | + } |
679 | 710 | }
|
0 commit comments