Rewrite rules confused - mod-rewrite

I am struggling to achieve this simple thing...
I have some static pages which should be like
www.domain.com/profile etc..
The problem is how to write the rewrite rules in order to ..
There would be some fixed rewrites
like /home
I want every file that exists not to be rewritten
www.domain.com/test.php should go to
test.php
Lastly if it is not found i want it to be redirected to static.php?_.....
RewriteRule ^/home/?$ /index.php?__i18n_language=$1 [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^/([^/]+)/?$ /static.php?__i18n_language=$1
This works ok but if i type index.php or test.php or even the mach from other redirection it gets me in static.php...
Please help!

According to your description you can use these rules:
# stop rewriting process if request can be mapped onto existing file
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteRule ^ - [L]
# rewrite known paths /home, /foo, /bar, etc.
RewriteRule ^/(home|foo|bar|…)$ /index.php [L]
# rewrite any other path
RewriteRule ^ /static.php [L]

I haven't used this in a long time, but it's something I found, that should help. It is part of an old script that generates .httaccess files for redirecting from /usr/share/doc only when the doc isn't found:
The rule is "Check, and if the target url exists, then leave":
RewriteEngine On
RewriteBase /doc/User_Documents
### If the directory already exists, then leave
### We're just redirecting request when the directory exists but has been renamed.
RewriteCond %{REQUEST_FILENAME} User_Documents/([^/]+-[0-9][^/]*)
RewriteCond $PWD/%1 -d
RewriteRule .* - [L]
It's the [L] that means leave if one of the conditions is matched. In the old script, there are hundreds of generated rules (after [L]) that are skipped, because one of the conditions matched. In your case you would skip the rest of the rules when the target %{REQUEST_FILENAME} is found.
So, I suggest, before the redirection rule:
RewriteCond %{REQUEST_FILENAME} -f
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule .* - [L]

Related

Assistance with .htaccess

I need the .htaccess file to allow all file and directories if they exist, but php extensions are not needed for existing files and everything else goes to the index file.(MVC type processing) I've tried a few things, but haven't got it right yet.
Examples:
www.example.com/search/
file exists as search.php and should display the file
www.example.com/shopping/mylist/file doesn't exist so should go to index.php
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ $1.php [L]
RewriteRule ^(.+)$ index.php?url=$1 [QSA,L]
mod_rewrite is highly order dependent so let's think through it logically from most specific to least specific.
You will need a condition to check for the existence of the .php file based on a match from the () group in RewriteCond first. That will be two conditions followed by a RewriteRule to actually direct it into the .php file. Your example /search/ has a trailing slash, and that's why we'll first need to capture it as %1 with two RewriteCond. Otherwise, I would probably use %{REQUEST_FILENAME}.php -f to test if it exists. This sort of explains how the %1 backreference can be used in RewriteCond chain.
Then after applying that one to attempt to match a .php file, use the more generic index.php rule as you already have it, together with the two conditions to check whether the file actually exists.
RewriteEngine On
# Match an optional trailing slash on the filename
# and capture it as %1
RewriteCond %{REQUEST_FILENAME} ^(.+)/?
# And test if the match (without /) has a .php file
RewriteCond %1.php -f
# Rewrite everything up to an optional trailing /
# matched in the first RewriteCond
# into its .php suffix (add QSA to retain query string)
# It isn't necessary to give a full regex here since %1
# already contains everything needed
RewriteRule ^ %1.php [L,QSA]
# Now with that out of the way, apply the generic
# rule to rewrite any other non-existing file to index.php
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
# I used * instead of + so it also matches an empty url
RewriteRule ^(.*) index.php?url=$1 [QSA,L]
I have successfully tested this setup in a temporary directory. It appears to meet your requirements.

how to create an empty rewrite rule, that will not modify the url

I have static files in several directories on my website.
I was trying to create a rule that will instruct the rewrite engine to disregard all of those static files.
something like this:
#RewriteCond %{REQUEST_URI} !\.*(jpg|css|js|gif|png|swf)$ [NC]
this seems to work only in some of the cases, but not all of them.
As a solution I decided to match the entire request URI of any requested file with one of the following extensions, and create an 'empty' rewrite rule for them, that will redirect the user to the precise request URL, basically.
To achieve that I did the following:
RewriteCond $1 \*.(js|ico|gif|jpg|png|css|swf|mp3|wav|txt)$ [NC]
RewriteRule ^(.*) \$1 [R=301,L]
This won't work for some reason, no useful information at the access.log and error.log either.
Thanks in advance for any assistance!
Full code:
#Catch static content and don't modify it
RewriteCond $1 \*.(js|ico|gif|jpg|png|css|swf|mp3|wav|txt)$ [NC]
RewriteRule ^(.*) \$1 [R=301,L]
#prevent looping
RewriteCond %{QUERY_STRING} !clientId=
#redirect sub domain to the client page cutl.mysite.com = mysite.com/in/index/php?clientId=curl
RewriteRule ^(.*)$ /in/index.php?uclinetId=$1 [L]
Rather than maintaining a long list of file extensions for exclusion you can simply use:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
Which means apply next RewriteRule if request is NOT for a real file or a symbolic link.
Probably your backslash should be between the asterix and the dot?
RewriteCond $1 *\.(js|ico|gif|jpg|png|css|swf|mp3|wav|txt)$ [NC]
RewriteRule ^(.*) \$1 [R=301,L]

mod_rewrite precedence

Let's say I want to support urls like twitter where:
twitter.com/username redirects to twitter.com/user_name.php?user=username
I have the following
RewriteRule ^(.*)$ user_name.php?user=$1
And that works fine. But the problem is now that everything, including twitter.com/index.php will of course redirect to user_name.php
How can I either create exceptions or precedence so that "real files" don't get rewritten? I tried adding an explicit rule for index.php before and after that one, but it doesn't seem to take effect.
You need to add RewriteCond for this
RewriteCond %{REQUEST_URI} !-f [OR] # for existing files
RewriteCond %{REQUEST_URI} !-d # for existing directories
RewriteRule ^(.*)$ user_name.php?user=$1

Rewrite URLs for static content

I have problems with static files url rewriting in current .htaccess setup on apache2.
My app structure is:
/siteroot
/siteroot/app
/siteroot/lib
/siteroot/...
/siteroot/public <- all the static files (images, js, etc.) stored here
/siteroot/index.php
/siteroot/.htaccess
So, i need to rewrite url like /css/style.css to /public/css/style.css. I did that in really simple way, but when the file is not found it causing 10 internal redirects, which is bad. I need somehow to return 404 code if file not found, or just pass it to the next rule. And i dont have any access to site configuration file. Only .htaccess.
The reason why i`m asking this question is that the site was running on nginx and i need to rebuild the same configuration on apache.
Here is my .htaccess file.
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^.+\.(jpg|jpeg|gif|png|ico|css|js|swf)$ /public/$0 [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
Test if a redirect is reasonable:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{DOCUMENT_ROOT}/public/$0 -f
RewriteRule ^.+\.(jpg|jpeg|gif|png|ico|css|js|swf)$ /public/$0 [L]
If the number of prefixes is limited, you could add another group to your regex:
RewriteRule ^(css|js|images|etc)/.+\.(jpg|jpeg|gif|png|ico|css|js|swf)$ /public/$0 [L]

mod_rewrite: what does this RewriteRule do?

Given these conditions (I know what they mean/do):
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
What does the first rule do? What is that lonely dash for?
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ /index.php [NC,L]
I've been using this for quite some time now in combination with the Zend Framework, but I never really got what the first rule does exactly.
The RewriteCond directive just describes an additional condition for a RewriteRule directive. So RewriteCond must always be associated with a RewriteRule.
In your case the three RewriteCond probably belong to the first RewriteRule like this:
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
Now this rule is applied if the pattern of the RewriteRule matches the current request URL (per-directory path stripped before) and if the condition is fulfilled.
In this case the condition is only true if when mapping the request URL to the filesystem it matches either an existing file with the file size greater than 0 (-s), or a symbolic link (-l) or a directory (-d). So your rule will be applied for any URL (^.*$ matches anything) that can be mapped to something existing in your filesystem. The substitution - just means to not change anything. And the NC (no case, case insensitive, useless in this context) and L (last rule if applied) are flags that modify either the pattern, replacement or the execution of the rule.

Resources