【问题标题】:Using RegEx to match URL routes使用 RegEx 匹配 URL 路由
【发布时间】:2013-11-07 20:18:27
【问题描述】:

我正在构建一个 PHP 框架来结束我的课程,我一直坚持一个解决方案来匹配一些自定义路由和标准路由。

我的框架的路由与 Zend Framework 1 的路由相似。

匹配标准路线

/module/controller/action/param/value/param2/value2/paramn/valuen

URI部分是可选的,/路由指向应用模块、索引控制器和索引动作,没有参数和值。

我陷入了一些自定义路线,我是这样定义的:

/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:匹配当前路由后,我必须将 :variable 绑定到 REQUEST_URI 中的相关位置。

感谢您的帮助。

【问题讨论】:

    标签: regex url routing routes


    【解决方案1】:

    虽然很诱人,但在这种特殊情况下,我不会使用正则表达式。尽管我通常是这样走的。一个简单的循环和匹配就可以了,除非你的课程设置了一些你必须遵守的限制。

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

    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;
    }
    

    【讨论】:

    • 感谢您的回答,但是.. OMG,这几乎与我在寻找 RegEx 之前尝试这样做的方式相同..
    【解决方案2】:

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

    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;
    }
    

    感谢您的帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-07-13
      • 1970-01-01
      • 2014-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-01-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多