.htaccess question - the [L] flag any way to simplify - .htaccess

I usually use MVC routing but I have to work on a site with non MVC and need to add a new feature.
Here is my commnads which works:
RewriteRule ^blog/why-am-using-htaccess/$ viewBlog.php?blogHook=$1 [L]
RewriteRule ^blog/(.*) blogs.php [L]
RewriteRule ^(.*)/$ page.php?hookName=$1
My issue is I have to put the [L] flag on everything above for it to work. I want to basically issue a flag to
RewriteRule ^(.*)/$ page.php?hookName=$1
That basically says do everything above but the last one is the fallback.
Is there any way to do that?

You have to use
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
before your last rule. The first rules rewrote the requested url to a valid (php) file which can be accessed, so the conditions will turn to false. If no rules matched before, but the requested url is a valid file yet (such as an image), this rule isn't processed too.
You should also omit the slash in the last rule: ^(.*)/$, because otherwise this rule only rewrites urls with an ending slash.

Related

What does this code in HTACCESS say

I' am just a beginner trying to learn about HTACCESS but can't seem to find anything on Google that will explain what this code below means. I know it for making pretty URL's but what is the long description of it. Please can someone professional or experts can guide me in explaining this. Thanks!
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
Let's look at it line by line
<IfModule mod_rewrite.c>
This says that whatever is between the tags should only be read if, and only if, mod_rewrite is installed and enabled on the target server.
RewriteEngine On
This turns the RewriteEngine on. Without it, no RewriteRules take effect. (docs)
RewriteBase /
RewriteBase is used when redirecting a request. As far as I am aware, it can never hurt to set it, even though sometimes it goes right automatically. (docs)
RewriteRule ^index\.php$ - [L]
This is the first RewriteRule. If a request is done to http://example.com/index.php (with or without a query string), the url is not rewritten. The [L] denotes that if this rule matches, it is the last rule that will be matched during this 'pass' through the file. Because the url is not rewritten, no further 'passes' through the .htaccess file are done.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
If the previous rule didn't match, it will try to match this rule. This rule matches any url of at least 1 character. A request to http://example.com would not match this rule. If the first part of the RewriteRule matches, it will check the conditions. The first condition checks if the file that is requested (%{REQUEST_FILENAME}) is not an existing file (!-f). -f means "is an existing file" and the prefix ! negates that. The second condition is similar, but tests if the requested file is not an existing directory. If both conditions are true, the request will be internally rewritten to index.php. The [L] flag will stop rewriting for this pass, and during the next pass the first rule will match, and stop rewriting altogether.
See the documentation for more information about what is possible with RewriteCond and RewriteRule.

How to avoid a looping redirection from .htaccess?

I've set a .htaccess with a set of rules.
RewriteEngine on
RewriteCond $1 !^(index\.php|images|stylesheets|javascript|robots\.txt)
RewriteRule ^Canvas/(.*)/(.*)$ /canvas.php?a=$1&b=$2 [L]
RewriteRule ^(.*)$ /index.php/$1 [L]
The above rule get redirected and throwing 500 internal server error.
When I comment the last line, everything that follows the rule /canvas/something/something is working fine but things are going wrong when un-comment the last line.
I tried adding condition like
RewriteCond %{REQUEST_URI} !^/canvas.php.*
and
RewriteCond %{REQUEST_FILENAME} !^/canvas.php.*
but it didn't resolved the problem.
How could I resolve this?
[L] does not do what you think it does: It only stops "this round" and restarts the rewriting execution with the new URL. You might want to try [END].
See End vs Last flags.
Alternatively, you cant try using the skip flag [S=number_of_rules_to_skip].
You could perhaps try adding an environment variable to mark the fact you've redirected and trap for this using a RewriteCond. For example (untested):
RewriteEngine on
RewriteCond $1 !^(index\.php|images|stylesheets|javascript|robots\.txt)
RewriteRule ^Canvas/(.*)/(.*)$ /canvas.php?a=$1&b=$2 [E=REWRITEDONE:1,L]
RewriteCond %{ENV:REWRITEDONE} !1
RewriteRule ^(.*)$ /index.php/$1 [L]
Two things are happening here. First, /canvas.php is getting rewritten to /index.php/canvas.php. Then /index.php itself is getting rewritten to /index.php/index.php/canvas.php, and then that keeps looping. Your second rule has no conditions to prevent it from blindly rewriting everything that matches ^(.*)$ (which is everything). Note that RewriteCond's only affect the immediately following RewriteRule, so the one that routes to /index.php won't have any conditions on it. A few conditions that you can add to prevent the looping:
RewriteCond $1 !^(index\.php|canvas\.php|images|stylesheets|javascript|robots\.txt)
RewriteRule ^(.*)$ /index.php/$1 [L]
Rewrites everything that isn't index.php, canvas.php, images, stylesheets, scripts, and the robots.txt file. Or:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /index.php/$1 [L]
Rewrites everything that isn't pointing to an existing file or directory. This also excludes direct access to stuff like scripts and styles and the robots.txt, along with any other static content.
Another possibility is to prevent looping entirely, by adding this to the top of your rules (right below RewriteEngine On:
RewriteCond %{ENV:REDIRECT_STATUS} 200
RewriteRule ^ - [L]
This means if there's already an internal rewrite, stop rewriting completely by passing through the URI (the - target). The rewrite engine loops until the URI going in stops changing, the passthrough essentially does that. If you are using apache 2.4, you can also use the END rewrite flag to stop rewriting.

htaccess redirection dynamic

I am trying to redirect /en/news/12345 to http://www.xyz.com/en/newsletters/12345
the only thing is that "en" and "12345" can change but "news" is always the same.
I have the following so far:
RewriteRule /^(.)/news/(.)$ http://www.xyz.com/$1/news/$2 [R=301,L]
but if i go to mydomain/wp-admin then i get an endless redirect?? Any ideas why this is happening?
Thanks
Options +FollowSymlinks
RewriteEngine on
RewriteRule ^en/news/([0-9]) http://www.xyz.com/en/newsletters/$1 [NC]
Please try this, hope it will solve your problem
I think I found the problem in your .htaccess file. Initially you had two conditions that prevented RewriteRule . /swissfil3/index.php [L] (catch-all) from redirecting when the path pointed to an existing file or folder (ignore-on-file):
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond only applies to the rule directly followed by the condition.
When you added a new rule directly below these directives, the catch-all rule was not prevented from redirecting existing files or directories like /wp-admin. I.e. every request not matching any rules before catch-all would be redirected to /swissfin/3/index.php.
In additoin you used (.) to capture each part of the path. This would match one arbitrary character, but no more, so your redirect would be limited to /X/news/Y, instead of /XX/news/YYYY..., to fix this you can use (.+) which will match zero or more chars, or even better ([^/]*) which will match zero or more characters not equal to /.
You should be able to avoid these problems by using the following code (where the catch-all directive has been moved directly below ignore-on-file, and the rewrite rule matches zero or more chars not equal to /):
# ...
RewriteRule ^([^/]*)/news/([^/]*)$ http://www.xyz.com/$1/news/$2 [R=301,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /swissfin3/index.php [L]
Here you match every URL that contains a char

RewriteRule subtle differences - one in the same?

I'm trying to better understand mod_rewrite and I've come across some differences, which I think do the same thing? In this case, no existing files or directories and rewriting to an index.php page.
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule .+ - [L]
Do I need the [OR] or can I leave it off?
What are the differences or advantages of the following rules? I'm currently using the first one, but I've come across the last four in places like WordPress:
#currently using
RewriteRule ^(.+)$ index\.php?$1 [L]
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
Do I need the [OR] or can I leave it off?
In this case you need the [OR] because RewriteCond's are inherently ANDed, and it's not the case that a request is both a file and a directory (as far as mod_rewrite is concerned).
RewriteRule ^(.+)$ index\.php?$1 [L]
This rewrites all requests that aren't for the document root (e.g. http://domain.com/) as a query string for index.php, thus a request for http://domain.com/some/path/file.html gets internally rewritten to index.php?some/path/file.html
RewriteRule ^index\.php$ - [L]
This is a rule to prevent rewrite looping. The rewrite engine will continue to loop through all the rules until the URI is the same before the rewrite iteration and after (without the query string). If the URI starts with index.php simply stop the current rewrite iteration (what the - does). The rewrite engine sees that the URI before sending it through the rules was index.php and after the rules was index.php, thus the rewrite engine stops and all rewriting is done. This prevents mod_rewrite from rewriting things to index.php?index.php which the first rule would do upon the 2nd pass through the rewrite engine if it isn't for this rule.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
This is the catch-all. If the first rule never gets applied, and the request isn't for an existing file or directory, send the request to index.php. Though in this case, it looks like this rule will never get applied.
EDIT:
is there a way to ignore a certain rule if a condition is true? For example, www.domain.com/some/path > index.php?some/path, but if the URI is www.domain.com/this/path > no rewrite?
You'd have to add 2 conditions, one that checks to make sure the requested host isn't "www.domain.com" and one to check that the URI isn't "/this/path":
RewriteCond %{HTTP_HOST} !^(www\.)?domain\.com$ [NC,OR]
RewriteCond %{REQUEST_URI} !^/some/path
The [NC] indicates that the condition's match should ignore case, so when someone enters the URL http://WWW.domain.com/ in their address bar, it will match (or in this case, not match). The second condition matches when the URI starts with "/some/path", which means requests for http://domain.com/some/path/file.html will match and NOT get rewritten. If you want to match exactly "/some/path", then the regular expression needs to be !^/some/path$.
Why not use [OR] in the final block between !-f and !-d?
This is the logical negation of -f OR -d: "if the file exists, don't rewrite, OR if the directory exists, don't rewrite" turns into "if the file doesn't exist, AND if the directory doesn't exist, then rewrite"

htaccess directory to file redirect problem

I’m trying to use the following .htaccess file
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !^images/
RewriteRule (.*) view.php?picid=$1 [L]
RewriteRule ^/user/(.*)$ /users.php?user=$1
I want two things to happen: Whenever someone requests /1234, it redirects to /view.php?picid=1234, and also when someone visits /users/bob, it redirects to /users.php?user=bob.
My code however, doesn’t seem to be working correctly.
There are several ways to do that. Here’s one that should work:
RewriteRule ^user/(.+)$ users.php?user=$1 [L]
RewriteRule ^([0-9]+)$ view.php?picid=$1 [L]
The first rule will catch any request that’s URI path begins with /user/ followed by one or more arbitrary characters. And the second will catch any request that’s URI path begins with / followed by one or more digits.
The initial problem with your rules is that the RewriteRule with (.*) will match everything.
If you do not want it to match a URL with a slash in it (such as users/bob), try ^([^/]*)$
Secondly, after a URL is rewritten, the new URL goes through your rules again. If you want to avoid matching something that has already been rewritten once, you should add a condition like
RewriteCond %{REQUEST_URI} !\.php

Resources