.htaccess directives to *not* redirect certain URLs - apache

In an application that heavily relies on .htaccess RewriteRules for its PrettyURLs (CakePHP in my case), how do I correctly set up directives to exclude certain directories from this rewriting? That is:
/appRoot/.htaccess
app/
static/
By default every request to /appRoot/* is being rewritten to be picked up by app/webroot/index.php, where it's being analysed and corresponding controller actions are being invoked. This is done by these directives in .htaccess:
RewriteBase /appRoot
RewriteRule ^$ app/webroot/ [L]
RewriteRule (.*) app/webroot/$1 [L]
I now want to exclude a few directories like static/ from this rewriting. I tried with this before the Cake RewriteRules:
RewriteCond $1 ^(static|otherDir).*$ [NC]
RewriteRule (.*) - [L]
It works in so far that requests are no longer rewritten, but now all requests are being skipped, even legitimate Cake requests which should not match ^(static|otherDir).*$.
I tried several variations of these rules but can't get it to work the way I want.

And the correct answer iiiiis...
RewriteRule ^(a|bunch|of|old|directories).* - [NC,L]
# all other requests will be forwarded to Cake
RewriteRule ^$ app/webroot/ [L]
RewriteRule (.*) app/webroot/$1 [L]
I still don't get why the index.php file in the root directory was called initially even with these directives in place. It is now located in
/appRoot/app/views/pages/home.ctp
and handled through Cake as well. With this in place now, I suppose this would have worked as well (slightly altered version of Mike's suggestion, untested):
RewriteCond $1 !^(a|bunch|of|old|directories).*$ [NC]
RewriteRule ^(.*)$ app/webroot/$1 [L]

Could you not apply the condition to the following rules, but with negation, as in (with some variation thereof, I'm not too good at remembering .htaccess rules, so the flags might be wrong):
RewriteCond $1 !^(static|otherDir).*$ [NC]
RewriteRule ^$ app/webroot/ [L]
RewriteCond $1 !^(static|otherDir).*$ [NC]
RewriteRule ^$ app/webroot/$1 [L]

Remove the [L] from the previous rules:
RewriteBase /appRoot
RewriteRule ^$ app/webroot/
RewriteRule (.*) app/webroot/$1
[L] means "Stop the rewriting process here and don't apply any more rewriting rules."

Related

Not able to track htaccess issue, How to implement IF ELSE in htaccess

I have a problem with htaccess to execute a rule and if rule matches then do not check for another rule. which i am trying to figure out from last few hours. Below is the sample code
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_URI} ^/projectname/$
#RewriteCond %{REQUEST_URI} !projectname/(storage)$
RewriteRule ^(.*)$ /projectname/abc/dist/$1 [L]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} projectname/(storage)$
RewriteRule ^(.*)$ /projectname/storage/$1 [L]
Rewritecond %{REQUEST_URI} projectname/(.*)$
#RewriteCond %{REQUEST_URI} !projectname/(storage)$ [NC]
RewriteCond %{REQUEST_URI} !\.(html?|png|woff|ttf|eot|svg|woff2|jpg|gif|xml|rss|png|css|js|json)$ [NC]
RewriteRule ^(.*)$ /projectname/#/$1 [NE,R=301,L]
RewriteRule ^(.*)$ /projectname/abc/dist/$1 [L]
I want to load everything from projectname/abc/dist folder but not for the case when i have storage inside url then i want to load the data from storage folder only.
So as per rules defined here everything works fine but when i have storage inside url/src for image it still checks /projectname/abc/dist/storage/xxxx.png instead of checking /projectname/storage/xxxx.png as defined in htaccess rule.
I have tried using [S=5] skip with storage rule in htaccess does not works from reference http://httpd.apache.org/docs/2.4/rewrite/flags.html.
Also as per my understanding [L] is the last so it should stop the htaccess after storage rule but it does not.
I have tried implementing IF ELSE in htaccess but the examples i tried for IF ELSE does not help even.
reference https://blogs.apache.org/httpd/entry/new_in_httpd_2_4
reference http://httpd.apache.org/docs/2.4/rewrite/flags.html (check Skip IF ELSE stanza)
Any Idea would be useful.
You want to load from 'projectname/abc/dist'-folder EXCEPT when there is 'storage' anywhere in the requested URI?! If I got that right, that might help:
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_URI} !storage
RewriteRule ^(.*)$ /projectname/abc/dist/$1 [END,P]
I added [P] for 'proxy' assuming that you don't want to show the customer he is rewritten by your server. If you don't mind seeing them, just leave that out.
First of all, L|last doesn't mean stop all processing.
If you are using RewriteRule in either .htaccess files or in sections, it is important to have some understanding of how the rules are processed. The simplified form of this is that once the rules have been processed, the rewritten request is handed back to the URL parsing engine to do what it may with it.
See also Ruleset Processing for how this works.
To load from /project/abc/dist, except when there's storage in the URL, you must first check for storage
RewriteCond %{REQUEST_URI} /storage/
RewriteRule /([^/]*$ /project/storage/$1 [L]
And then
RewriteRule ^(.*)$ /project/abc/dist/$1 [L]
Finally, to prevent a rewrite loop, prefix the rules with
RewriteCond %{ENV:REDIRECT_STATUS} 200
RewriteRule ^ - [L]
Everything together
RewriteCond %{ENV:REDIRECT_STATUS} 200
RewriteRule ^ - [L]
RewriteCond %{REQUEST_URI} /storage/
RewriteRule /([^/]*$ /project/storage/$1 [L]
RewriteRule ^(.*)$ /project/abc/dist/$1 [L]

.htaccess rule redirecting, but not rewriting

I am writing a simple rewrite rule.
I want all trafic going to a given path to get contetns from another
I have these rules:
Options +FollowSymlinks
RewriteEngine on
#this is the rule I am implementing
RewriteCond %{REQUEST_URI} ^/bar/$
Rewriterule ^(.*)$ "/foo/bar/" [L]
#This rule is working
RewriteCond %{QUERY_STRING} ^(.*)$
RewriteRule ^([a-zA-Z]+)$ "/foo/bar/index.php?fb=$1&%1 [L]
There is one rule more after this one and it's working:
Like before it does not work. Like this, it does:
RewriteCond %{REQUEST_URI} ^/bar/$
Rewriterule ^(.*)$ "/foo/bar/" [R,L]
I want to rewrite, not redirect, but I often use the R just to test.
I am probably doing something wrong, but what?
Note: I had another rule before, for rewrite, that worked. Its not missing any modules (I think).
After some fighting I discovered the problem.
For this rule to work:
#this is the rule I am implementing
RewriteCond %{REQUEST_URI} ^/bar/$
Rewriterule ^(.*)$ "/foo/bar/" [L]
It needs to be written like:
RewriteCond %{REQUEST_URI} ^/bar/index.php$
Rewriterule ^(.*)$ "/foo/bar/" [L]
It needed the index.php. You should replace for the file or resource that you have.

why does a matched rewriterule not work?

I have the following .htaccess:
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteRule ^a/(.*)$ api.php?params=$1 [L,QSA]
RewriteRule ^$ app/webroot/ [L]
RewriteRule (.*) app/webroot/$1 [L]
</IfModule>
I expect that when I go to /a/test that the server returns /api.php?params=test
Instead, the third rule is matched.
If I comment out the third rule, then the first rule works.
Why is that?
Eventhough you have the L flag, which stops rewriting for the current rewriting iteration, the result (the rewritten URI) will be put back into the rewrite engine, and will continue to do so, until the URI going into the rewrite engine comes out unchanged. So what's happening is the first rule gets applied, then api.php?params=test is put back into the rewrite engine, where the 3rd rule gets applied.
You can either turn off all looping, by passing through the URI if an internal redirect was made, by adding this right underneath RewriteEngine On:
RewriteCond %{ENV:REDIRECT_STATUS} 200
RewriteRule ^ - [L]
Or add a condition to the 3rd rule so that it ignores requests to existing resources:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*) app/webroot/$1 [L]
Or add an explicit condition to ignore api.php:
RewriteCond %{REQUEST_URI} !^/api\.php
RewriteRule (.*) app/webroot/$1 [L]

htaccess for redirect to SSL

For the past few hours (days) I have been having some trouble redirecting a
page to SSL.
My setup is as follows: I have the following .htaccess for an e-commerce site
on Apache 2.2.16 on Debian (all required mods enabled)
RewriteEngine On
RewriteBase /shop
RewriteCond $1 !^(index\.php|products|img|theme\.php|checkout\.php)
RewriteRule ^(.*)$ index.php?/$1 [L]
all requests are passed to index.php which acts as my controller and includes
other .php files as necessary.
I now want to use HTTPS for the checkout process which is a php script
cleverly called checkout.php
I thought it would be as easy as changing my .htaccess to:
RewriteEngine On
RewriteBase /shop
RewriteCond %{SERVER_PORT} !^443$
RewriteCond %{SERVER_URI} checkout\.php
RewriteRule ^checkout.php?/$1 https://localhost/shop/checkout.php?/$1 [L,R]
RewriteCond $1 !^(index\.php|products|img|theme\.php|checkout\.php)
RewriteRule ^(.*)$ index.php?/$1 [L]
so that checkout.php is not processed by index.php.
Apparently it is not that simple. I could probably do it by using a hardcoded
https link to checkout but I would prefer to do it with mod_rewrite.
If anyone can share some insight into
this it would be really appreciated.
Thanks in advance
There are a few problems. First, the pattern in your first RewriteRule
RewriteRule ^checkout.php?/$1 https://localhost/shop/checkout.php?/$1 [L,R]
is written incorrectly. $1 isn't meaningful there (it's a capture result, but no capture has happened yet), and also the query string (part of the request after the ?) isn't part of what's matched, as the RewriteRule documentation says.
Second, I think you meant to use REQUEST_URI instead of SERVER_URI.
So I think you want something like this:
RewriteCond %{HTTPS} off
RewriteCond %{REQUEST_URI} ^/checkout\.php
RewriteRule .* https://localhost/shop/checkout.php [L,R]
RewriteCond %{REQUEST_URI} !^/(index\.php|products|img|theme\.php|checkout\.php)
RewriteRule ^(.*)$ /index.php?/$1 [L]
A few notes:
You don't need to match or add back in the query string in the first RewriteRule; mod_rewrite will automatically add it back in.
It's conventional to test RewriteCond %{HTTPS} off instead of
RewriteCond %{SERVER_PORT} !443, as #Jon Lin suggests.
You may want to add the QSA flag in your second RewriteRule.

RewriteRule Last flag being ignored

I don't get that if a rewrite rule matches and it has the Last [L] flag that it still executes the rules beneath. I redirect all calls to the public folder but I've added an exception for images, but the exception is being ignored. I thought that with the [L] flag if a rule matches it stops looking for rules beneath.
This is my .htaccess file:
RewriteRule ^image/(.*)/?$ image.php?t=$1 [L]
RewriteRule ^$ public/ [L]
RewriteRule (.*) public/$1 [L]
If I remove the bottom 2 rules it does work.
Thanks in advance
It is not ignored.
It is the specific of .htaccess.
It reruns every time URL is changed.
Try this instead.
RewriteEngine on
RewriteCond %{QUERY_STRING} rewritten
RewriteRule .* - [L]
RewriteRule ^image/(.*)/?$ image.php?t=$1&rewritten=1 [L,QSA]
RewriteRule ^$ public/?rewritten=1 [L,QSA]
RewriteRule (.*) public/$1?rewritten=1 [L,QSA]