PHP Regular Expression Routing URL

I am writing a class that handles the routing of my PHP web service, but I need to fix the regex and I want to know what would be the most efficient way of parsing the url.

Example URL:

  • POST / users
  • Get / users
  • GET / users & limit = 10 & offset = 0
  • GET / users / search & keyword = Richard
  • GET / users / 15 / posts / 38

What I want to create in PHP for the class is:

$router = new Router(); $router->addRoute('POST', '/users', function(){}); $router->addRoute('GET', '/users/:uid/posts/:pid', function($uid, $pid){}); $target = $router->doRouting(); 

The target variable will now contain an array with:

  • method
  • URL
  • callback method

This is what I got so far:

 class Router{ use Singleton; private $routes = []; private $routeCount = 0; public function addRoute($method, $url, $callback){ $this->routes[] = ['method' => $method, 'url' => $url, 'callback' => $callback]; $this->routeCount++; } public function doRouting(){ $reqUrl = $_SERVER['REQUEST_URI']; $reqMet = $_SERVER['REQUEST_METHOD']; for($i = 0; $i < $this->routeCount; $i++){ // Check if the url matches ... // Parse the arguments of the url ... } } } 

So I need a regular expression, which is first of all:

  • / mainAction /: ArgumentName / secondaryAction /: secondaryActionName

checks if this matches $ reqUrl (see for loop above)

  • Retrieves the arguments, so we can use them in our callback function.

What I tried myself:

 (code should be in the for loop @ doRouting function) // Extract arguments ... $this->routing[$i]['url'] = str_replace(':arg', '.+', $this->routing[$i]['url']); // Does the url matches the routing url? if(preg_match('#^' . $this->routes[$i]['url'] . '$#', $reqUrl)){ return $this->routes[$i]; } 

I really appreciate all the help, thank you very much.

+8
php regex routing
source share
1 answer

it basically works now.

 public function doRouting(){ // I used PATH_INFO instead of REQUEST_URI, because the // application may not be in the root direcory // and we dont want stuff like ?var=value $reqUrl = $_SERVER['PATH_INFO']; $reqMet = $_SERVER['REQUEST_METHOD']; foreach($this->routes as $route) { // convert urls like '/users/:uid/posts/:pid' to regular expression $pattern = "@^" . preg_replace('/\\\:[a-zA-Z0-9\_\-]+/', '([a-zA-Z0-9\-\_]+)', preg_quote($route['url'])) . "$@D"; $matches = Array(); // check if the current request matches the expression if($reqMet == $route['method'] && preg_match($pattern, $reqUrl, $matches)) { // remove the first match array_shift($matches); // call the callback with the matched positions as params return call_user_func_array($route['callback'], $matches); } } } 

PS: You do not need the attribute $routeCount

+8
source share

All Articles