简体   繁体   中英

regex matching url

In PHP, the klein routing will match as many routes as it can. 2 routes I have set up are conflicting. They are:

$route1: '/websites/[i:websiteId]/users/[i:id]?'

and

$route2: '/websites/[i:websiteId]/users/[a:filename].[json|csv:extension]?'

This is the URL I'm trying to match, which I think should match the first and not the second, is:

/api/v1-test/websites/100/users/4

The regex produced for these two are:

$regex1: `^/api(?:/(v1|v1-test))/websites(?:/(?P<websiteId>[0-9]++))/users(?:/(?P<id>[0-9]++))?$`

$regex2: `^/api(?:/(v1|v1-test))/websites(?:/(?P<websiteId>[0-9]++))/users(?:/(?P<filename>[0-9A-Za-z]++))(?:\.(?P<extension>json|csv))?$`

I mean for it not to match if there is no '.csv' or '.json'. The problem is that it is matching both routes. For the second, the resulting filename is '4' and the extension is blank.

Sending /api/v1-test/websites/100/users/users.csv works correctly and only matches the second route.

I only have control over the route, not the regex or the matching. Thanks.

This bit here

(?:\.(?P<extension>json|csv))?

at the end of your second regex causes it to match whether or not there's a filename due to the ? at the very end. Question marks mean 0 or 1 of the previous expression . Get rid of that and, at the least, strings will only match this regex when they have the extension.

To make this change, just remove the question mark from your second route, like so:

$route2: '/websites/[i:websiteId]/users/[a:filename].[json|csv:extension]'

The problem is that the match_type is defined really... weirdly:

$match_types = array(
            'i' => '[0-9]++',
            'a' => '[0-9A-Za-z]++',
[...]

As such, you can't really capture a sequence corresponding to [a-zA-Z] only... The only option I see would be to use 3 routes:

$route1: '/websites/[i:websiteId]/users/[i:id]?'
$route2: '/websites/[i:websiteId]/users/[a:filename]'
$route3: '/websites/[i:websiteId]/users/[a:filename].[json|csv:extension]'

And to assign the same actions for routes 2 and 3. Then you would have this:

  • /api/v1-test/websites/100/users/ is matched by 1
  • /api/v1-test/websites/100/users/4 is matched by 1
  • /api/v1-test/websites/100/users/test is matched by 2
  • /api/v1-test/websites/100/users/test.csv is matched by 3

Which seems like the behavior you wanted.

Abother (easier) solution would be to take advantage of this bit of the documentation:

Routes automatically match the entire request URI.
If you need to match only a part of the request URI
or use a custom regular expression, use the @ operator.

You can then define your routes like this:

$route1: '@/websites/[0-9]+/users/[0-9]*$'
$route1: '@/websites/[0-9]+/users/[a-zA-Z]+(\.[a-zA-Z]+)?$'

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM