htaccess canonical URL subdirectory - apache

I have the same problem as htaccess - canonical URL when redirecting to subdirectory, but the solution there appears to use a hardcoded host name in the htaccess file which I can't do.
The following is in my htaccess file in the root directory which works fine for redirecting all requests into the /public directory with the exception of node_modules:
<IfModule mod_rewrite.c>
RewriteEngine on
# Allow node_modules
RewriteRule ^node_modules($|/) - [L]
# Rewrite everything to public
RewriteRule ^(.*)$ public/$1 [L,QSA]
</IfModule>
However I realize that the pages can be accessed through two different URLs, for example:
https://localhost/application1/foo/books.php
https://localhost/application1/public/foo/books.php
How do I either prevent the second one (ideally) or have it redirect to the first one?
I tried various RewriteCond statements with %{THE_REQUEST} but they turned out to be infinite loops. As mentioned above this needs to be hostname-agnostic as the application runs on different environments.
Update
I tried #SuperDuperApps answer below with the following in my .htaccess, which seemed to make no difference:
RewriteEngine on
RewriteCond $1 !^node_modules($|/)
RewriteCond $1 !^public($|/)
RewriteRule ^(.*)$ public/$1 [L,QSA]
RewriteRule ^public/ - [L,R=404]
After enabling RewriteLogLevel 3 in my dev server, this is what appears when I access a file with /public in the URL:
192.168.33.1 - - [27/Jan/2017:22:52:45 --0500] [localhost/sid#7f4a0d1d2cf0][rid#7f4a0d6a5d58/initial] (1) [perdir /var/www/html/application1/public/] pass through /var/www/html/application1/public/common/assets/js/nav.min.js
And this is when I access the same file without /public in the URL (desired behaviour):
192.168.33.1 - - [27/Jan/2017:22:48:45 --0500] [localhost/sid#7f4a0d1d2cf0][rid#7f4a0d684738/initial] (3) [perdir /var/www/html/application1/] add path info postfix: /var/www/html/application1/common -> /var/www/html/application1/common/assets/js/nav.min.js
192.168.33.1 - - [27/Jan/2017:22:48:45 --0500] [localhost/sid#7f4a0d1d2cf0][rid#7f4a0d684738/initial] (3) [perdir /var/www/html/application1/] strip per-dir prefix: /var/www/html/application1/common/assets/js/nav.min.js -> common/assets/js/nav.min.js
192.168.33.1 - - [27/Jan/2017:22:48:45 --0500] [localhost/sid#7f4a0d1d2cf0][rid#7f4a0d684738/initial] (3) [perdir /var/www/html/application1/] applying pattern '^(.*)$' to uri 'common/assets/js/nav.min.js'
192.168.33.1 - - [27/Jan/2017:22:48:45 --0500] [localhost/sid#7f4a0d1d2cf0][rid#7f4a0d684738/initial] (2) [perdir /var/www/html/application1/] rewrite 'common/assets/js/nav.min.js' -> 'public/common/assets/js/nav.min.js'
192.168.33.1 - - [27/Jan/2017:22:48:45 --0500] [localhost/sid#7f4a0d1d2cf0][rid#7f4a0d684738/initial] (3) [perdir /var/www/html/application1/] add per-dir prefix: public/common/assets/js/nav.min.js -> /var/www/html/application1/public/common/assets/js/nav.min.js
192.168.33.1 - - [27/Jan/2017:22:48:45 --0500] [localhost/sid#7f4a0d1d2cf0][rid#7f4a0d684738/initial] (2) [perdir /var/www/html/application1/] strip document_root prefix: /var/www/html/application1/public/common/assets/js/nav.min.js -> /application1/public/common/assets/js/nav.min.js
192.168.33.1 - - [27/Jan/2017:22:48:45 --0500] [localhost/sid#7f4a0d1d2cf0][rid#7f4a0d684738/initial] (1) [perdir /var/www/html/application1/] internal redirect with /application1/public/common/assets/js/nav.min.js [INTERNAL REDIRECT]
192.168.33.1 - - [27/Jan/2017:22:48:45 --0500] [localhost/sid#7f4a0d1d2cf0][rid#7f4a0d676688/initial/redir#1] (1) [perdir /var/www/html/application1/public/] pass through /var/www/html/application1/public/common/assets/js/nav.min.js

This should do it:
RewriteEngine on
# Allow node_modules
RewriteCond $1 !^node_modules($|/)
# Rewrite everything to public except public
RewriteCond $1 !^public($|/)
RewriteRule ^(.*)$ public/$1 [L,QSA]
# 404 diret access to public
RewriteRule ^public/ - [L,R=404]

Got it working with two separate files.
.htaccess:
<IfModule mod_rewrite.c>
RewriteEngine on
# Allow node_modules
RewriteRule ^node_modules($|/) - [L]
# Rewrite everything to public
RewriteRule ^(.*)$ public/$1 [L,QSA]
</IfModule>
.htaccess inside public:
<IfModule mod_rewrite.c>
RewriteEngine on
# pass-through if another rewrite rule has been applied already
RewriteCond %{ENV:REDIRECT_STATUS} 200
RewriteRule .* - [S=1] # Skip the next rule
RewriteRule ^ - [L,R=404]
# ...additional rules here as needed
</IfModule>
[L] can have been used instead of [S=1] in the second file if there are no additional rules.
This question gave me the idea with "pass-through if redirect".
Also thanks to #SuperDuperApps for the debugging hint with RewriteLogLevel and the original answer with the [END] flag that may have worked if I had Apache 2.4.

Related

Rewrite subdomain to subdirectory in Apache .htaccess file

Suppose I have a domain called example.com and I want to use rewrite rules in the .htaccess file of Apache to rewrite:
https://office.example.com/index.html
to
https://example.com/office/index.html.
How would I do that? I checked lots of answers here, and the solution seems to be something like this:
RewriteEngine on
RewriteCond %{HTTP_HOST} ^office.example.com$
RewriteRule ^(.*)$ https://example.com/office/$1 [L,NC,QSA]
This works when I test it here:
https://htaccess.madewithlove.be?share=b40ca72f-86d3-5452-a04b-ac9f24812c57
Regrettably, it does generate an error 500 on my server. I enabled logging and found that this seems to be a recursion problem:
AH00124: Request exceeded the limit of 10 internal redirects.
In the logs it seems to add office to office endlessly: /office/office/office/.... I have no idea why this is happening. The rewritten URL doesn't meet the rewrite condition, so why would it do this?
I have found a way to make it "work". If I add R=301 to the RewriteRule attributes it does a redirect, and works, but I would prefer if the original URL remained in the address bar.
Here's the log for the first 2 redirects:
init rewrite engine with requested uri /
applying pattern '^(.*)$' to uri '/'
applying pattern '^(.*)$' to uri '/'
applying pattern '^(.*)$' to uri '/'
pass through /
[perdir /var/www/vhosts/example.com/httpdocs/] strip per-dir prefix: /var/www/vhosts/example.com/httpdocs/ ->
[perdir /var/www/vhosts/example.com/httpdocs/] applying pattern '^(.*)$' to uri ''
[perdir /var/www/vhosts/example.com/httpdocs/] rewrite '' -> 'https://example.com/office/'
reduce https://example.com/office/ -> /office/
[perdir /var/www/vhosts/example.com/httpdocs/] internal redirect with /office/ [INTERNAL REDIRECT]
#1 init rewrite engine with requested uri /office/
#1 applying pattern '^(.*)$' to uri '/office/'
#1 applying pattern '^(.*)$' to uri '/office/'
#1 applying pattern '^(.*)$' to uri '/office/'
#1 pass through /office/
#1 [perdir /var/www/vhosts/example.com/httpdocs/] strip per-dir prefix: /var/www/vhosts/example.com/httpdocs/office/
#1 [perdir /var/www/vhosts/example.com/httpdocs/] applying pattern '^(.*)$' to uri 'office/'
#1 [perdir /var/www/vhosts/example.com/httpdocs/] rewrite 'office/' -> 'https://example.com/office/office/'
#1 reduce https://example.com/office/office/ -> /office/office/
#1 [perdir /var/www/vhosts/example.com/httpdocs/] internal redirect with /office/office/ [INTERNAL REDIRECT]
#2 init rewrite engine with requested uri /office/office/
#2 applying pattern '^(.*)$' to uri '/office/office/'
#2 applying pattern '^(.*)$' to uri '/office/office/'
#2 applying pattern '^(.*)$' to uri '/office/office/'
#2 pass through /office/office/
#2 [perdir /var/www/vhosts/example.com/httpdocs/] add path info postfix: /var/www/vhosts/example.com/httpdocs/office
#2 [perdir /var/www/vhosts/example.com/httpdocs/] strip per-dir prefix: /var/www/vhosts/example.com/httpdocs/office/
#2 [perdir /var/www/vhosts/example.com/httpdocs/] applying pattern '^(.*)$' to uri 'office/office/'
#2 [perdir /var/www/vhosts/example.com/httpdocs/] rewrite 'office/office/' -> 'https://example.com/office/office/off
#2 reduce https://example.com/office/office/office/ -> /office/office/office/
#2 [perdir /var/www/vhosts/example.com/httpdocs/] internal redirect with /office/office/office/ [INTERNAL REDIRECT]
RewriteCond %{HTTP_HOST} ^office.example.com$
RewriteRule ^(.*)$ https://example.com/office/$1 [L,NC,QSA]
Rather confusing, this should implicitly trigger an external 302 (temporary) redirect, not an internal rewrite - when specifying a different host in the substitution string to the one being requested. (Although in my experience, any absolute URL in the substitution string triggers an external redirect.)
If it does trigger an internal rewrite (as indicated by the logs) then the requested hostname does not change (since this is not a separate request) and you will indeed get a rewrite loop.
However, if "the subdomain is an alias of the main domain" and a rewrite is what's required, then there is no need to specify a hostname in the substitution string and you will indeed need to make additional checks to prevent an internal rewrite loop (500 error).
Try the following instead:
RewriteEngine on
RewriteCond %{HTTP_HOST} ^office\.example\.com [NC]
RewriteRule !^office office%{REQUEST_URI} [L]
...to exclude any requests (including rewritten requests) that already start /office.
No need for the NC and QSA flags.
Alternatively, to only target direct requests (not rewritten requests) you could check the REDIRECT_STATUS environment variable instead (which is empty on the initial request and set to "200", as in 200 OK, after the first successful rewrite).
For example:
RewriteCond %{HTTP_HOST} ^office\.example\.com [NC]
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule (.*) office/$1 [L]
This has the added "benefit" that you can potentially have a sub-subdirectory called /office as well. ie. /office/office.
UPDATE: A third version is to check against the REQUEST_URI server variable. However, I would not expect this to be any different from the first version above.
RewriteCond %{HTTP_HOST} ^office\.example\.com [NC]
RewriteCond %{REQUEST_URI} !^/office
RewriteRule ^ office%{REQUEST_URI} [L]
Sadly enough, both your suggestions gave the same error as before.
Two things to try...
Add a slash prefix on the substitution string. ie. /office%{REQUEST_URI} and /office/$1 respectively. This changes the substitution string into a URL-path, rather than a relative filesystem path. However, I wouldn't necessarily expect this to make any difference in this respect. (It would be required for an external redirect.)
Use the END flag instead of L on the RewriteRule directives - this is an Apache 2.4 addition that should halt all processing. The L flag "only" ends the current pass before restarting the rewriting process (hence the need for additional checks to prevent rewrite loops).
But now any other file (IMG, CSS) gives an 404.
The above rewrites everything, so it will naturally rewrite all static resources if they don't already start /office. (If they already start /office then they should already be excluded by the above rules.)
To exclude common resources, you could make an exception (an additional RewriteCond directive) to exclude specific file extensions. For example:
RewriteCond %{REQUEST_URI} !\.(css|js|png|jpg|gif)$
And/or add an additional RewriteCond directive to exclude requests that already map to physical files (although this is "marginally" more expensive). For example:
RewriteCond %{REQUEST_FILENAME} !-f
Summary:
RewriteEngine On
RewriteCond %{HTTP_HOST} ^office\.example\.com [NC]
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{REQUEST_URI} !\.(css|js|png|jpg|gif)$
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule (.*) office/$1 [END]

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/.

Apache Mod Rewrite for Pretty URLs isn't working

I'm trying to figure out how to do an apache mod_rewrite to remap $_GET.
What I'm trying to accomplish:
Currently, to get to the page one would have to go to
http://www.domain.com/index.php?URL=pages/the-page.php
I would like this to work in 2 ways:
If someone goes to domain.com/the-page, it takes them to the above but keeps it looking like this. Secondly, if someone goes to the http://www.domain.com/index.php?URL=pages/the-page.php, it will still show as domain.com/the-page, keeping the URL short and clean.
Most Recently Tried Code
Options +FollowSymlinks
RewriteEngine on
RewriteCond %{REQUEST_URI} ^/index\.php$
RewriteCond %{QUERY_STRING} URL=pages/([a-z0-9-_]+)\.php$
RewriteRule ^(.*) /%1
I'm pretty sure I setup everything right in the apache httpd.conf. I'm using XAMPP to test locally, restarted apache on changes, still nothing. Where am I going wrong?
I would prefer to handle this in .htaccess
I am using XAMPP localhost and trying on live server.
Log File:
127.0.0.1 - - [05/Apr/2013:16:50:43 --0400] [localhost/sid#2f3140][rid#3b14068/initial] (3) [perdir C:/xampp/htdocs/cdi/] strip per-dir prefix: C:/xampp/htdocs/cdi/index.php -> index.php
127.0.0.1 - - [05/Apr/2013:16:50:43 --0400] [localhost/sid#2f3140][rid#3b14068/initial] (3) [perdir C:/xampp/htdocs/cdi/] applying pattern '^(.*)' to uri 'index.php'
127.0.0.1 - - [05/Apr/2013:16:50:43 --0400] [localhost/sid#2f3140][rid#3b14068/initial] (1) [perdir C:/xampp/htdocs/cdi/] pass through C:/xampp/htdocs/cdi/index.php
Updated log with Olaf's script (last rule commented out)
127.0.0.1 - - [05/Apr/2013:20:02:24 --0400] [localhost/sid#2e3140][rid#3b14090/initial] (3) [perdir C:/xampp/htdocs/cdi/] strip per-dir prefix: C:/xampp/htdocs/cdi/index.php -> index.php
127.0.0.1 - - [05/Apr/2013:20:02:24 --0400] [localhost/sid#2e3140][rid#3b14090/initial] (3) [perdir C:/xampp/htdocs/cdi/] applying pattern '^' to uri 'index.php'
127.0.0.1 - - [05/Apr/2013:20:02:24 --0400] [localhost/sid#2e3140][rid#3b14090/initial] (3) [perdir C:/xampp/htdocs/cdi/] strip per-dir prefix: C:/xampp/htdocs/cdi/index.php -> index.php
127.0.0.1 - - [05/Apr/2013:20:02:24 --0400] [localhost/sid#2e3140][rid#3b14090/initial] (3) [perdir C:/xampp/htdocs/cdi/] applying pattern '^index\.php$' to uri 'index.php'
127.0.0.1 - - [05/Apr/2013:20:02:24 --0400] [localhost/sid#2e3140][rid#3b14090/initial] (2) [perdir C:/xampp/htdocs/cdi/] rewrite 'index.php' -> '/newhome?'
127.0.0.1 - - [05/Apr/2013:20:02:24 --0400] [localhost/sid#2e3140][rid#3b14090/initial] (3) split uri=/newhome? -> uri=/newhome, args=<none>
127.0.0.1 - - [05/Apr/2013:20:02:24 --0400] [localhost/sid#2e3140][rid#3b14090/initial] (2) [perdir C:/xampp/htdocs/cdi/] explicitly forcing redirect with http://localhost/newhome <--this one seems to be causing the issue
127.0.0.1 - - [05/Apr/2013:20:02:24 --0400] [localhost/sid#2e3140][rid#3b14090/initial] (1) [perdir C:/xampp/htdocs/cdi/] escaping http://localhost/newhome for redirect
127.0.0.1 - - [05/Apr/2013:20:02:24 --0400] [localhost/sid#2e3140][rid#3b14090/initial] (1) [perdir C:/xampp/htdocs/cdi/] redirect to http://localhost/newhome [REDIRECT/302]
Thank you everyone that is helping. I've spent 2 days trying to get this to work!!!
Basically, you need two rules. One rule to redirect the client to a clean URL and another to internally rewrite the pretty URL to the real content via index.php.
Assuming the index.php and .htaccess is in a directory cdi
RewriteEngine on
# prevent endless loop
RewriteCond %{ENV:REDIRECT_STATUS} 200
RewriteRule ^ - [L]
# redirect the client
RewriteCond %{QUERY_STRING} URL=pages/(.+?)\.php
RewriteRule ^index\.php$ /cdi/%1? [R,L]
# exclude rewriting all files located in /cdi/files
RewriteCond %{REQUEST_URI} !^/cdi/files/
# rewrite to real content
RewriteRule ^.*$ /cdi/index.php?URL=pages/$0.php [L]
Update:
When the request is /cdi/index.php?URL=pages/abc.php, the second rule extracts the needed URL part and redirects the client to the new URL path. The client then requests the new URL /cdi/abc and the third rule takes this and does an internal rewrite to the real content.
This all works fine as it should, but would rewrite and redirect indefinitely. To break this endless rule, the first rule checks the environment %{ENV:...}, if the request was already redirected REDIRECT_STATUS and then stops the cycle with the RewriteRule
RewriteRule ^ - [L]
which matches everything ^ and does no substitution, but ends the rewrite cycle with the flag [L]
Instead of using the system provided environment STATUS/REDIRECT_STATUS, you can also set a variable yourself with the flag E=SEO:1 for example, and then test for this variable with
RewriteCond %{ENV:REDIRECT_SEO} 1
For the REDIRECT_ prefix, see Available Variables.
You could try this:
RewriteRule ^/([a-z0-9_-]{1,40})/?$ index.php?URL=pages/$1.php
Though ideally you might want to get rid of the "pages/" part of the query string variable, as this fixed constant could be handled by the index.php script.
You approach seems fine but your RewriteCond doesn't match your requirements:
RewriteCond %{REQUEST_URI} ^index.php?URL=pages
means "rewrite the URL if someone requests something that starts with 'index.php"—but that's not what anyone will be requesting. You want your visitors to request pretty URLs.
If your server only needs to serve those requests for /the-page, you can drop the condition entirely. Then any URL will be rewritten. (Note: This might not be what you want!)
Otherwise, the condition should read something like this:
RewriteCond %{REQUEST_URI} ^[a-z0-9-_]{1,40}
If you don't want to mess with regular expressions, you could also try this:
RewriteCond %{REQUEST_FILENAME} !-f
which means "if the user requests a URL for which no file can be found, rewrite the URL according to the upcoming RewriteRule."
If you want the group ([0-9]+) to be alphabetic then just change it to ([a-z]+) and if you've wanted it to be alphanumeric, then change it to ([a-z0-9]+), and ([a-z0-9-_]+) if with a hyphen and an underscore. If you've wanted it to set their limits manually, you can do that with this format ([a-z0-9-_]{1,40}). Do you see, the plus sign is gone, for it limited the [chars] with 1 to anything, and the {1,40} limited the [chars] with 1 to 40, you can either change it.
Do you know what the real problem is? Is my stress.. Imagine even I know that you want to remap /$var into /index.php?URL=pages/$var.php I'm still trying giving you a wrong information that will rewrite /index.php?URL=pages/$var.php into /$var. I just have realize that after my 4 hours sleep. Did you see what's happening when the time of your sleep isn't right? Maybe a rule I would gives to you when my brain's in functioning well, was:
RewriteRule ^([a-z0-9-_]+)/?$ /index.php?URL=pages/$1.php
Why did the viewers letting this to happened.. My previous codes are needed to be voted down.

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

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]