Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Laravel route to check for multiple string

I want redirects (301) for some routes which contains the following -

page=1 (query string) or index.php or ?&(query string)

I have added the route as -

Route::get('/{any_url}', 'UsersController@processRedirect')->where('any_url', '(.*)index\.php(.*)|(.*)page=1(.*)|(.*)|?&(.*)');

When I am checing in https://regex101.com/ it is working but in my app iit iis not working.

What could be the issue?

I have done this via MiddleWare but I do not want to check for all urls.

Is there any other way to achieve this?

like image 672
Sougata Bose Avatar asked Apr 21 '20 07:04

Sougata Bose


2 Answers

So the trick is not to do this in the route but instead make a global catch all route that catches all routes and then you can do any handling of path or query string in your controller. This keeps your routes clean and easy to use and allows more power over processing of query strings and the path or base url. Be sure to remove the routes you want to handle with this catch all route.

routes/web.php

//make this last route to catch
Route::any('/{any}', "ProcessRequestController@handler")->where("any", ".*");

App/Http/Controllers/ProcessController.php

namespace App\Http\Controllers;

use Illuminate\Http\Request;


class ProcessRequestController extends Controller{

    public function handler(Request $request){
        //from here you can now access each section of the route a little more conviently.
        $request->path();
        if($request->has('page')){

        }
    }
}
like image 78
jgetner Avatar answered Oct 10 '22 08:10

jgetner


Middleware is probably the better solution.

Catch-all routes work, but there are unintended consequences. You will have to manually handle 404 errors. You may also notice decreased performance depending on how your routes are setup.

Unlike catch-all routes, middleware can run before any routes are matched. Middleware can also be attached to a group of routes or a specific route. There are other middleware classes that are running by default, such as Authentication and CORS.

Here are the latest docs for middleware. Middleware hasn't changed much since Laravel 5, but the latest docs just explain the concept better. https://laravel.com/docs/7.x/middleware


Here is how you could use middleware to solve your problem.

Create a middleware class.

php artisan make:middleware My301Filter

If you want the middleware to run on all requests, register the class in app/http/kernel.php

protected $middleware = [
    // ...
    \App\Http\Middleware\My301Filter::class
];

Then you can parse your route using any way you want. Use logic to determine if a 301 should be called or if the app should continue. The $next closure will go to the next middleware or route.

I chose to write something like this in my middleware class. However, this code is not perfect and you will probably have to change it to fit your needs.

<?php

namespace App\Http\Middleware;

use Closure;

class My301Filter
{

    // ...

    public function handle($request, Closure $next)
    {
        $needles = ["page=1", "index.php", "?&"];

        foreach ($needles as $needle) {
            if (strpos($request->getRequestUri(), $needle) !== false) {
                return redirect('/some/route', 301);
            }
        }

        return $next($request);
    }
}
like image 1
wizardzeb Avatar answered Oct 10 '22 09:10

wizardzeb