I make a route like
Route::get('/{url1}', function ($url1) {
return ' url1: '.$url1;
})
->where('url1', '^(?!(string1|string2)$)');
and access url like:
- domain/abc
not found => incorrect ??
- domain/string1
not found => correct
and more, when i do with
Route::get('/{url1}/{url2}', function ($url1) {
return ' url1: '.$url1;
})
->where('url1', '^(?!(string1|string2)$)');
and access url like:
- domain/abc/abc
not found => incorrect ???
- domain/string1/abc
not found => correct
How to fix that thank
Please try with this for 1st scenario:
Route::get('/{url1}', function ($url1) {
return ' url1: '.$url1;
})->where('url1', '^!(string1|string2)$');
for 2nd scenario:
Route::get('/{url1}/{url2}', function ($url1, $url2) {
return ' url1: '.$url1 . ' url2: '.$url2;
})->where('url1', '^!(string1|string2)$');
i hope this help :)
Try this
Route::get('{url1}', function ($url1) {
return ' url1: '.$url1;
})->where('url1','^(?!string1$|string2$)([a-zA-Z0-9-]+)');
Unclean way to achieve this
Route::get('{url1}/{url2?}', function ($url1,$url2 = null) {
if ($url2 == "string1" || $url2 == "string2" || $url1 == "string1" || $url1 == "string2") {
return "false";
} else {
return "true";
}
});
One more way I have tried in by using RouteServiceProvider.php
Change your boot()
like this.
public function boot()
{
//
Route::pattern('url1', '^(?!string1$|string2$)([a-zA-Z0-9-]+)');
Route::pattern('url2', '^(?!string1$|string2$)([a-zA-Z0-9-]+)');
parent::boot();
}
After tests I think it's impossible to achieve exactly what you want. It seems when you want to exclude string1
and string2
you need to agree that also strings starting with string1
and string2
will be excluded (so for example string1aaa
).
When using such routes:
Route::get('/{url1}', function ($url1) {
return ' url1: '.$url1;
})->where('url1', '(?!string1|string2)[^\/]+');
Route::get('/{url1}/{url2}', function ($url1, $url2) {
return ' url1: '.$url1. ' # '.$url2;
})->where('url1', '(?!string1|string2)[^\/]+');
result will be:
domain/abc - found, correct
domain/string1 - not found, correct
domain/abc/abc - found, correct
domain/string1/abc - not found, correct
domain/string1aaa - not found, I believe you need to accept this
domain/string1aaa/abc - not found, I believe you need to accept this
I believe such limitation comes from Laravel and not from regex. If you need to accept also parameters starting with string1
and string2
I believe you need to do it in manual way like so:
Route::get('/{url1}', function ($url1) {
if (!preg_match('#^(?!string1$|string2$)[^\/]*$#', $url1)) {
abort(404);
}
return ' url1: '.$url1;
});
Route::get('/{url1}/{url2}', function ($url1, $url2) {
if (!preg_match('#^(?!string1$|string2$)[^\/]*$#', $url1)) {
abort(404);
}
return ' url1: '.$url1. ' # '.$url2;
});
Try this regex:
Route::get('/{url1}', function ($url1) {
return 'url: '.url1;
})->where('url1', '^(?!(string1|string2)$)(\S+)');
Rather than writing a route to match anything other than certain static strings, I find it clearer to write two routes: one route to match certain static strings, and another route to match everything else.
// route that matches forbidden static strings, optionally with a postfix slug
$router->get('/{forbidden}/{optional_path?}', function () {
return response('Not found', 404);
})->where([ 'forbidden' => '(?:string1|string2)', 'optional_path' => '.*' ]);
// route that matches anything else (order of definition matters, must be last)
// might also consider using Route::fallback(), but I prefer to leave that
// alone in case my future self changes this below and opens up a hole
$router->get('/{anything?}', function () {
return response('Found', 200);
})->where([ 'anything' => '.*' ]);
Which results in*:
domain
=> 200 Founddomain/
=> 200 Founddomain/abc
=> 200 Founddomain/string1
=> 404 Not founddomain/string1/
=> 404 Not founddomain/string1/abc
=> 404 Not founddomain/string10
=> 200 Founddomain/string10/
=> 200 Founddomain/string10/abc
=> 200 Founddomain/string2
=> 404 Not founddomain/string2/
=> 404 Not founddomain/string2/abc
=> 404 Not founddomain/string20
=> 200 Founddomain/string20/
=> 200 Founddomain/string20/abc
=> 200 FoundI find this more clear, because I don't have to think in terms of exclusions. Rather, I can think of matching exactly what I want to forbid, then letting Laravel react to everything else (fail open policy). This may not meet your design criteria, but I do believe it results in clearer code.
Also, the code is more performant. ?!
has to backtrack, which is by definition more expensive than forward matching.
I don't have a Laravel environment to hand, but I'll hazard a guess as to why your attempts didn't work. Laravel uses Symfony Router, which does not support lookarounds on slugs. IIRC, when a lookaround's detected, Symfony applies the lookaround to the entire URL, not the slug you've bound the pattern to. This messes with the developer's idea of how anchors (^, $) and greedy (*) meta characters work. This can lead to a bad experience in trying to get it to work, since the developer's operating under one assumption but the underlying libraries operating on another.
* Full disclosure, I wrote this for Lumen then mentally converted it to Laravel format. It's possible there are some translation errors. Here's the original Lumen:
$router->get('/{forbidden:(?:string1|string2)}[/{optional_path:.*}]', function () {
return response('Not found', 404);
});
$router->get('{anything:.*}', function () {
return response('Found', 200);
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With