I'm having Laravel build images for me, but once the image exists, I'd like Apache to serve it (instead of booting Laravel, reading in the image, and passing it through). Here is the rule I wrote in htaccess to do this:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} ^/storage/product_images/(.*).png
RewriteRule ^storage/product_images/(.*)\.png$ index.php/image/$1 [L]
My question is about this last bit: index.php/image/$1 in which I am trying to pass values into Laravel as though it were a route. This doesn't seem to be working. I'm just getting a 404 from Laravel even though the actual route works (/image/23). Is there a different way to do this? Maybe something like this?
index.php?_url=image/23
... another way to phrase this question: how might I use Laravel without an .htaccess? How could I simply pass params to the index.php file?
Related
Moved from https://serverfault.com/questions/1013461/cant-use-parentheses-in-rewritecond-query-string because it's on topic here.
I need to capture a UID from an old url and redirect it to a new format.
example.com/?uid=123 should redirect to example.com/user/123
What should work:
RewriteCond %{QUERY_STRING} ^uid=(\d+)$
RewriteRule ^$ /user/%1? [L]
This does not redirect at all.
However, this does:
RewriteCond %{QUERY_STRING} ^uid=\d+$
RewriteRule ^$ /user/%1? [L]
It goes to example.com/user. The UID is left out, but it DOES redirect.
Notice: All I did was remove the parentheses in the second example.
Why is this?? How can I match the query AND capture the value of UID?
Updates
This is a laravel app. I've discovered that the redirects I did see may have been coming from the app, not Apache.
Self-answer coming soon...
Temporarily adding R=302 gives the desired result:
RewriteCond %{QUERY_STRING} ^uid=(\d+)$
RewriteRule ^$ /user/%1? [L,R=302]
This, of course, sends a 302 redirect to /users/123. I'd like to see if this can be done with an internal rewrite though...
Here are some rules in laravel's default .htaccess:
# Handle Front Controller...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]
This catches paths that do not point to real files, and it points them to the laravel app. When this is removed, Apache responds with a 404 for /users/1234.
https://httpd.apache.org/docs/2.4/rewrite/flags.html#flag_l
Such a rewrite goes back to Apache's URL parser. Then the .htaccess is processed again (since it's still applicable to this new URL). At this point, I'd expect the above rules to pick up the non-existent path and point it to the laravel app...
Found it. Writing an answer now.
The Answer
MrWhite was right. You have to add R=302 or R=301 to perform a redirect. An plain ol' rewrite won't work.
RewriteCond %{QUERY_STRING} ^uid=(\d+)$
RewriteRule ^$ /user/%1? [L,R=302]
The Reason
So, the way Laravel works is:
you request /some/file
.htaccess tells apache, "hey apache, if you have a request for a file that doesn't exist just pretend it's for index.php"
apache says, "hey php, I have a request to run index.php and the url is /some/file"
php runs the script which --whoah-- is a huge laravel application
whatever, "hey laravel, the server said /some/file is the url"
laravel does all it's fancy stuff, and it tries to match the url to one of your routes
Now, I added a rule to rewrite a certain URL to a virtual URL that Laravel should handle. I was matching against query parameters, but that was irrelevant. (see below for details)
When Apache's Rewrite Module hits a RewriteRule without an [R] flag, it rewrites the URL and sends it back to the URL Handler. Apache's URL Handler then processes the new URL against all the rules, including those in any applicable .htaccess files.
So all the proper rules did get applied.
Here's the key revelation:
The originally requested URL never changed. So while Apache was able to pass the request to PHP with the correct file, it was also sending along the old URL.
Therefore, we have to tell Apache to send a 301 or 302 Redirect response, instead of just rewriting the request. The user will send another request with the URL that Laravel needs to resolve the route.
But what about the different behavior with/without the parentheses?
The answer lies within Laravel's default .htaccess. Let's take a look my old rules without the parentheses:
RewriteCond %{QUERY_STRING} ^uid=\d+$
RewriteRule ^$ /user/%1? [L]
Without the parenthesis to grab the uid value, %1 is empty. So we end up rewriting the URL to just /user/.
Now, we have to look at another set of Laravel rules:
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/$ /$1 [L,R=301]
This normalizes urls so that virtual paths/routes don't contain trailing slashes. Doing this makes route parsing easier.
This returns a 301 Redirect to `/users'. This is very different from the 200 we were getting with the parentheses, but it does not mean the parentheses were behaving differently. As MrWhite said in the comments, surely something else was doing it.
I hope you enjoyed the ride. And I hope even more that this will save some poor, confused soul from hours of torment. :)
I have read a lot on stack about rewriterule and how it applies and I've tried reading up on some good articles online but I still cannot wrap my head around a few things.
I have blogs setup where all folders are in
https://domain.ca/posts/post-tree/*
So I've setup htaccess like this
RewriteRule ^posts/post-tree/(.*)$ /index.php?$1 [R=301]
As I'm sure you can guess this basically brings me root index.php where I catch this request with a $_GET to know the name of the blog folder it was requesting.
This is fine I can hit index.php and with $_GET I know the blog page they requested.
What I do not get, and I've tried a lot of things, is once I have this request in index.php how do I re-write the URL to show something like https://domain.ca/blogpage/ instead of looking like https://domain.ca/index.php? where https://domain.ca/blogpage/ does not really exist of course, but it is because I want to hide the http://domain.ca/posts/post-tree/ path.
Its a little like when wordpress processes a blog page with the id and after rewrites the url to whatever slug is set for that blog page. at least my understanding of it as they don't have individual folders for blogs, but I do.
I finally got this working with the following in the htaccess file
RewriteEngine on
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
# the above checks if file or folder exists, if not the below is processed
# this will route to base index file and fetch $1 folder via $_GET
RewriteRule . /posts/post-tree/index.php?$1
I believe that I already did all the important thing to set up the custom route in codeigniter but I still don't know why I always get 404 error.
The current url I can access is: http://localhost:8080/project/api/profile_test/
And I want to rewrite it as: http://localhost:8080/project/api/users/
I've added this code in the route.php but still not working: $route[‘users’] = 'profile_test';
My .htaccess is:
RewriteEngine on
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /index.php?$1 [L]
I already set the AllowOverride All and remove the index.php in $config['index_page'] = '';. But still not working.
I’m almost 8 hours for this with this little thing and I need help to the one who knows it.
What am I missing? Any help is much appreciated.
In Codeigniter, a route consists of 3 parts:
the URL
the controller name
the method name
The docs explain it well.
So, if your project's root is http://localhost:8080/, for a URL like project/api/users/, to be handled by a controller (located in application/controllers/) called Profile_test and a method called index, you would need a route like:
$route['/project/api/users'] = 'profile_test/index';
Note that the controller file and class must be capitalised, as described in the docs, so for example controllers/Profile_test.php.
If your project's root is http://localhost:8080/project, you would change that to:
$route['/api/users'] = 'profile_test/index';
If your controller is located in a subdirectory like application/controllers/api/, you would change that to:
$route['/project/api/users'] = 'api/profile_test/index';
Also make sure you are using normal single quotes. Some of the code you include in your question includes 'smart' quotes: $route[‘users’] which will not work in PHP.
I'm having a strange problem. I recently moved my Laravel site from one directory to another in my localhost (on a Mac). Nothing has been right since. I had to change my .htaccess from the standard Laravel 4 .htaccess to:
Options +FollowSymLinks
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . index.php [L]
which is the alternative Laravel .htaccess for L4. That at least makes my public folder not be forbidden. But now Laravel just completely ignores the routes file. In fact, all routes (those in the file and those not) seem to valid and none seem to call a 404 error, even though I try to call both routes that exist and routes that don't. I even deleted everything in the routes file except the base route and nothing changed.
How is it possible that routes that don't exist can be called and I don't get the page not found error? All I get is a white screen. The same is true except for the base route. Why is it honoring only the base route (which is '')? If I change that route to one of the other controllers, it will call that controller. In short, the only route that works is ''. Why has everything changed since I moved the site?
Well i started coding a mini MVC base that I can just use on client websites, which also uses the same type of router class as CakePHP. I currently have the url display like this:
http://localhost/mvc/index.php?page=blog/viewall
Which gets the controller and tells it the function, just like CakePHP index(), view(), and so on.
Now, I'm not sure how I can make the url look like this with .htaccess
http://localhost/mvc/blog/viewall
I was trying to add this in the .htaccess file:
RewriteRule ^(.*)$ index.php?page=$1 [QSA]
Have your redirect rule like this:
RewriteEngine On
RewriteCond %{REQUEST_URI} !^/mvc/index.php/.*
RewriteRule ^/mvc/(.*) /mvc/index.php?page=$1 [QSA,L]