I'm building a small app that needs to redirect old URLs to the newer and cleaner URLs that Lumen provides.
Basically I want to route and possibly giving it a 301 redirect.
/something.php?id=1 -> /somethings/1
The problem is this code doesn't seem to work:
$app->get('/something.php?id={id}', function ($id) {
redirect()->route('somethings', ['id' => $id]);
});
This route is where I wanted to redirect this to:
$app->get('somethings/{id}', [
'as' => 'somethings', 'uses' => 'SomeController#show'
]);
This is supposed to work, but I can't seem to manage it.
I would also go the .htaccess route if that's better.
Adding this snippet into the public/.htaccess file didn't seem to work either.
RewriteRule something\.php?id=(.+)$ somethings/$1 [R=301,L]
I'm not very handy with rewrites, so there could be something wrong that I'm totally missing here.
Anyone wanna point me in the right direction?
You could do it in Lumen itself, but it'll be faster if you use .htaccess:
RewriteCond %{QUERY_STRING} ^id=(\d+)$
RewriteRule ^something.php$ /somethings/%1 [R=301,L]
The above should be placed just below RewriteEngine On. In addition, you should know that a condition only applies to the rule that follows. So, If you want to check another URI and query string, you'll need to repeat the above for that.
If you'd prefer to use Lumen, you can add this to your routing config:
$app->get('something.php', function() use ($app) {
$request = $app['request'];
$param = 'id';
if ($request->has($param)) {
if (preg_match('/[0-9]+/', $request->input($param))) {
return redirect()->route('somethings', ['id' => $request->input($param)]);
}
}
});
If you only want to get the value of id from the old URL, you can resolve request service inside the route and get the value of id from there. Like this :
$app->get('somethings.php',function() use ($app){
dd($app['request']->id);
});
//localhost/somethings.php?id=1 ---> return "1"
You didn't use the return keyword, It should be:
return redirect()->route('somethings', ['id' => $id]);
Instead of
redirect()->route('somethings', ['id' => $id]);
If you are using Homestead, it runs nginx as the web server and not Apache. .htaccess is specific to Apache.
Related
We have a bunch of URLs like this /order/step1.php?service=999 out there on the Internet.
Do you have to just abandon all of your old links that are published out on the Internet when you migrate to Laravel?
We tried to use mod_rewrite to simply rewrite the URL to /order/step1/999 but because of the .htaccess for Laravel that isn't working.
RewriteRule ^/order/step1\.php\?service=([0-9]+)$ /order/step1/$1 [L,QSA]
We also tried adding a route into web.php like this:
Route::get('/step-1.php?service={slug}', 'PageController#step1');
and that doesn't work either.
We would like to be able to not lose all of our old URLs.
Given that the url is like this:
/order/step1.php?service=999
The ?service=999 segment can be taken as a query param. So I think this should do the trick:
Route::get('order/step-1.php', 'PageController#step1');
Then in your controller:
# PageController.php
public function step1(Request $request)
{
$slug = $request->query('service');
dd($slug) // '999'
}
Check the section Retrieving Input > Retrieving Input From The Query String of the documentation.
I'm using the following Laravel version:
$ php artisan --version
Laravel Framework 5.5.44
On my Laravel routes I have the following:
...
Route::get('/', function () {
myLog(Input::all());
});
Route::get('/name', function () {
myLog(Input::all());
});
...
When I go to the following url (first route):
https://my.website.com/?field1=value1&field2=value2&field3=value3
I get on the logs file:
2019-03-11 16:15:17|DEBUG|{"field1":"value1","field2":"value2","field3":"value3"}
which is fine.
My problem is when I go to the following url (second route):
https://my.website.com/name?field1=value1&field2=value2&field3=value3
(notice: /name)
I get on the logs file:
2019-03-11 16:15:45|DEBUG|{"url":"name"}
Any idea about why when I use a Laravel route other than the root one, I cannot get the parameters on the url passed in a Get way?
I need to retrieve those parameters only as a Get, that's a requirement for me.
Any idea about how to solve this?
Thanks!
I found the issue on my case.
For some reason I was using the following Rewrite Rule on the .htaccess. Pay attention to that file:
RewriteRule ^(.*)$ index.php?url=$1 [PT,L]
Hope that helps somebody.
I use: slim-skeleton (Mr. Rob Allen's scaffold provided on github)
Under /projects grouped routes, only "get" method routes work without any problem but with rest of all return page not found error. Also these routes have auth middleware + cors middleware (Cors Middleware taken from Slim Framework's v3 Documentation).
Here is my ../src/routes.php file:
use Slim\Http\Request;
use Slim\Http\Response;
// Routes
// Administration
$app->group('/admin', function() use ($app) {
// Dashboard
$app->get('/dashboard', 'App\Controllers\Admin\Dashboard:index');
// Projects and images management
$app->group('/projects', function() use ($app){
// Projects Actions
$app->get('/list', 'App\Controllers\Admin\ProjectManagement:index');
$app->post('/add', 'App\Controllers\Admin\ProjectManagement:add'); # NOT WORKING
$app->get('/id/{id}', 'App\Controllers\Admin\ProjectManagement:find');
$app->put('/edit/{id}', 'App\Controllers\Admin\ProjectManagement:edit'); # NOT WORKING
$app->delete('/remove/{id}', 'App\Controllers\Admin\ProjectManagement:remove'); # NOT WORKING
// Project Images Actions
$app->get('/{pid}/images', 'App\Controllers\Admin\ProjectImageManagement:attachments');
$app->post('/{pid}/images/attach', 'App\Controllers\Admin\ProjectImageManagement:attach');
// Project's Image management
$app->get('/{pid}/images/id/{id}', 'App\Controllers\Admin\ProjectImageManagement:find');
$app->put('/{pid}/images/edit/{id}', 'App\Controllers\Admin\ProjectImageManagement:edit');
$app->delete('/{pid}/images/remove/{id}', 'App\Controllers\Admin\ProjectImageManagement:removeImage');
/**
* Project's Image Sort Order
*
* Additional Info:
*
* GET /{pid}/images Retrieves current sort order beforehand
*
*/
$app->put('/{pid}/images/order/{id}/resort', 'App\Controllers\Admin\ProjectImageManagement:sortOrder');
});
// Page management
$app->group('/pages', function() use ($app) {
// About Page
$app->get('/about/content', 'App\Controllers\Admin\PageManagement:aboutPage');
$app->put('/about/content/update', 'App\Controllers\Admin\PageManagement:updateAbout');
// Contact Page
$app->get('/contact/content', 'App\Controllers\Admin\PageManagement:contactPage');
$app->put('/contact/content/update', 'App\Controllers\Admin\PageManagement:updateContact');
});
// Settings
$app->group('/settings', function() use ($app) {
// Account
$app->get('/account/details', 'App\Controllers\Admin\Settings:accountDetails');
$app->post('/account/details/apply', 'App\Controllers\Admin\Settings::applyAccountSettingChanges');
});
})->add($auth);
// Auth
$app->get('/auth/point', 'App\Controllers\AuthController:checkPoint');
$app->post('/auth/login','App\Controllers\AuthController:login');
$app->get('/auth/logout', 'App\Controllers\AuthController:logout');
// Guest
$app->get('/about', 'App\Controllers\Guest\PageContents:about');
$app->get('/contact', 'App\Controllers\Guest\PageContents:contact');
$app->get('/works', 'App\Controllers\Guest\ProjectExplorer:projects');
And here is my .htaccess under /public directory:
<IfModule mod_rewrite.c>
RewriteEngine On
# Some hosts may require you to use the `RewriteBase` directive.
# Determine the RewriteBase automatically and set it as environment v
ariable.
# If you are using Apache aliases to do mass virtual hosting or
installed the
# project in a subdirectory, the base path will be prepended to allow proper
# resolution of the index.php file and to redirect to the correct URI. It will
# work in environments without path prefix as well, providing a safe, one-size
# fits all solution. But as you do not need it in this case, you can comment
# the following 2 lines to eliminate the overhead.
RewriteCond %{REQUEST_URI}::$1 ^(/.+)/(.*)::\2$
RewriteRule ^(.*) - [E=BASE:%1]
# If the above doesn't work you might need to set the `RewriteBase` directive manually, it should be the
# absolute physical path to the directory that contains this htaccess file.
# RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [QSA,L]
</IfModule>
I also added Allow from all, but it results in same way. But if i have doing something wrong why all other routes created outside of "/projects" work well. For instance, Auth related routes work well.
I know that, I have to see "Method Not Allowed" warning instead of seeing not found. Where am i doing something wrong? Any help would be very appreciated.
EDIT:
$app->map(['GET', 'POST', 'PUT', 'DELETE', 'PATCH'], '/{routes:.+}', function($req, $res) {
$handler = $this->notFoundHandler; // handle using the default Slim page not found handler
return $handler($req, $res);
});
I forgot this one. This mapping hides/exchanges method not allowed page => not found handler. It seems to me as an application based error. Sorry for my carelessness...
My suggestion is to add a root for the group you added
$app->group('/admin', function(){};
Under this you should add
$this->get('', function(){/*-----activities----*/});
And try to use $this while using the groups
Explanation:
when you are using $app you are referring to slim object.
when you are using $this inside your $app->group(){} then you are referring to grouped object which will be responsible for grouping the statements.
So, basically when you use $app inside the group then you make it useless because your slim-app is looking for it on above layer of the code(ie. outside the group). and you are not using group object($this in this case) to declare routes so eventually they are getting declared but not addressed properly.
$app->map(['GET', 'POST', 'PUT', 'DELETE', 'PATCH'], '/{routes:.+}', function($req, $res) {
$handler = $this->notFoundHandler; // handle using the default Slim page not found handler
return $handler($req, $res);
});
I forgot this one. This mapping hides/exchanges method not allowed page => not found handler. It seems to me as an application based error. Sorry for my carelessness...
But in my opinion notFoundHandler is not the right choice for this. A custom error message has to be raised for this situation like 405 Method Not Allowed - (notFoundHandler returns 404)
Not sure if this is the case, but if you need to change $app->get or $app->post to $this->get or $this->post if you group the routes.
I got an error with redirecting I dont know why, i read the documentation of laravel 5.2 about redirecting and still not working pls help me thanks, here is my route in the routes.php
Route::get('/orders/view/{id}', 'OrderController#view');
here is my code in the controller for the redirecting
return redirect()->route('/orders/view/', ['id' => 5]);
and still it gives me this error
InvalidArgumentException in UrlGenerator.php line 314: Route
[/orders/view/] not defined.
The Problem
You're trying to redirect to a route by it's name, but you're passing an URL to the method.
return redirect() # Initialize a redirect...
->route(...); # to a route by it's name
The solutions
There are multiple ways to solve this. You can either redirect by path (that's
how you're trying to do at the moment), or by using route names.
Method 1: Redirect by path
You can redirect by path in two ways:
- concat the path by hand
- use the URL facade.
Concat the path by hand
$url = '/orders/view/' . $order->id;
return redirect($url);
Use the URL facade
# Remember to remove the trailing slash.
# Appending a trailing slash would lead to example.com/orders/view//1
$url = URL::to('/orders/view', [$order->id]);
return redirect($url);
You're done!
Method 2: Redirect by route name
To use route names, you need to prepare your routes and give them a name.
I recommend this way, because sometimes it's more clear but it also makes
maintaining your application easier when you need to change some paths, because
the names will be still the same. Read more about it here:
https://laravel.com/docs/5.2/routing#named-routes
This also allows you to use the easy-to-use and useful route() helper method.
Prepare your routes file
To assign your routes a name, you need to pass them to your router in your app/Http/routes.php.
# Example 1
Route::get('/orders/view/{id}', [
'as' => 'orders.view', 'uses' => 'OrderController#view'
]);
# Example 2
Route::get('/orders/view/{id}', 'OrderController#view')->name('orders.view');
For myself, I recommend to use the second syntax. It makes your code more
readable.
Redirect by route name
Now it's time to redirect! If you're using the method of route naming, you don't
even have to change much in your code.
return redirect()->route('orders.view', ['id' => $order->id]);
A note from my side
Have a look on route-model-binding in the documentation:
https://laravel.com/docs/5.2/routing#route-model-binding
This allows you to pass a model instance directly to the route() method and
it helps you fetching models by passing the proper model to your controller method
like this:
# Generate route URL
route('orders.view', $order);
# Controller
public function view(Order $order) {
return $order;
}
And in your app/Http/routes.php you would have {order} instead of {id}:
Route::get('/orders/view/{order}', 'OrderController#view');
You can use
return redirect()->action('OrderController#view', ['id' => 5]);
or
// $id = 5
return redirect()->to('/orders/view/'.$id);
I want to route to filter access to files in upploads folder.
Route::get('uploads/{class}/{id}/{filename}', array('before' => 'auth', function()
{
return "route works";
}));
the code above works for link uploads/Deviation/1/Laravel%20Cheatsheet, but if the link is to an actual file uploads/Deviation/1/Laravel%20Cheatsheet.pdf, it seems like laravel is bypassing router. I get why does it do it, but is there a way to bend the rules for uploads folder?
By default characters like slashes and dots are not allowed in parameter values. In order to override that, you'll need to define the route as follows:
Route::get('uploads/{class}/{id}/{filename}', array('before' => 'auth', function()
{
return "route works";
}))->where('filename', '[a-zA-Z0-9\.]+');
Just make sure that you don't store the files in publicly accessible location - I suggest to store it somewhere in storage/.
The recommended Laravel Apache configuration is:
Options +FollowSymLinks
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]
The recommended nginx configuration is:
location / {
try_files $uri $uri/ /index.php?$query_string;
}
Both of these prioritize any files with that exact filename first, falling back to Laravel's index.php only if a file is not found. This is fairly important - you don't want the largeish PHP framework involved in serving static files like CSS/JS/images, it'd be a heavy load on the server.
If you want to sit Laravel in front of your uploads, just use a different URL to reference them, and have Laravel serve the file after you've done whatever it is you need to do.
Route::get('not-the-real-uploads/{class}/{id}/{filename}', array('before' => 'auth', function()
{
// something like this
return Response::download('uploads/...', ...);
}));