使用RegEx匹配URL路由

时间:2013-11-07 20:18:27

标签: regex url routing routes

我正在构建一个PHP框架来完成我的课程,并且我坚持使用一些解决方案来匹配一些自定义路由和标准路由。

我的框架路线在Zend Framework 1的路线上类似。

符合

的标准路线
/module/controller/action/param/value/param2/value2/paramn/valuen

URI的一部分是可选的,/ route导致应用程序模块,索引控制器和索引操作没有参数和值。

我陷入了一些自定义路线,我用这种方式定义:

/blog/:postname/
/admin/logout/
/blog/posts/:year/:category/
/about/

这些路由必须与此示例URI请求匹配。

/blog/my-first-post/
/blog/my-first-post/referenced/facebook/
/admin/logout/
/admin/logout/session-id/246753/action
/blog/posts/2013/turism/
/blog/posts/2013/turism/page/2/

但不必匹配标准路线。自定义路由必须位于标准路由之前。 标准路线的一些例子。例子:

/
/application/
/application/index/
/application/index/index/
/blog/posts/view/id/3/
/admin/login/
/admin/login/logout (that one are the 
/admin/blog/posts/edit/id/3/
/admin/blog/posts/edit/id/3/success/false/

我发现这样做的方式是使用RegEx进行比赛,但是我试图学习RegEx一个多月而且没有完全掌握。

PS:匹配当前路线后,我必须将:变量与REQUEST_URI中的相关位置绑定。

感谢您的帮助。

2 个答案:

答案 0 :(得分:0)

虽然很有诱惑力,但在这种特殊情况下我不会使用正则表达式。即使我通常这样做。一个简单的循环和匹配就行了,除非你的课程设置了一些你必须遵循的限制。

我把一个应该完成工作并在控制台中运行的示例放在一起,只是为了表明我的意思。

function get_route($uri){
  $routes = [
    'blog#show' => 'blog/:postname',
    'admin#logout' => 'admin/logout',
    'blog#category' => 'blog/posts/:year/:category',
    'home#about' => 'about'
  ];

  $params = [];

  $uri = preg_replace('/#|\?.+/', '', $uri); // remove hash or query strings
  $uri = preg_replace('/(^\/)?(\/$)?/', '', $uri); // trim slashes
  $uri = explode('/', $uri);
  $action = null;
  foreach ($routes as $this_action => $this_route) { // loop through possible routes
    $fractions = explode('/', $this_route);
    if (sizeof($fractions) !== sizeof($uri)) continue; // did not match length of uri
    for ($i=0; $i<sizeof($uri); $i++) { // compare each part of uri to each part of route
      if (substr($fractions[$i], 0, 1) !== ':' && $fractions[$i] !== $uri[$i]) break; // not a match and not a param
      if ($i === sizeof($uri)-1) { // made it to the last fraction!
        $ii = 0;
        foreach ($fractions as $fraction) {
          if (substr($fraction, 0, 1) == ':') { // it's a param, map it!
            $params[substr($fraction,1)] = $uri[$ii];
          }
          $ii++;
        }

        return ['action'=>$this_action, 'params'=>$params];
      }
    }
  }
  return false;
}

答案 1 :(得分:0)

我可以通过此代码满足我的需求,已经过了很多测试。

public function matchCustomRoute($uri)
{
    if($uri == '')
    {
        return null;
    }

    $customRoutes = $this->getRoutes();

    $explodeUri = explode('/', $uri);
    $arrayUri = array();
    foreach($explodeUri as $uriPart)
    {
        if($uriPart == '')
        {
            continue;
        }
        $arrayUri[] = $uriPart;
    }
    $countUri = count($arrayUri);


    foreach($customRoutes as $key => $value)
    {

        $explodeRoute = explode('/',$value['route']);
        $arrayRoute = array();
        foreach($explodeRoute as $routePart)
        {
            if($routePart == '')
            {
                continue;
            }
            $arrayRoute[] = $routePart;
        }
        $countRoute = count($arrayRoute);
        if($countRoute > $countUri)
        {
            continue;
        }
        $matches = 0;

        for($i = 0 ; $i < $countRoute ; $i++)
        {
            $match = preg_match('/'.$arrayUri[$i].'/', '/'.$arrayRoute[$i].'/');
            if($match == 0)
            {
                if(substr($arrayRoute[$i], 0, 1) == ':')
                {
                    $value['params'][substr($arrayRoute[$i], 1)] = $arrayUri[$i];
                }
                else
                {
                    continue;
                }
            }
            $matches++;

        }
        if($matches == $countRoute)
        {
            return $value;
        }

    }
    return null;
}

感谢您的帮助。