Laravel route variable is limited to 17 characters

In Laravel, I am trying to implement the ability to have a variable number of categories in the url followed by a bullet. For example:

www.trashaccount.com/category1/category2/slug

I am using Laravel route pattern to define categories

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

      

and the demo / test route looks like this:

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

      

This can be checked at the address: www.trashaccount.com/test/ {cat }/.../ {slug}

This code successfully pulls a variable number of categories of any character length; for example this works:

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

Where it breaks down is the number of characters of the finite element, {slug}. For some reason, nothing more than 17 characters throws a NotFoundHttpException. So this doesn't work:

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

But if you just remove the "r" (character 18h) it works.

To clarify (since my post was misinterpreted on another forum), you can enter as many categories as you like, they can be of any length (subject to HTTP restrictions) and they will be accepted and processed. The last element, which I marked as {slug}, cannot be longer than 17 characters without throwing a NotFoundHttpException error.

Does anyone know what I am doing wrong?

Thank!

+3


source to share


3 answers


I find this behavior rather odd to be honest.

I had nothing to do, so I started to study the inner Laravel code to figure out what was wrong, and I came to the conclusion that if the last part of the route is longer than 17 characters, it will not work.

Everything happens in Illuminate \ Routing \ Matching \ UriValidator-> matches () line 25 .

Here's some debug prints using /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

      

It's ok until I try to use a slug longer than 17 characters.

I am trying to use /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");

      

This is repeated because the framework checks if there are alternative routes with the same routing but different methods in Illuminate / Routing / RouteCollection.php-> match () line 141 .

Now I tried to debug these two preg_matc()

in a separate file:

$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);

      

And this is what they return:

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) {
}

      

In my opinion, there must be something wrong (?) With preg_match.

+2


source


Thanks @GiamPy for looking into this and the effort you put forth in your answer, it is greatly appreciated.

I banged my head against the wall for a few more hours and started playing with the regex pattern. I could not figure out that I agree with the final list of category lists, but also specify that forwardlash is the delimiter between {cat} and {slug} in the Route. This suspicion sent me to positive views to remove the final forward hatch and punch the result.

To be completely honest, I'm not sure if this was the problem or not, as I ended up resorting to the Easter regex summing up until I found something that works:

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

      



This pattern matches any character (.) One or more times (), followed by (? =) A forwardlash (/), any character (.) One or more times (), not including it in the lookup (functionality positive lookahead? =).

You can check this at www.trashaccount.com/test2/cat1/cat2/veryverylongslugthatshouldbreak.

If anyone wants to fix me, or expand on this, we would be very grateful.

0


source


Use this template instead:

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

      

The pattern matches expressions in the same way as ([-a-zA-Z0-9]+\/?)*

, except that you make sure that {cat} is never slash-terminated. I think /

between {cat}

and is {slug}

matched in cat

pattern when - and I don't know why - {slug}

longer than 17 characters. As @GiamPy said this is probably a bug in the function preg_match

.

0


source







All Articles