diff --git a/README.md b/README.md index d2558a6..cc74051 100644 --- a/README.md +++ b/README.md @@ -25,10 +25,6 @@ Add the latest version pf Simple PHP Router to your ```composer.json``` - CSRF Protection - Optional/required parameters -### Known issues - -- Posting invalid/unsupported request-type throws 404 instead of "method not allowed" exception, unless defined within a group. - ## Initialising the router In your ```index.php``` require your ```routes.php``` and call the ```routeRequest()``` method when all your custom routes has been loaded. This will trigger and do the actual routing of the requests. @@ -197,7 +193,7 @@ The router can be easily extended to customize your needs. ## The MIT License (MIT) -Copyright (c) 2015 Simon Sessingø / simple-php-router +Copyright (c) 2015 Simon Sessing� / simple-php-router Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Pecee/SimpleRouter/RouterBase.php b/src/Pecee/SimpleRouter/RouterBase.php index b5a69e3..b5cc3d0 100644 --- a/src/Pecee/SimpleRouter/RouterBase.php +++ b/src/Pecee/SimpleRouter/RouterBase.php @@ -94,16 +94,32 @@ class RouterBase { return strcmp($b->getUrl(), $a->getUrl()); }); + $routeNotAllowed = false; + + /* @var $route RouterEntry */ foreach($this->controllerUrlMap as $route) { $routeMatch = $route->matchRoute($this->request); + if($routeMatch && !($routeMatch instanceof RouterGroup)) { + + if(count($route->getRequestMethods()) && !in_array($this->request->getMethod(), $route->getRequestMethods())) { + $routeNotAllowed = true; + continue; + } + + $routeNotAllowed = false; + $this->loadedRoute = $routeMatch; $routeMatch->renderRoute($this->request); break; } } + if($routeNotAllowed) { + throw new RouterException('Route or method not allowed', 403); + } + if(!$this->loadedRoute) { throw new RouterException(sprintf('Route not found: %s', $this->request->getUri()), 404); } diff --git a/src/Pecee/SimpleRouter/RouterEntry.php b/src/Pecee/SimpleRouter/RouterEntry.php index 32085aa..03a88fe 100644 --- a/src/Pecee/SimpleRouter/RouterEntry.php +++ b/src/Pecee/SimpleRouter/RouterEntry.php @@ -27,6 +27,7 @@ abstract class RouterEntry { public function __construct() { $this->settings = array(); + $this->settings['requestMethods'] = array(); $this->parameters = array(); $this->parametersRegex = array(); } @@ -193,8 +194,10 @@ abstract class RouterEntry { * @param array $settings * @return self */ - public function addSettings(array $settings) { - $this->settings = array_merge($this->settings, $settings); + public function addSettings(array $settings = null) { + if(is_array($settings)) { + $this->settings = array_merge($this->settings, $settings); + } return $this; } @@ -280,6 +283,30 @@ abstract class RouterEntry { return null; } + /** + * Set allowed request methods + * + * @param array $methods + * @return self $this + */ + public function setRequestMethods(array $methods) { + $this->settings['requestMethods'] = $methods; + return $this; + } + + /** + * Get allowed requeset methods + * + * @return array + */ + public function getRequestMethods() { + if(!isset($this->settings['requestMethods']) || isset($this->settings['requestMethods']) && !is_array($this->settings['requestMethods'])) { + $value = isset($this->settings['requestMethods']) ? $this->settings['requestMethods'] : null; + return array($value); + } + return $this->settings['requestMethods']; + } + abstract function matchRoute(Request $request); } \ No newline at end of file diff --git a/src/Pecee/SimpleRouter/RouterGroup.php b/src/Pecee/SimpleRouter/RouterGroup.php index 49de9b5..1537a71 100644 --- a/src/Pecee/SimpleRouter/RouterGroup.php +++ b/src/Pecee/SimpleRouter/RouterGroup.php @@ -19,9 +19,9 @@ class RouterGroup extends RouterEntry { if($this->method) { if(is_array($this->method)) { - $hasAccess = (in_array($request->getMethod(), $this->method)); + $hasAccess = (in_array($request->getMethod(), $this->getRequestMethods())); } else { - $hasAccess = strtolower($this->method) == strtolower($request->getMethod()); + $hasAccess = strtolower($this->getRequestMethods()) == strtolower($request->getMethod()); } } diff --git a/src/Pecee/SimpleRouter/RouterRoute.php b/src/Pecee/SimpleRouter/RouterRoute.php index a5d012a..029c242 100644 --- a/src/Pecee/SimpleRouter/RouterRoute.php +++ b/src/Pecee/SimpleRouter/RouterRoute.php @@ -9,7 +9,6 @@ class RouterRoute extends RouterEntry { const PARAMETERS_REGEX_MATCH = '{([A-Za-z\-\_]*?)}'; protected $url; - protected $requestTypes; public function __construct($url, $callback) { parent::__construct(); @@ -17,7 +16,6 @@ class RouterRoute extends RouterEntry { $this->setCallback($callback); $this->settings['aliases'] = array(); - $this->requestTypes = array(); } protected function parseParameters($url, $multiple = false, $regex = self::PARAMETERS_REGEX_MATCH) { @@ -39,71 +37,69 @@ class RouterRoute extends RouterEntry { public function matchRoute(Request $request) { // Check if request method is allowed - if(count($this->requestTypes) === 0 || in_array($request->getMethod(), $this->requestTypes)) { - $url = parse_url($request->getUri()); - $url = $url['path']; + $url = parse_url($request->getUri()); + $url = $url['path']; - $route = $this->url; + $route = $this->url; - $routeMatch = preg_replace('/'.self::PARAMETERS_REGEX_MATCH.'/is', '', $route); + $routeMatch = preg_replace('/'.self::PARAMETERS_REGEX_MATCH.'/is', '', $route); - // Check if url parameter count matches - if(stripos($url, $routeMatch) === 0) { + // Check if url parameter count matches + if(stripos($url, $routeMatch) === 0) { - $matches = true; + $matches = true; - if($this->regexMatch) { - $parameters = $this->parseParameters($url, true, $this->regexMatch); - - // If regex doesn't match, make sure to return an array - if(!is_array($parameters)) { - $parameters = array(); - } - - } else { - - $url = explode('/', $url); - $route = explode('/', $route); + if($this->regexMatch) { + $parameters = $this->parseParameters($url, true, $this->regexMatch); + // If regex doesn't match, make sure to return an array + if(!is_array($parameters)) { $parameters = array(); + } - // Check if url matches - foreach ($route as $i => $path) { - $parameter = $this->parseParameters($path, false); + } else { - // Check if parameter of path matches, otherwise quit.. - if (is_null($parameter) && strtolower($path) != strtolower($url[$i])) { - $matches = false; - break; - } + $url = explode('/', $url); + $route = explode('/', $route); - // Save parameter if we have one - if ($parameter) { - $parameterValue = $url[$i]; - $regex = (isset($this->parametersRegex[$parameter]) ? $this->parametersRegex[$parameter] : null); + $parameters = array(); - if ($regex !== null) { - // Use the regular expression rule provided to filter the value - $matches = array(); - preg_match('/' . $regex . '/is', $url[$i], $matches); + // Check if url matches + foreach ($route as $i => $path) { + $parameter = $this->parseParameters($path, false); - if (count($matches)) { - $parameterValue = $matches[0]; - } + // Check if parameter of path matches, otherwise quit.. + if (is_null($parameter) && strtolower($path) != strtolower($url[$i])) { + $matches = false; + break; + } + + // Save parameter if we have one + if ($parameter) { + $parameterValue = $url[$i]; + $regex = (isset($this->parametersRegex[$parameter]) ? $this->parametersRegex[$parameter] : null); + + if ($regex !== null) { + // Use the regular expression rule provided to filter the value + $matches = array(); + preg_match('/' . $regex . '/is', $url[$i], $matches); + + if (count($matches)) { + $parameterValue = $matches[0]; } - - // Add parameter value - $parameters[$parameter] = $parameterValue; } + + // Add parameter value + $parameters[$parameter] = $parameterValue; } } + } - // This route matches - if($matches) { - $this->parameters = $parameters; - return $this; - } + // This route matches + if($matches) { + $this->parameters = $parameters; + return $this; } } @@ -136,29 +132,6 @@ class RouterRoute extends RouterEntry { return $this; } - /** - * Add request type - * - * @param $type - * @return self - * @throws RouterException - */ - public function addRequestType($type) { - if(!in_array($type, self::$allowedRequestTypes)) { - throw new RouterException('Invalid request method: ' . $type); - } - - $this->requestTypes[] = $type; - return $this; - } - - /** - * @return mixed - */ - public function getRequestTypes() { - return $this->requestTypes; - } - /** * Get alias for the url which can be used when getting the url route. * @return string diff --git a/src/Pecee/SimpleRouter/SimpleRouter.php b/src/Pecee/SimpleRouter/SimpleRouter.php index 8820c17..99b050a 100644 --- a/src/Pecee/SimpleRouter/SimpleRouter.php +++ b/src/Pecee/SimpleRouter/SimpleRouter.php @@ -20,7 +20,7 @@ class SimpleRouter { public static function get($url, $callback, array $settings = null) { $route = new RouterRoute($url, $callback); $route->addSettings($settings); - $route->addRequestType(RouterRoute::REQUEST_TYPE_GET); + $route->setRequestMethods(array(RouterRoute::REQUEST_TYPE_GET)); $router = RouterBase::getInstance(); $router->addRoute($route); @@ -31,7 +31,7 @@ class SimpleRouter { public static function post($url, $callback, array $settings = null) { $route = new RouterRoute($url, $callback); $route->addSettings($settings); - $route->addRequestType(RouterRoute::REQUEST_TYPE_POST); + $route->setRequestMethods(array(RouterRoute::REQUEST_TYPE_POST)); $router = RouterBase::getInstance(); $router->addRoute($route); @@ -42,7 +42,7 @@ class SimpleRouter { public static function put($url, $callback, array $settings = null) { $route = new RouterRoute($url, $callback); $route->addSettings($settings); - $route->addRequestType(RouterRoute::REQUEST_TYPE_PUT); + $route->setRequestMethods(array(RouterRoute::REQUEST_TYPE_PUT)); $router = RouterBase::getInstance(); $router->addRoute($route); @@ -53,7 +53,7 @@ class SimpleRouter { public static function delete($url, $callback, array $settings = null) { $route = new RouterRoute($url, $callback); $route->addSettings($settings); - $route->addRequestType(RouterRoute::REQUEST_TYPE_DELETE); + $route->setRequestMethods(array(RouterRoute::REQUEST_TYPE_DELETE)); $router = RouterBase::getInstance(); $router->addRoute($route); @@ -75,12 +75,10 @@ class SimpleRouter { return $group; } - public static function match(array $requestTypes, $url, $callback, array $settings = null) { + public static function match(array $requestMethods, $url, $callback, array $settings = null) { $route = new RouterRoute($url, $callback); + $route->setRequestMethods($requestMethods); $route->addSettings($settings); - foreach($requestTypes as $requestType) { - $route->addRequestType($requestType); - } $router = RouterBase::getInstance(); $router->addRoute($route);