Forum Moderators: phranque
This is my first post on the forum. I have some trouble with Mod_rewrite, and I hope you guys can help me with them. Babytalk please, as my understanding of mod_rewrite is fairly basic..
I have trouble with:
- If I enter the domain name without a trailing slash, I get a 'Bad Request' error. On sub-folders I do not have that problem.
- On my dev. server, the website sits under /necov/, which I have hard-coded. However on the live server the domain sits on the root. Is there a way to include a working directory in the mod_rewrite 'header'? Can somebody please help me adjust the code to reflect this?
- This is my first serious stab at the rewriting. Could you please verify that this code will not mess me over in the long run?
Here goes.. I am rebuilding a cms for an old website. So I want to take all the old pages:
domain.org/index.php
domain.org/folder/page.php
etc.
and rewrite them to:
domein.org/index.php?p=folder/page.php
On top of this, there are multiple languages, currently nl and en, which were written like:
domain.org/sub/index.php?lan=en
Which I would like as:
domain.org/en/sub/index.php => domain.org/en/index.php?p=sub/index.php
As there are a series of folders which require specific scripts, I have protected these folders.
This is my code so far:
Options +FollowSymLinks
# Switch on the rewrite module
RewriteEngine On
# rewrite lan=en to /en/ to have the right subfolder
# if old links were used
RewriteCond %{QUERY_STRING} lan=([a-zA-Z]+)
RewriteRule ^(.*)?$ [%{SERVER_NAME}...] [R,L]
#Rewrite file to index & language, but protect some files/folders
RewriteCond %{REQUEST_URI}!^(/necov/)?(en/¦nl/)?((index\.php¦layout¦manage¦admin¦contact¦users¦news¦tinymce)(/.*)?)$ [NC]
# the rule below was the idea, but doesn't work
# as AE and TE are existing folders..
#RewriteRule ^([a-z][a-z]/)?(.*)?$ index.php?l=$1&p=$2 [L]
#Instead we use this:
RewriteRule ^(en/¦nl/)?(.*)?$ index.php?l=$1&p=$2 [L]
#Rewrite file language, for previously protected folders
RewriteCond %{REQUEST_URI} ^(/necov/)?(en/¦nl/)?((index\.php¦layout¦manage¦admin¦contact¦users¦news)(/.*)?)$ [NC]
RewriteRule ^([a-z][a-z])/(.*)$ $2?l=$1 [L]
# rewrite newsitems
RewriteCond %{REQUEST_URI} ^(/necov/)?(en/¦nl/)?(news/)([0-9]+)?$ [NC]
RewriteRule ^(.*)?(news/)([0-9]+)?$ news/index.php?show=$3 [L]
I hope someone can help me crack this -for me complex- nut!
Cheers!
Jelle.
Yes, more complex than most are willing to take on. Which parts of this work, and which don't? How, specifically, does each part "not work" -- Does it do nothing, rewrite to the wrong place, or what? How did you test? What were the results? How did those results differ from what you expected?
You'll have better luck taking these rules one-at-a-time, posting the answers to the above questions, and asking about them separately, rather than in one huge incomprehensible (to us, who've never seen your site) hunk.
All that said, this code, which appears at least twice, looks wrong:
RewriteCond %{REQUEST_URI} ^(/necov/)?(en/¦nl/)?(news/)([0-9]+)?$ [NC]
RewriteCond %{REQUEST_URI} ^(/necov)?(/en¦/nl)?/news/[0-9]*$ [NC]
Jim
Thank you for your reply. Is there a good reason for calling this nuts? Is it un-necessarily complex, and could it be achieved with simpler rules?
To answer your questions:
All works. The only thing which does NOT work is the trailing slash:
If I enter the domain name without a trailing slash, I get a 'Bad Request' error. On sub-folders I do not have that problem. So..:
On my development server, if I go to [localhost...] I get a bad request error. If I go to: [localhost...] , the site loads perfectly normal showing the page [localhost...] Any other page loads fine too.
=> My main question is: How do I add the trailing slash. I am sure it can't be hard, just cannot figure it out :(
=> Second question would be:
At the moment I add '/necov/' to the rules, as that is the folder where the site sits on my development server (localhost/necov/). However, on the live server, it will just run from the root of the server, and does not require /necov/. Is there a way to pre-pend the foldername using one command, instead of mixed in with the code as it is now?
=> Third question would be:
What potential pitfalls have I built in the rewrites? As I am a novice at this stuff, I am not sure what trouble I can cause myself, and your expert opinion would be highly appreciated
Thanks so much for your time (I spent a lot of time posting PhP support on phpbuilder, and realize how many novice questions, and simple things drop by on a forum),
Cheers,
Jelle.
Create one of thee 400-Bad Request errors, and then examine both the access log and the error log. What do you see?
Again, the regex in your RewriteCond is not robust, and it seems that it will fail if some of the (optional-path)? parts are omitted in the incoming request. Compare to the code I provided.
You might look into using RewriteBase, but I'm not sure that will help with the path difference between your dev and production servers.
I suggest you do not do this until you get what you have working with/without a trailing slash.
It should not be necessary to add any code to get things working without a trailing slash -- Apache mod_dir should be handling this automatically.
Jim
Thanks for your continued support on this.
I have created a 400 / bad request error, using the new rewrite rules. When I try to access: localhost/necov the acceslog gives me one entry:
127.0.0.1 - - [27/Feb/2007:21:43:05 +0000] "GET /necov HTTP/1.1" 400 330
With the rewrite log giving me:
127.0.0.1 - - [27/Feb/2007:21:43:05 +0000] [localhost/sid#7959f8][rid#37a2228/initial] (3) [per-dir d:/_websites/necov/] applying pattern '^(.*)?$' to uri 'd:/_websites/necov'
127.0.0.1 - - [27/Feb/2007:21:43:05 +0000] [localhost/sid#7959f8][rid#37a2228/initial] (4) RewriteCond: input='' pattern='lan=([a-zA-Z]+)' => not-matched
127.0.0.1 - - [27/Feb/2007:21:43:05 +0000] [localhost/sid#7959f8][rid#37a2228/initial] (3) [per-dir d:/_websites/necov/] applying pattern '^(en/¦nl/)?(.*)?$' to uri 'd:/_websites/necov'
127.0.0.1 - - [27/Feb/2007:21:43:05 +0000] [localhost/sid#7959f8][rid#37a2228/initial] (4) RewriteCond: input='/necov' pattern='!^/necov(/en¦/nl)?((/index\.php¦/layout¦/manage¦/admin¦/contact¦/users¦/links¦/news¦/tinymce)(/.*)?)$' => matched
127.0.0.1 - - [27/Feb/2007:21:43:05 +0000] [localhost/sid#7959f8][rid#37a2228/initial] (2) [per-dir d:/_websites/necov/] rewrite d:/_websites/necov -> index.php?l=&p=d:/_websites/necov
127.0.0.1 - - [27/Feb/2007:21:43:05 +0000] [localhost/sid#7959f8][rid#37a2228/initial] (3) split uri=index.php?l=&p=d:/_websites/necov -> uri=index.php, args=l=&p=d:/_websites/necov
So it erroneously invokes this rule:
#Rewrite file to index & language, but protect some files/folders
RewriteCond %{REQUEST_URI}!^/necov(/en¦/nl)?((/index\.php¦/layout¦/manage¦/admin¦/contact¦/users¦/links¦/news¦/tinymce)(/.*)?)$ [NC]
RewriteRule ^(en/¦nl/)?(.*)?$ index.php?l=$1&p=$2 [L]
Again, all other paths work fine. Can you please advice me on how to adjust the rule, so it skips when there is no trailing slash? Possible by adding another condition that the URI has to be longer than 0? Is that possible?
Thank you so much for your help.
Jelle
It *correctly invoked that rule, because the request did not include one of (/index\.php¦/layout¦/manage¦/admin¦/contact¦/users¦/links¦/news¦/tinymce)
In order to avoid the rewrite, your URL must contain one of those (non-optional) strings. When you add a trailing slash, it's likely that your server converts that to a request for index.php (I am guessing about this), and so the RewriteCond suppresses the rewrite. But if you omit the trailing slash, then mod_rewrite sees that the request does not contain one of the "pages" you've specified as excluded, and so the rule is invoked.
If you want to NOT invoke that rule when there is no "page", then you'll need to add a question mark to the parenthesized sub-pattern above to make it optional.
Jim
Yes, you are right, it is correct in matching the rule, but it is (read was!) not doing what I anticipated it to do.
I added the? and now it works beautifully! Thank you so much. I really appreciate this!
If you ahve a moment to glance through it: If you look at the full set of rules, do you see anything which might be asking for trouble?
# rewrite?lan=en to /en/
RewriteCond %{QUERY_STRING} lan=([a-zA-Z]+)
RewriteRule ^(.*)?$ [%{SERVER_NAME}...] [R,L]
#Rewrite file to index & language, but protect some files/folders
RewriteCond %{REQUEST_URI}!^/necov(/en¦/nl)?((/index\.php¦/layout¦/manage¦/admin¦/contact¦/users¦/links¦/news¦/tinymce)?(/.*)?)$ [NC]
RewriteRule ^(en/¦nl/)?(.*)?$ index.php?l=$1&p=$2 [L]
#Rewrite file language, for previously protected folders
RewriteCond %{REQUEST_URI} ^/necov(/en¦/nl)?((/index\.php¦/layout¦/manage¦/admin¦/contact¦/users¦/links¦/news)(/.*)?)$ [NC]
RewriteRule ^([a-z][a-z])/(.*)$ $2?l=$1 [L]
# rewrite newsitems
RewriteCond %{REQUEST_URI} ^/necov(/en¦/nl)?/news/([0-9]+)?$ [NC]
RewriteRule ^(.*)?(news/)([0-9]+)?$ news/index.php?show=$3 [L]
You also might consider tightening-up some of the quantifiers, for example, using lang=[a-z]{2} instead of lang=[a-z]+ if you always use standard two-letter language/country-codes.
It all depends on the details of your site and your desires, neither of which I know.
Jim
I want to -in the future- only use /en/ or /nl/ or [a-z]{2}/ type language links. So it is a permanent redirect. What should I modify?
Yes, I will always stick to two letter language codes, as the site will never in foresee-able future be more then few-langual.. I'll modiy the code to [a-z]{2}, good tip.
J.