htaccess rewrite trouble - apache

I'm completely stuck with htaccess rewrites not working on my server. It's a basic index.php rewrite for Codeigniter, and works fine when developing on my Mac but fails on my server (CentOS, Apache 2, WHM)
RewriteEngine on
RewriteCond $1 !^(index\.php|images|css|js|robots\.txt)
RewriteRule ^(.*)$ /index.php/$1 [L]
Attempting to load /about/ will display the index.php page. /index.php/about will display the correct page. I've tried every combination of options I can think of to no avail. A sample of my rewrite.log is below.
[dev.tirius.co.uk/sid#5d65288][rid#5e37c00/initial] (3) [per-dir /home/tirius/subdomains/dev/public_html/] add path info postfix: /home/tirius/subdomains/dev/public_html/about -> /home/tirius/subdomains/dev/public_html/about/
[dev.tirius.co.uk/sid#5d65288][rid#5e37c00/initial] (3) [per-dir /home/tirius/subdomains/dev/public_html/] strip per-dir prefix: /home/tirius/subdomains/dev/public_html/about/ -> about/
[dev.tirius.co.uk/sid#5d65288][rid#5e37c00/initial] (3) [per-dir /home/tirius/subdomains/dev/public_html/] applying pattern '^(.*)$' to uri 'about/'
[dev.tirius.co.uk/sid#5d65288][rid#5e37c00/initial] (2) [per-dir /home/tirius/subdomains/dev/public_html/] rewrite about/ -> /index.php/about/
[dev.tirius.co.uk/sid#5d65288][rid#5e37c00/initial] (1) [per-dir /home/tirius/subdomains/dev/public_html/] internal redirect with /index.php/about/ [INTERNAL REDIRECT]
[dev.tirius.co.uk/sid#5d65288][rid#5e3f7c8/initial/redir#1] (3) [per-dir /home/tirius/subdomains/dev/public_html/] add path info postfix: /home/tirius/subdomains/dev/public_html/index.php -> /home/tirius/subdomains/dev/public_html/index.php/about/
[dev.tirius.co.uk/sid#5d65288][rid#5e3f7c8/initial/redir#1] (3) [per-dir /home/tirius/subdomains/dev/public_html/] strip per-dir prefix: /home/tirius/subdomains/dev/public_html/index.php/about/ -> index.php/about/
[dev.tirius.co.uk/sid#5d65288][rid#5e3f7c8/initial/redir#1] (3) [per-dir /home/tirius/subdomains/dev/public_html/] applying pattern '^(.*)$' to uri 'index.php/about/'
[dev.tirius.co.uk/sid#5d65288][rid#5e3f7c8/initial/redir#1] (1) [per-dir /home/tirius/subdomains/dev/public_html/] pass through /home/tirius/subdomains/dev/public_html/index.php
As you can see, the htaccess is picked up and mod_rewrite is enabled and working, but nothing seems to be being appended to index.php
This must be an Apache configuration issue but I'm really lost as to what it could be.
Sample from httpd.conf
<Directory "/">
Options ExecCGI FollowSymLinks IncludesNOEXEC Indexes MultiViews SymLinksIfOwnerMatch
AllowOverride All
</Directory>

This is my .htaccess on CentOS:
RewriteCond $1 !^(index\.php|images|robots\.txt|favicon\.ico)
RewriteRule ^(.*)$ index.php?/$1 [L]
Note the question-mark before the forward-slash.
I think the reason for this relates to running PHP as FastCGI. I believe the questionmark makes the preceding character optional (i.e. it would also match index.ph). I've tried researching this a bit more but couldn't find a definitive reason. I think I just tried every variation on the rewriterule I could find when I was looking and didn't bother asking why it worked.
Glad to be of help.

Related

How to redirect URL with htaccess (RewriteRule) and prevent direct access

using .htaccess I'd like to transparently redirect requests for folder "old" to folder "new", and in the same time prevent direct access to folder "new":
desired result:
http://example.com/old/... -> will display what's in "new" (no URL change in browser!)
http://example.com/new/... -> no access
this is my code in .htaccess (the 1st line is here because several domains share the same root folder):
RewriteCond %{HTTP_HOST} ^example\.com$ [NC]
RewriteRule ^old(.*)$ new$1 [L]
RewriteRule ^new(.*)$ - [F]
Well, what happens is that the 3d line triggers because of the substitution in the 2nd. I was convinced that the flag "L" would prevent this from happening (end of processing), but it seems that's not the case.
Do you have any suggestions what needs to be done (I tried to debug with rewrite log, but without success)?
I did some logging and found the following:
[rid#d0ac98/initial] (3) [per-dir C:/www/example/] add path info postfix: C:/www/example/new -> C:/www/example/new/
[rid#d0ac98/initial] (3) [per-dir C:/www/example/] strip per-dir prefix: C:/www/example/new/ -> new/
[rid#d0ac98/initial] (3) [per-dir C:/www/example/] applying pattern '^new(.*)$' to uri 'new/'
[rid#d0ac98/initial] (4) RewriteCond: input='localhost' pattern='^example\.com$' => not-matched
[rid#d0ac98/initial] (4) RewriteCond: input='localhost' pattern='^localhost$' => matched
[rid#d0ac98/initial] (2) [per-dir C:/www/example/] rewrite new/ -> old/
[rid#d0ac98/initial] (3) [per-dir C:/www/example/] add per-dir prefix: old/ -> C:/www/example/old/
[rid#d0ac98/initial] (2) [per-dir C:/www/example/] strip document_root prefix: C:/www/example/old/ -> /example/old/
[rid#d0ac98/initial] (1) [per-dir C:/www/example/] internal redirect with /example/old/ [INTERNAL REDIRECT]
[rid#d217a8/initial/redir#1] (3) [per-dir C:/www/example/] strip per-dir prefix: C:/www/example/old/ -> old/
[rid#d217a8/initial/redir#1] (3) [per-dir C:/www/example/] applying pattern '^new(.*)$' to uri 'old/'
[rid#d217a8/initial/redir#1] (3) [per-dir C:/www/example/] strip per-dir prefix: C:/www/example/old/ -> old/
[rid#d217a8/initial/redir#1] (3) [per-dir C:/www/example/] applying pattern '^old(.*)$' to uri 'old/'
[rid#d217a8/initial/redir#1] (2) forcing 'C:/www/example/old/' to be forbidden
This seems an internal redirect, which causes the "forbidden" result. Indeed, the documentation mentions it:
It is therefore important, if you are using RewriteRule directives in one of these contexts, that you take explicit steps to avoid rules looping, and not count solely on the [L] flag to terminate execution of a series of rules, as shown below. An alternative flag, [END], can be used to terminate not only the current round of rewrite processing but prevent any subsequent rewrite processing from occurring in per-directory (htaccess) context. This does not apply to new requests resulting from external redirects...
So I suppose that in my example the error was due to the fact that I used "L" flag instead the "END" flag?
I found an alternative solution (3rd line is inserted here):
RewriteCond %{HTTP_HOST} ^example\.com$ [NC]
RewriteRule ^old(.*)$ new$1 [L]
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^new(.*)$ - [F]
The 4th line will be executed only if there's no internal redirect.
You can use:
RewriteEngine On
# if directly requesting /new then block it
RewriteCond %{THE_REQUEST} \s/+new(/\S*)?\s [NC]
RewriteRule ^ - [F]
# forward /old/abc to /new/abc
RewriteCond %{HTTP_HOST} ^(www\.)?example\.com$ [NC]
RewriteRule ^old(/.*)?$ new$1 [L,NC]
We used THE_REQUEST in first rule. THE_REQUEST variable represents original request received by Apache from your browser and it doesn't get overwritten after execution of some rewrite rules. REQUEST_URI on the other hand changes its value after other rewrite rules.
For the same reason your rule RewriteRule ^new(.*)$ - [F] will even block your request from /old/ since first rule changes URI to /new/.

Mod Rewrite is giving me a hard time

I'm currently using wamp on windows 7. I'd like to clean my urls obviously. I've tried to find the current syntax and what not, but I haven't figured it out.
My path right now is localhost/rs/index.php
When I go to localhost/rs/user it gives me a 404, but localhost/rs/ gives me the index.php page.
This is what I have in my .htaccess file at the www directory of wamp.
RewriteEngine On
RewriteRule ^/$ index.php
RewriteRule ^/([a-z]+)$ index.php?page=$1
RewriteRule ^/([a-z]+)/$ index.php?page=$1
I have un-commented the line
LoadModule rewrite_module modules/mod_rewrite.so
in the httpd.conf file of Apache
What's wrong? Is my .htaccess file in the wrong spot? Is my syntax wrong?
Thanks!
Place your .htaccess in /rs folder and try
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([A-Za-z0-9]*)/?$ index.php?page=$1 [L]
Hope this will help
Your .htaccess file should be placed in '/rs' folder, in the same directory where index.php is.
I've tried with enabled rewrite log, and what I saw there, when tried to access localhost/test/user:
::1 - - [12/Oct/2012:09:53:11 +0400] [localhost/sid#68a898][rid#1cc4d48/initial] (3) [perdir D:/Development/htdocs/test/] strip per-dir prefix: D:/Development/htdocs/test/user -> user
::1 - - [12/Oct/2012:09:53:11 +0400] [localhost/sid#68a898][rid#1cc4d48/initial] (3) [perdir D:/Development/htdocs/test/] applying pattern '^/$' to uri 'user'
::1 - - [12/Oct/2012:09:53:11 +0400] [localhost/sid#68a898][rid#1cc4d48/initial] (3) [perdir D:/Development/htdocs/test/] strip per-dir prefix: D:/Development/htdocs/test/user -> user
::1 - - [12/Oct/2012:09:53:11 +0400] [localhost/sid#68a898][rid#1cc4d48/initial] (3) [perdir D:/Development/htdocs/test/] applying pattern '^/([a-z]+)$' to uri 'user'
::1 - - [12/Oct/2012:09:53:11 +0400] [localhost/sid#68a898][rid#1cc4d48/initial] (3) [perdir D:/Development/htdocs/test/] strip per-dir prefix: D:/Development/htdocs/test/user -> user
::1 - - [12/Oct/2012:09:53:11 +0400] [localhost/sid#68a898][rid#1cc4d48/initial] (3) [perdir D:/Development/htdocs/test/] applying pattern '^/([a-z]+)/$' to uri 'user'
::1 - - [12/Oct/2012:09:53:11 +0400] [localhost/sid#68a898][rid#1cc4d48/initial] (1) [perdir D:/Development/htdocs/test/] pass through D:/Development/htdocs/test/user
From the first line it is clear, that mod_rewrite is stripping beginning '/', and you are getting 'user' instead of '/user'. So, rewrite rules should be written without '/', that is:
RewriteEngine On
RewriteRule ^$ index.php
RewriteRule ^([a-z]+)/?$ index.php?page=$1
Also notice, that I've combined two last rules by writing '/?'. That means '/' symbol at the end of url is optional.
In order to turn on rewrite log, set the following in your httd.conf file:
#
# Logging for mod_rewrite
# Use RewriteLogLevel 3 only for debug purposes
# Normally use RewriteLogLevel 0
#
<IfModule rewrite_module>
RewriteLogLevel 3
RewriteLog "logs/rewrite.log"
</IfModule>
That way log will be created in logs/rewrite.log file. And this is usually the best way to examine what goes wrong.
If you're running it in subfolder you need to add this line after RewriteEngine On
RewriteBase /rs
Also, make sure that in your apache virtual host section has this value
AllowOverride All

Why doesn't the RewriteCond prevent the RewriteRule from processing?

I've got the following in my .conf file used for cache busting js:
<Directory "/www/virtual/site/html/js/">
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^\d+\/(.+)$ $1 [L]
</Directory>
The idea here is to rewrite site.com/js/123456/script.js to site.com/js/script.js
(The rewriting works just fine)
If I look at the rewrite log the part I'm not understanding is that it is applying the RewriteRule to the script after the interal redirect... Shouldn't the %{REQUEST_FILENAME} !-f prevent it from processing the RewriteRule since the file exists?
Rewrite Log
[rid#2b607f8f2dc8/initial] (3) [perdir /www/virtual/site2/html/js/] add path info postfix: /www/virtual/site2/html/js/1234 -> /www/virtual/site2/html/js/1234/script.js
[rid#2b607f8f2dc8/initial] (3) [perdir /www/virtual/site2/html/js/] strip per-dir prefix: /www/virtual/site2/html/js/1234/script.js -> 1234/script.js
[rid#2b607f8f2dc8/initial] (3) [perdir /www/virtual/site2/html/js/] applying pattern '^\d+\/(.+)$' to uri '1234/script.js'
[rid#2b607f8f2dc8/initial] (2) [perdir /www/virtual/site2/html/js/] rewrite '1234/script.js' -> 'script.js'
[rid#2b607f8f2dc8/initial] (3) [perdir /www/virtual/site2/html/js/] add per-dir prefix: script.js -> /www/virtual/site2/html/js/script.js
[rid#2b607f8f2dc8/initial] (2) [perdir /www/virtual/site2/html/js/] strip document_root prefix: /www/virtual/site2/html/js/script.js -> /js/script.js
[rid#2b607f8f2dc8/initial] (1) [perdir /www/virtual/site2/html/js/] internal redirect with /js/script.js [INTERNAL REDIRECT]
[rid#2b6073eb14a8/initial/redir#1] (3) [perdir /www/virtual/site2/html/js/] strip per-dir prefix: /www/virtual/site2/html/js/script.js -> script.js
[rid#2b6073eb14a8/initial/redir#1] (3) [perdir /www/virtual/site2/html/js/] applying pattern '^\d+\/(.+)$' to uri 'script.js'
[rid#2b6073eb14a8/initial/redir#1] (1) [perdir /www/virtual/site2/html/js/] pass through /www/virtual/site2/html/js/script.js
mod_rewrite (by design) keeps on applying rewrite-rules, till the url no longer changes.
So the first time it rewrite 1234/script.js to script.js the second time it tries to apply the rule, the pattern regular expression doesn't match and script.js is 'passed through'.
This is the way it is supposed to work. It can sometimes be a pain, but it makes mod_rewrite a lot more powerful/useful.
edit
mod_rewite first tests the RewriteRule pattern, before trying to apply the RewriteCond's. This is so you can use backreferences $0, $1 etc. in your RewriteCond. After all the RewriteCond's it will create the substitution string, so it can also use backrefereces %0, %1. etc. See also the diagram below.
So this is why it tried to apply the pattern before testing if the file exists.

Help understanding rewrite log (want to internally rewrite a page when requested from specific HTTP_HOST)

I have a Drupal site, site.com, and our client has a campaign that they're promoting for which they've bought a new domain name, campaign.com. I'd like it so that a request for campaign.com internally rewrites to a particular page of the Drupal site. Note Drupal uses an .htaccess file in the document root.
The normal Drupal rewrite is
# Rewrite URLs of the form 'x' to the form 'index.php?q=x'.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !=/favicon.ico
RewriteRule ^(.*)$ index.php?q=$1 [L,QSA]
I added the following before the normal rewrite.
# Custom URLS (eg. microsites) go here
RewriteCond %{HTTP_HOST} =campaign.com
RewriteCond %{REQUEST_URI} =/
RewriteRule ^ index.php?q=node/22 [L]
Unfortunately it doesn't work, it just shows the homepage. Turning on the rewrite log I get this.
1. [rid#2da8ea8/initial] (3) [perdir D:/wamp/www/] strip per-dir prefix: D:/wamp/www/ ->
2. [rid#2da8ea8/initial] (3) [perdir D:/wamp/www/] applying pattern '^' to uri ''
3. [rid#2da8ea8/initial] (2) [perdir D:/wamp/www/] rewrite '' -> 'index.php?q=node/22'
4. [rid#2da8ea8/initial] (3) split uri=index.php?q=node/22 -> uri=index.php, args=q=node/22
5. [rid#2da8ea8/initial] (3) [perdir D:/wamp/www/] add per-dir prefix: index.php -> D:/wamp/www/index.php
6. [rid#2da8ea8/initial] (2) [perdir D:/wamp/www/] strip document_root prefix: D:/wamp/www/index.php -> /index.php
7. [rid#2da8ea8/initial] (1) [perdir D:/wamp/www/] internal redirect with /index.php [INTERNAL REDIRECT]
8. [rid#2da7770/initial/redir#1] (3) [perdir D:/wamp/www/] strip per-dir prefix: D:/wamp/www/index.php -> index.php
9. [rid#2da7770/initial/redir#1] (3) [perdir D:/wamp/www/] applying pattern '^' to uri 'index.php'
10.[rid#2da7770/initial/redir#1] (3) [perdir D:/wamp/www/] strip per-dir prefix: D:/wamp/www/index.php -> index.php
11.[rid#2da7770/initial/redir#1] (3) [perdir D:/wamp/www/] applying pattern '^(.*)$' to uri 'index.php'
12.[rid#2da7770/initial/redir#1] (1) [perdir D:/wamp/www/] pass through D:/wamp/www/index.php
I'm not used to mod_rewrite, so I might be missing something, but comparing the logs from a call to http://site.com/node/3 and from http://campaign.com/ I can't see any meaningful difference. Specifically uri and args on line 4 seem correct, the internal redirect on line 7 seems right, and the pass through on line 12 seems right (because the file index.php exists). But for some reason it seems the query string's been discarded/ignored around the time of the internal redirect. I'm completely stumped.
Also, if anyone could provide a reference on understanding the rewrite log, that might help. It'd be great if there's a way to track the query string through the internal redirect.
FWIW I'm using WampServer 2.1 with Apache 2.2.17.
Thanks for asking this question, it's something that I need to do too. I don't know the way to do this by means of the .htaccess, and hope that someone here can answer that.
But I do the same thing by using Drupal's menu system with this code in a custom module:
function mymodule_menu() {
$items = array();
$items['domain_redirect'] = array(
'page callback' => 'domain_redirect',
'type' => MENU_NORMAL_ITEM,
'access arguments' => array('access content'),
);
return $items;
}
function domain_redirect() {
switch ($_SERVER['SERVER_NAME'])
{
case "campaign.com":
$goto = "node/22";
break;
default:
$goto = "/";
}
drupal_goto($goto);
}
Then set the frontpage to domain_redirect.

A mod_rewrite problem

I'm trying to implement the following mod_rewrite rule:
host.com/developer/ => host.com/developer/index.py
host.com/developer/branchX => host.com/developer/index.py?branch=branchX
host.com/developer/branchX/commitY => host.com/developer/index.py?branch=branchX&commit=commitY
Currently, the appropriate config section looks like this:
Options FollowSymLinks
AllowOverride None
RewriteEngine on
RewriteRule ^([^/]+)$ /$1/index.py [L]
RewriteRule ^([^/]+)/([^/]+) /$1/index.py?branch=$2 [L]
RewriteRule ^([^/]+)/([^/]+)/([^/]+)$ /$1/index.py?branch=$2&commit=$3 [L]
However, after the URL has been initially rewritten, an internal redirect occurs and the URL is being rewritten again, ruining it. The process repeats many times and eventually results into a 500 error. The log (timestamps and perdir parts removed):
[..initial] (3) strip per-dir prefix: /home/www/host.com/master/a -> master/a
[..initial] (3) applying pattern '^([^/]+)$' to uri 'master/a'
[..initial] (3) strip per-dir prefix: /home/www/host.com/master/a -> master/a
[..initial] (3) applying pattern '^([^/]+)/([^/]+)' to uri 'master/a'
[..initial] (2) rewrite 'master/a' -> '/master/index.py?branch=a'
[..initial] (3) split uri=/master/index.py?branch=a -> uri=/master/index.py, args=branch=a
[..initial] (1) internal redirect with /master/index.py [INTERNAL REDIRECT]
[..initial/redir#1] (3) strip per-dir prefix: /home/www/host.com/master/index.py -> master/index.py
[..initial/redir#1] (3) applying pattern '^([^/]+)$' to uri 'master/index.py'
[..initial/redir#1] (3) strip per-dir prefix: /home/www/host.com/master/index.py -> master/index.py
[..initial/redir#1] (3) applying pattern '^([^/]+)/([^/]+)' to uri 'master/index.py'
[..initial/redir#1] (2) rewrite 'master/index.py' -> '/master/index.py?branch=index.py'
[..initial/redir#1] (3) split uri=/master/index.py?branch=index.py -> uri=/master/index.py, args=branch=index.py
How can I fix my rules to prevent the endless internal redirects?
Thanks.
The problem is that the url you are rewriting to is matched in the next pass. L specifies the last rule but only for this execution of the rules, URLs are processed again under certain circumstances (in this case, internal redirects). The solution is to add a RewriteCond to prevent looping, like this:
RewriteEngine on
RewriteCond %{REQUEST_URI} !index\.py
RewriteRule ^([^/]+)$ /$1/index.py [L]
RewriteCond %{REQUEST_URI} !index\.py
RewriteRule ^([^/]+)/([^/]+) /$1/index.py?branch=$2 [L]
RewriteCond %{REQUEST_URI} !index\.py
RewriteRule ^([^/]+)/([^/]+)/([^/]+)$ /$1/index.py?branch=$2&commit=$3 [L]