【问题标题】:Laravel Route variable limited to 17 charactersLaravel Route 变量限制为 17 个字符
【发布时间】:2015-02-26 05:06:06
【问题描述】:

在 Laravel 中,我试图实现在 URL 中包含可变数量的类别的能力,然后是 slug。例如:

www.trashaccount.com/category1/category2/slug

我在 Laravel 中使用路由模式来识别类别

Route::pattern('cat', '([-a-zA-Z0-9]+\/?)*');

演示/测试路线如下所示:

Route::get('test/{cat}/{slug}', function($cat, $slug) {
    $categories = explode('/', $cat);
    $i = 1;
    foreach($categories as $category)  {
        echo "category " . $i . ": " . $category . "<br>";
        $i++;
    }
    echo "slug: " . $slug . "<br>";
});

这可以在 www.trashaccount.com/test/{cat}/.../{slug} 进行测试

此代码成功提取了任意字符长度的可变数量的类别;例如这有效:

http://www.trashaccount.com/test/cat1/cat2/cat3/abcdefghijklmnopqrstuvwxyzabcdevg/my-slug

中断的地方在于最后一个元素 {slug} 的字符数。出于某种原因,超过 17 个字符的任何内容都会引发 NotFoundHttpException。所以,这不起作用:

http://www.trashaccount.com/test/cat1/abcdefghijklmnopqr

但如果你只是删除“r”(18h 字符),它就可以工作。

为了澄清(因为我的帖子在另一个论坛上被误解了),您可以输入任意数量的类别,它们可以是任意长度(尊重 HTTP 限制),它们将被接受和处理。我标记为 {slug} 的最后一个元素不能超过 17 个字符而不会引发 NotFoundHttpException 错误。

有人知道我做错了什么吗?

谢谢!

【问题讨论】:

    标签: php regex laravel routes


    【解决方案1】:

    说实话,我觉得这种行为很奇怪。

    我无事可做,所以我开始研究 Laravel 的内部代码,看看有什么问题,我得出的结论是,如果 路由的最后部分 长于 17 个字符 那么它就失败了。

    一切都发生在Illuminate\Routing\Matching\UriValidator->matches() line 25

    这里有一些使用/test/first-category/testingslug 的调试打印:

    preg_match("#^/assets/(?P(?!\.\.)(.*))$#s", "/test/first-category/testingslug");
    
    // successful
    preg_match("#^/test/(?P([-a-zA-Z0-9]+\/?)*)/(?P[^/]++)$#s", "/test/first-category/testingslug");
    
    category 1: first-category
    slug: testingslug
    

    在我尝试使用超过 17 个字符的 slug 之前,一切都很好。

    我尝试使用/test/first-category/testingslugmuchlonger

    preg_match("#^/assets/(?P(?!\.\.)(.*))$#s", "/test/first-category/testingslugmuchlonger");   
    
    // fails
    preg_match("#^/test/(?P([-a-zA-Z0-9]+\/?)*)/(?P[^/]++)$#s", "/test/first-category/testingslugmuchlonger");
    
    preg_match("#^/assets/(?P(?!\.\.)(.*))$#s", "/test/first-category/testingslugmuchlonger");  
    
    // fails again
    preg_match("#^/test/(?P([-a-zA-Z0-9]+\/?)*)/(?P[^/]++)$#s", "/test/first-category/testingslugmuchlonger");
    

    之所以重复,是因为框架会检查是否有替代路由,在 Illuminate/Routing/RouteCollection.php->match() line 141 中是否存在具有相同路由但方法不同的替代路由。

    现在我尝试在单独的文件中调试这两个preg_matc()

    $works = null;
    preg_match("#^/test/(([-a-zA-Z0-9]+\/?)*)/([^/]++)$#s", "/test/first-category/testingslug", $works);
    var_dump($works);
    
    $fails = null;
    preg_match("#^/test/(([-a-zA-Z0-9]+\/?)*)/([^/]++)$#s", "/test/first-category/testingslugmuchlonger", $fails);
    var_dump($fails);
    

    这就是他们返回的:

    array(4) {
      [0]=>
      string(32) "/test/first-category/testingslug"
      [1]=>
      string(14) "first-category"
      [2]=>
      string(14) "first-category"
      [3]=>
      string(11) "testingslug"
    }
    
    array(0) {
    }
    

    我认为 preg_match 一定有什么问题(?)。

    【讨论】:

      【解决方案2】:

      感谢@GiamPy 对此进行调查以及您在回答中付出的努力,非常感谢。

      我又用头撞墙了几个小时,然后开始使用正则表达式模式。我无法摆脱我正在匹配类别的最终正斜杠的想法,但还将该正斜杠定义为 Route 中 {cat} 和 {slug} 之间的分隔符。这种怀疑将我引向positive lookaheads,以从结果中删除最后的正斜杠和slug。

      老实说,我不确定这是否是问题所在,因为我最终求助于复活节彩蛋正则表达式,直到找到可行的方法:

      Route::pattern('cat2', '.+(?=\/.+)');
      

      此模式匹配任何字符 (.) 一次或多次 (),后跟 (?=) 正斜杠 (/),任何字符 (.) 一次或多次 (),但不包括它在搜索中(积极前瞻的功能?=)。

      这可以在 www.trashaccount.com/test2/cat1/cat2/veryverylongslugthatshouldbreak 进行验证。

      如果有人想纠正我或对此进行扩展,将不胜感激。

      【讨论】:

        【解决方案3】:

        改用这个模式:

        Route::pattern('cat', '[-a-zA-Z0-9]+(\/[-a-zA-Z0-9]+)*');
        

        该模式匹配表达式的方式与 ([-a-zA-Z0-9]+\/?)* 相同,但您可以确保 {cat} 永远不会以正斜杠结尾。 我认为{cat}{slug} 之间的/cat 模式中匹配when -- 我不知道为什么 -- {slug}超过 17 个字符。正如@GiamPy 所说,这可能是preg_match 函数中的一个错误

        【讨论】:

          【解决方案4】:

          将此行添加到RouteServiceProvider.php上的启动功能

          Route::pattern(':route_variable', '[a-zA-Z-]{0,255}+');
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2018-02-10
            • 1970-01-01
            • 2016-04-08
            • 2015-09-15
            • 2018-01-13
            • 2020-12-13
            • 2019-09-29
            相关资源
            最近更新 更多