mod_rewrite and pretty urls - apache

What I'm trying to achieve:
1) http://localhost/en/script.php?param1=random is mapped to http://localhost/script.php?param1=random&language=English
This has to work always.
2) http://localhost/en/random/text/here will be mapped to http://localhost/categories.php?term=random/text/here
This has to work if random/text/here is 404
What I have at the moment:
RewriteEngine on
RewriteCond substr(%{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^en/(.+)$ categories.php?lang=English&terms=$1 [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ee/(.+)$ categories.php?lang=Estonian&terms=$1 [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^fi/(.+)$ categories.php?lang=Finnish&terms=$1 [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ru/(.+)$ categories.php?lang=Russian&terms=$1 [L]
RewriteRule ^en/(.*) $1?lang=English [QSA]
RewriteRule ^ee/(.*) $1?lang=Estonian [QSA]
RewriteRule ^ru/(.*) $1?lang=Russian [QSA]
RewriteRule ^fi/(.*) $1?lang=Finnish [QSA]
What is the problem:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
It's supposed to redirect to categories.php?lang=English IF /en/this/here/does/not/match/a/script. If I load an URL like en/index.php it will also get mapped to categories.php?lang=English because en/index.php does not exist.
What I've thought:
substr(%{REQUEST_FILENAME},3) would fix my problem (as currently /ee/index.php is literally mapped to /ee/index.php instead of just /index.php)
Unfortunately I couldn't find a way to manipulate strings :/

I take it the language code is what makes the URL map to a non-existant file. Switch the two steps, moving the language code to the query string first. This also has the added advantage of simplifying the keyword step to a single RewriteRule, since they no longer need to do two things at once.
RewriteRule ^en/(.*) $1?lang=English [QSA,DPI]
RewriteRule ^ee/(.*) $1?lang=Estonian [QSA,DPI]
RewriteRule ^ru/(.*) $1?lang=Russian [QSA,DPI]
RewriteRule ^fi/(.*) $1?lang=Finnish [QSA,DPI]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)$ categories.php?terms=$1 [L,QSA]

the issue is that you are using the L flag. Which means that rule will be the last to be executed.
also
%{QUERY_STRING}
isnt necessary, add QSA and you will get all parameters added to the end of the url
try to do:
RewriteRule ^en/(.*) $1?lang=English [QSA]

For substr problem, you could try absolute paths:
RewriteRule ^en/(.*) /$1?lang=English&%{QUERY_STRING}
or
RewriteRule ^en/(.*) http:/localhost/$1?lang=English&%{QUERY_STRING}
Also, I might be nitpicking, but wouldn't it be easier if you did the language evaluation in the PHP base on language codes, 404'ed non-existent languages and used
RewriteRule ^(.*?)/(.*) $2?lang=$1&%{QUERY_STRING}
Edit: depending on how many scripts you have, can't you do something like:
RewriteRule ^(.*?)/(script.php|other.php) $2?lang=$1 [QSA]
= have pipe-list files, that are accesible?

Related

htaccess Rerwite rules colliding

I have to rewrite rules that collide with each other. Actually, it's the second rule that causes the first not to work, even when I switch positions.
artistmusic.php
From: http://www.example.com/artistmusic?slug=Ben
To: http://www.example.com/Ben/music
artistvideos.php
From: http://www.example.com/artistvideos?slug=Ben
To: http://www.example.com/Ben/videos
Rewrite rule for the above urls.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^/]*)/([^/]*)$ /artist$2?address=$1 [L]
This works like it should, until I add the rewrite rule for the set of URls below.
allsongs.php
From: http://www.example.com/allsongs?standard=popular&request=monthly
To: http://www.example.com/songs/popular/monthly
allartists.php
From: http://www.example.com/allartists?standard=popular&request=monthly
To: http://www.example.com/artists/popular/monthly
Rewrite rule for the second set above.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^/]*)/([^/]*)/([^/]*)$ /all$1?standard=$2&request=$3
The rule above works but kills the first one.
What is the cause of this? Thanks.
With your shown samples/attempts, please have your htaccess rules file in following manner. Please make sure to clear your browser cache before testing your URLs.
RewriteEngine ON
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^songs/([^/]*)/([^/]*)/?$ allsongs.php?standard=$1&request=$2 [NC,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^artists/([^/]*)/([^/]*)/?$ allartists.php?standard=$1&request=$2 [NC,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^/]*)/(music|videos)/?$ artist$2.php?slug=$1 [QSA,NC,L]
Generic solution: In case you don't want to hard code values in your new rules then try following. Make sure use either above OR following only 1 at a time.
RewriteEngine ON
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^/]*)/([^/]*)/([^/]*)/?$ all$1.php?standard=$2&request=$3 [QSA,NC,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^/]*)/([^/]*)/?$ artist$2.php?slug=$1 [QSA,NC,L]

Rewriting Specific to more General

I'd like to do a mod_rewrite so that:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
Any requests to users/ goes to index.php?login=(whatever).
RewriteRule ^users/(.+) ?login=$1 [NE,L]
Any other requests, outside of users/, goes to the same place.
RewriteRule ^(.+) users/?login=$1 [NE,L]
but the second part is producing a 500 Internal Server Error
I was asked to explain it, so here are some examples:
if "domain.com/aaa/" exists, it goes to "domain.com/aaa/"
if "domain.com/bbb/" does not exist, it goes to "domain.com/users/?login=bbb"
if "domain.com/ccc.html exists, it goes to "domain.com/ccc.html"
if "domain.com/ddd.html does not exist, it goes to "domain.com/users/?login=ddd.html"
meanwhile, "domain.com/users/eee" goes to "domain.com/users/?login=eee" since that's the primary condition, and the second condition is a fallback or more general catchall.
This should work. You have to repeat the conditions, they don't carry over to the next rule.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^users/(.+)$ /users/?login=$1 [NE,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)$ /users/?login=$1 [NE,L]
Assuming that the /users/ directory does actually exist.
Or this is more efficient, if you're not running any rules later. It prevents any processing of existing items and avoids doubling up the file-system checks.
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
RewriteRule ^users/(.+)$ /users/?login=$1 [NE,L]
RewriteRule ^(.+)$ /users/?login=$1 [NE,L]

Pretty URLs .htaccess

I always get in a tangle with .htaccess so was hoping someone could help me write one.
I have found stuff online similar to what I want, but I'm not confident enough
to rewrite their rewrites :P
I want this:
/foo/ = index.php?a=foo
/foo/bar/ = index.php?a=foo&b=bar
etc. up to /foo/bar/baz/cat/dog/ (&e=dog)
I also want the index.php to be invisible so that /index.php rewrites to /.
Another thing, I would like there to always be a trailing slash and therefore the ability
to do...
/foo/bar/baz/?another=whatever
I have directories such as /images/ that I don't want this to apply to,
so would I have to make a white list for this or are there certain redirects I can use?
Cheers!
You don't need to whitelist directories. That's what RewriteConds are for.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
It checks to make sure it's not a real file or real directory then performs the RewriteRule.
Try these rules below in your .htaccess file to get what you want.
RewriteEngine On
RewriteCond %{REQUEST_URI} /+[^\.]+$
RewriteRule ^(.+[^/])$ %{REQUEST_URI}/ [R=301,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^/]+)/([^/]+)/([^/]+)/([^/]+)/([^/]+) index.php?a=$1&b=$2&c=$3&d=$4&e=$5&%{QUERY_STRING} [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^/]+)/([^/]+)/([^/]+)/([^/]+) index.php?a=$1&b=$2&c=$3&d=$4&%{QUERY_STRING} [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^/]+)/([^/]+)/([^/]+) index.php?a=$1&b=$2&c=$3&%{QUERY_STRING} [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^/]+)/([^/]+) index.php?a=$1&b=$2&%{QUERY_STRING} [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^/]+) index.php?a=$1&%{QUERY_STRING} [L]

RewriteCond with negative conditions

I'm trying to rewrite all www.site.com/hello to www.site.com/index.php?p=hello
and it works with the following code (in .htaccess):
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^/]*)/?$ /index.php?p=$1
But I want to keep the old links working so www.site.com/?p=hello will stay www.site.com/?p=hello
I've tried the following code but it won't work
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !(\?p=)
RewriteRule ^([^/]*)/?$ /index.php?p=$1
I've found an answer.
The mistake was trying to get the GET parameters with REQUEST_URI. The right usage should be with QUERY STRING like this:
RewriteCond %{QUERY_STRING} !(p=.*)$
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^/]*)/?$ /index.php?p=$1

.htaccess rewrite of a url [help with rule]

I'm trying to rewrite a url of this:
http://www.foo.com/bar/baz
to
index.php?q=$1&d=baz
Where bar is not a fixed value, but baz is.
RewriteRule ^(.*)\/baz$ index.php?q=$1&d=baz [L,QSA]
RewriteRule ^(.*)$ index.php?q=$1 [L,QSA]
What i have above kinda works but unfortunately breaks all the includes in the site (css/javascript) but strangely all the pages work :/
This is a drupal install, (so the second line needs to remain).
UPDATE
This might help actually, i forgot to include
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !=/favicon.ico
**RewriteRule ^(.*)/details index.php?q=$1&details=true [L,QSA]**
RewriteRule ^(.*)$ index.php?q=$1 [L,QSA]
It seems to be doing my rewrite correctly, the only problem is it's ignoring the other conditional statements now, i.e. it's still attempting to rewrite files that exist (i.e. css,js) when it's mean to avoid them.
site is fine without my line (The one with the stars), but with it, the variables and pages work, but static files like css etc are also being rewritten....need to stop that!
Thanks in advance.
Shadi
Conditions only apply to the first rule immediately following. So try duplicating the condition lines.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/details index.php?q=$1&details=true [L,QSA]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !=/favicon.ico
RewriteRule ^(.*)$ index.php?q=$1 [L,QSA]
RewriteRule ^(.*)/details index.php?q=$1&details=true [L,QSA]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !=/favicon.ico
RewriteRule ^(.*)$ index.php?q=$1 [L,QSA]
This is what finally worked. it just required the rearranging of the rules...