.htaccess not working for a specific case - .htaccess

I am facing a strange issue while working with .htaccess file.
Here is my file:
<IfModule mod_rewrite.c>
Options +FollowSymlinks
RewriteEngine On
RewriteRule ^(admin)($|/) - [L]
RewriteRule ^$ ./web/view/
RewriteRule ^([A-Za-z0-9]+)$ ./web/view/?module=$1
RewriteRule ^([A-Za-z0-9]+)/$ ./web/view/?module=$1
RewriteRule ^([A-Za-z0-9]+)/([A-Za-z0-9]+)/([0-9]+)$ ./web/view/?module=$1&id1=$2&id2=$3
RewriteRule ^([A-Za-z0-9]+)/([A-Za-z0-9]+)/([0-9]+)/$ ./web/view/?module=$1&id1=$2&id2=$3
RewriteRule ^([A-Za-z0-9]+)/([A-Za-z0-9]+)$ ./web/view/?module=$1&id1=$2
RewriteRule ^([A-Za-z0-9]+)/([0-9]+)/$ ./web/view/?module=$1&id1=$2
ErrorDocument 404 err.php
</IfModule>
Now in the last rule, if I add [a-z] along with [0-9], I am getting a 500 error. E.g., the below line will give me 500 error:
RewriteRule ^([A-Za-z0-9]+)/([a-z0-9]+)/$ ./web/view/?module=$1&id1=$2
However, if I use A-Z, it is working fine.
RewriteRule ^([A-Za-z0-9]+)/([A-Z0-9]+)/$ ./web/view/?module=$1&id1=$2
Even [NC] is also giving me same error.
Can you help me to identify and correct this problem?

Now in the last rule, if I add [a-z] along with [0-9], I am getting a 500 error. E.g., the below line will give me 500 error:
The reason is because the rewrite engine is going into an infinite loop:
request URI looks like /something/id/ (note the trailing slash)
it matches the rule: RewriteRule ^([A-Za-z0-9]+)/([a-z0-9]+)/$ ./web/view/?module=$1&id1=$2
URI gets rewritten to /web/view/?module=something&id=id
new URI is put back into the rewrite engine, new URI = /web/view/
URI matches the (same) rule: RewriteRule ^([A-Za-z0-9]+)/([a-z0-9]+)/$ ./web/view/?module=$1&id1=$2
URI gets rewritten to /web/view/?module=web&id=view
repeat from step 4
You need to add a condition to prevent it from looping:
RewriteCond %{REQUEST_URI} !/web/view
RewriteRule ^([A-Za-z0-9]+)/([A-Za-z0-9]+)/$ ./web/view/?module=$1&id1=$2

My first instinct is to add a [L] at the end of each rewrite line, for example:
RewriteRule ^([A-Za-z0-9]+)$ ./web/view/?module=$1 [L]
This works just fine since your rewrites are independent of each other.
The second step is to consolidate each group of RewriteRule directives where the forward slash (/) is optional, so instead of:
RewriteRule ^([A-Za-z0-9]+)$ ./web/view/?module=$1
RewriteRule ^([A-Za-z0-9]+)/$ ./web/view/?module=$1
It is just as safe to say:
RewriteRule ^([A-Za-z0-9]+)/?$ ./web/view/?module=$1
The question mark (?) means 0 or 1 but not more than the preceding character, group or expression.
Lastly you may consider optimizing the group of RewriteRule directives:
<IfModule mod_rewrite.c>
Options +FollowSymlinks
RewriteEngine On
RewriteRule ^(admin)($|/) - [L]
RewriteRule ^$ ./web/view/ [L]
RewriteRule ^([A-Za-z0-9]+)/?((([A-Za-z0-9]+)/?)?(([A-Za-z0-9]+)/?)?)?$ ./web/view/?module=$1&id1=$4&id2=$6 [L]
ErrorDocument 404 err.php
</IfModule>
And as bonus information, it may be worth your while to use the QSA (query string append) flag, for example:
RewriteRule ^$ ./web/view/ [L,QSA]
You may also consider using gskinner's RegExr tool to help you create, test or troubleshoot your regular expressions.
Lasty, in your .htaccess file, depending on how the AllowOverrides directive is defined, you may be able to turn on mod_rewrite logging:
RewriteLog "/path/to/your/home/dir/rewrite.log"
RewriteLogLevel 4
However, depending on your apache server version or configuration, you may be required to use the per-module logging configuration since RewriteLog/Level is deprecated:
LogLevel alert rewrite:trace4
As a disclaimer, this level of logging will slow down your webserver, so do not enable it for too long nor on a production environment.

Related

Rewrite rule only if other rules do not apply

I have the following rules:
RewriteRule ^error$ 404.php
RewriteRule ^home$ index.php
Now I want, that everything behind domain.com<> (in the <>) redirects to test.php.
I did
RewriteRule ^([^/]+)$ test.php
and that works but when I enter "error" or "home" it also redirects to test.php instead of to 404.php and index.php
You can REDIRECT_STATUS like this:
RewriteEngine On
RewriteBase /
RewriteRule ^error/?$ 404.php [L,NC]
RewriteRule ^home/?$ index.php [L,NC]
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^ test.php
REDIRECT_STATUS gets set to non-zero value (200) after execution of some rewrite rules.
Try this :
RewriteEngine On
RewriteRule ^error$ 404.php
RewriteRule ^home$ index.php
RewriteCond %{REQUEST_URI} !/(error|home|index|404)
RewriteRule ^([^/]+)$ test.php
The problem is that , you have already captured error and home but when they redirected to 404 or index they being captured again by the last rule so you should exclude them from last rule.
You can tell the rewrite that it has completed when a matching condition is found and therefore not to continue when the condition is met so your rewrites could be something like this:
RewriteEngine On
RewriteBase /
RewriteRule ^error$ 404.php [L,NC]
RewriteRule ^home$ index.php [L,NC]
RewriteRule ^(.*)$ test.php
The 'L' rewrite flag tells the redirect that this is the last condition (i.e. look no further). The 'NC' flag make the rule case insensitive. You can decide if this you also want to include need a R=301 flag or not.
However, I can see a potential issue in the above because once the rules have been processed, the rewritten request is handed back to the URL parsing engine and the rewritten request is handled again by the .htaccess file. This will cause the second last rule to be accepted on the second pass.
The alternative [END] flag, can be used to terminate not only the current round of rewrite processing but prevent any subsequent rewrite processing from occurring in the htaccess context. I will be interested if this works.
Hope this helps.

Need Assistance for this Htaccess Rewrite Rule

I have a problem with my .htaccess, a short explanation I would like to set http://example.com/newest on my website. However, it always redirects to http://example.com/postname. Where I just need the exact "newest" page. Here is my code:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteBase /
RewriteRule ^[^/]+$ %{REQUEST_URI}/ [L,R=301]
RewriteRule ^/category/(.*)$ page.php?f=$1
RewriteRule ^/search/(.*)$ search.php?f=$1
RewriteRule ^(.*)/$ post.php?f=$1 <- If this is removed, my post htaccess will not work
RewriteRule ^newest/$ index.php?f=newest <- I want to execute this code
I really don't know what this is called, I have been looking for the whole stackoverflow but I did not get any answer. Please remain me if this is a duplicate question.
As Mohammed implied in comments, your directives are in the wrong order. The line above your "newest" rewrite is a catch-all and rewrites all requests, so the last line will never match.
http://example.com/newest
Note that your rules imply that your URLs should end in a trailing slash. So, you should be linking to http://example.com/newest/ (with a trailing slash), not http://example.com/newest, otherwise your users will get a lot of unnecessary redirects.
However, you appear to be under the belief that the RewriteCond directive applies to all the directives that follow. This is not the case. It only applies to the first RewriteCond directive. You also need some L flags to prevent further processing.
You also have a slash prefix on the "category" and "search" rewrite patterns, so these would never match in a .htaccess context.
Try something like the following instead:
RewriteEngine On
RewriteBase /
# Don't process the request further if it maps to an existing file
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^ - [L]
# Append trailing if omitted
# Although strictly speaking this only redirects if there are no slashes at all in the URL
RewriteRule ^[^/]+$ %{REQUEST_URI}/ [L,R=301]
RewriteRule ^category/(.*)$ page.php?f=$1 [L]
RewriteRule ^search/(.*)$ search.php?f=$1 [L]
RewriteRule ^newest/$ index.php?f=newest [L]
RewriteRule ^(.*)/$ post.php?f=$1 [L]

SEO Url for Profiles

Preface
I'm trying to re-write a URL for a profile page. All of my application pages have a .html extension, so I'm trying to match just letters, numbers, -, and ..
So these would be valid
site.com/steve
site.com/steve-robbins
site.com/steve.robbins
But these wouldn't be
site.com/steve.html
site.com/steve-robbins.php
Assume I have a check in place so that custom URLs don't have .html or .php on the end.
Problem
I'm currently using this but it's not working
RewriteRule ^([a-zA-Z0-9\.-]+)$ profile.php?url=$1 [L]
It should set url to steve, but it's setting it to profile.php
What am I doing wrong?
My complete .htaccess
Options +FollowSymLinks
RewriteEngine On
RewriteBase /
RewriteCond %{HTTP_HOST} ^[^.]+\.[^.]+$
RewriteRule ^(.*) http://www.%{HTTP_HOST}/$1 [R=301]
#
# LOGIN
#
RewriteRule ^([a-z0-9]{255})/activate\.html$ login.php?activate=$1 [L]
RewriteRule ^logout\.html$ login.php?logout [L]
#
# SETTINGS
#
RewriteRule ^change-([a-z]+)\.html$ account-settings.php?$1 [L]
RewriteRule ^([a-zA-Z0-9\.-]+)$ profile.php?url=$1 [L]
# SEO friendly URLs
RewriteRule ^([a-zA-Z0-9-_.]+)\.html$ $1.php [L]
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /([a-zA-Z0-9-_.]+)\.php
RewriteRule ^([a-zA-Z0-9-_.]+)\.php$ $1.html [R=301]
Add this to the top of your rules (under the RewriteBase / directive):
RewriteCond %{ENV:REDIRECT_STATUS} 200
RewriteRule ^ - [L]
That should stop it from looping. The rewrite engine will keep re-applying all the rules until the URI going in (sans query string) is the same as the URI that comes out of the rules. That's why the value of url is profile.php.
I'm kind of a beginner in interpreting mod_rewrite rules but if I understand it correctly your rule is matched and than matched again, either add something to the url matching scheme like /profile/user or add a condition to not redirect if already redirected
Try adding a leading slash to the redirect like this:
RewriteRule ^([a-zA-Z0-9.-]+)$ /profile.php?url=$1 [L]
The reason you're getting a url value of profile.php is because the [L] flag is kinda misleading when it comes to the .htaccess file. In the server config files it does exactly what you'd think, but in the .htaccess file it stops reading rules at that rule, but then goes through the rules again until path is unchanged by any of the rules. By adding the leading /, your rule will not match the second time around as you exclude / from the regex. I spent a while struggling with this feature myself.

Rewrite rule not working without trailing slash

I have a working rewrite rule to hide index.php?dir= from the URL.So for instance if I try
www.example.com/folder/dir1/
it rewrites it to
www.example.com/folder/index.php?dir=dir1/
and that fine!The trouble is if I remove the trailing slash from the URL i.e.
www.example.com/folder/dir1
it goes into a redirection loop!My complete htaccess is:
Options +FollowSymLinks
RewriteEngine On
RewriteBase /folder
RewriteCond %{ENV:REDIRECT_STATUS} 200
RewriteRule .* - [L]
RewriteCond %{QUERY_STRING} ^dir=(.*)$ [NC]
RewriteRule ^ %1? [L,R=301,NE]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^(.+)/? index.php?dir=$1 [L,QSA]
Please advice?
(i) I am confused about the RewriteBase /papers. This only makes sense in DOCROOT/papers/.htaccess. If this the location and is "folder" == papers? If not then, I am not surprised that the rewrite engine is getting confused. (ii) `%{REDIRECT_STATUS} is not 200 on a subquery lookup to evaluate the default if MultiViews or DirectoryIndex is a match.
So before you do anything else:
Validate that your base is correct, and if not fix it.
Use Options -MultiViews if you don't use them.
Check your system, vhost config and DOCROOT/.htaccess to see if a DirectoryIndex is specified. (Unlike rewrite rules which are only taken from the lowest .htaccess, all are scanned for directives such as this.)
Replace the RewriteCond %{ENV:REDIRECT_STATUS} 200 by
RewriteCond %{ENV:REDIRECT_END}%{IS_SUBREQ} true
and add the flag E=END:true to any rules that you want to force to end of the cycle as a match (similar to the Apache 2.4 [END] flag) The extra %{IS_SUBREQ} prevents the rules being fired on a subquery. You don't want this to happen unless you really know what you are doing.
Figured it out!
Had to replace
RewriteRule ^(.+)/? index.php?dir=$1 [L,QSA]
with
RewriteRule ^(.*)? index.php?dir=$1/ [L,QSA]
Thanks everyone for contributing..

How do I map path components into query parameters using mod_rewrite?

How would I change this:
http://www.mattvisk.com/?page=portfolio&item=rae
To this:
http://www.mattvisk.com/portfolio/rae
Try this:
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_URI} ^/(images/|css/|js/)
RewriteRule . - [S=2]
RewriteRule ^([a-z0-9_\-\.]+)/?$ index.php?page=$1 [L,NC,QSA]
RewriteRule ^([a-z0-9_\-\.]+)/([a-z0-9_\-\.]+)/?$ index.php?page=$1&item=$2 [L,NC,QSA]
Make sure mod_rewrite is enable
edit: I added the dot, poolie had a good point there.
The [S] flag is used to skip rules that you don't want to run. This can be thought of as a goto statement in your rewrite ruleset. In the following example, we only want to run the RewriteRule if the requested URI doesn't correspond with an actual file.

Resources