Rewriting Specific to more General - apache

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]

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]

Apache rewrite conditions not catching existing directories or files

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^/board/([a-zA-Z0-9\_\-]*).* /board/index.php?$1 [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^/board/user/([a-zA-Z0-9\_\-]*).* /board/user/index.php?$1 [L]
I am trying to forward mydomain.com/board/something to mydomain.com/board/index.php?something and /board/user/something to /board/user/index.php?something. And have it not rewrite existing files or directories.
The board/ one works but it fires even if i request an existing directory so I can't test the second one. Also a page like mydomain.com/board/signup/index.php is forwarding to /board/index.php?signup
These are all within a <VirtualHost *:443> and my VPS is actually handling a few different domain names on the same instance if that makes a difference.
I found similar issues in search but their solution was what I am using above already.
Apparently on Apache 2.4 (maybe 2.2 and above?) you have to do it like this:
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-f
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-d
However this does not catch if you navigate to, say, mydomain.com/board/ when there is an index.php there. So this is what I have come up with, finally.
RewriteEngine On
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-f
RewriteCond $1 !index\.
RewriteCond %{DOCUMENT_ROOT}/board/$1/index.php !-f
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-d
RewriteRule ^/board/([a-zA-Z0-9\_\-\.]*) /board/index.php?$1 [L]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-f
RewriteCond $1 !index\.
RewriteCond %{DOCUMENT_ROOT}/board/user/$1/index.php !-f
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-d
RewriteRule ^/board/user/([a-zA-Z0-9\_\-\.]*) /board/user/index.php?$1 [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]

Multiple .htaccess rules?

I'm getting the grip of .htaccess, but now i'm stuck in a situation where there's multiple redirects needed.
website/werknemers/5
website/lijst/5
Those links should work, redirecting from
index.php?page=werknemers&klant=5
index.php?page=lijst&lijst=5
I'm using the following .htaccess, which is working! but only the one's i put at the top of the document
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/(.*)$ index.php?page=$1&klant=$2 [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/(.*)$ index.php?page=$1&lijst=$2 [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?page=$1 [L]
Since your patterns are exactly the same, there is no difference between the first and second rules, so the first always matches and you will always get the klant query string no matter what. You can hardcode the page names if that's the only thing that's different:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^werknemers/(.*)$ index.php?page=werknemers&klant=$1 [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^lijst/(.*)$ index.php?page=lijst&lijst=$1 [L]

mod_rewrite and pretty urls

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?