Rewrite only if Folder exists but file doesn't - mod-rewrite

I am trying to rewrite all requests to a file that doesn't exist but the folder does.
What I mean is:
Say I have this folder structure:
foo
'-bar1
'-bar2
'-bar2.html
'-shared
'-shared.html
What I am looking for the rewrite rule to do is to serve up example.com/foo/bar2/bar2.html as normal. Serve example.com/foo/bar1/bar1.html as /foo/shared/shared.html and to no serve example.com/foo/bar3/bar3.html.
So in summary. I am trying to develop a RewriteCond that hits only when the directory exists but the file doesnt exist in that directory.
The problem with:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
is that it will rewrite www.example.com/bar3/bar3.html even though /foo/bar3 directory doesn't exist.
Thanks for the help!

These rules should do the job:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{DOCUMENT_ROOT}/$1/ -d
RewriteRule ^(.+)/([^/]+)$ /foo/shared/shared.html [L,QSA]
These rules intended to be placed in .htaccess file in root folder. If you need to place them in config file (e.g. httpd-vhost.conf) then you will need to modify it a bit (remove some slashes in 2nd RewriteCond .. or add leading slash in RewriteRule -- testing is actually required).
These rules will only work if requested resource has at least 1 folder (obvious -- as requested).

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 do I exclude stylesheet and javascript files from my rewrite rules?

I have a rewrite rule currently as shown below:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^/]+)/([^/]+)$ $2.php?locale=$1 [QSA,L]
RewriteRule ^([^/]+)/([^/]+)/([^/]+) $2.php?page=$3&locale=$1 [QSA,L]
My page URLs are like this:
http://example.com/en/new
or this:
http://example.com/en/new/1
As for the index page it's like this:
http://example.com/en/index
and I wanna get rid of the 'index' word so I added this rule:
RewriteRule ^(.*)$ index\.php/$1 [L]
Which works as expected except for my web assets (css, js files) which are located under: /css and /js folders now has 500 error. So my question is how to I exclude URLs pointing to these files under these 2 directories from being rewritten.
This solved my problem. Either use the suggested answer from here
http://stackoverflow.com/questions/1848500/htaccess-mod-rewrite-how-to-exclude-directory-from-rewrite-rule?rq=1
or simply create a .htaccess file inside the directory where you don't want rewriting to take place and put this in:
RewriteEngine Off

Mod-rewrite problems with REQUEST_FILENAME

I have a problem with server interpreting domain.com/index as domain.com/index.php. This screws with my URL structure.
I have created a .htaccess file with the following:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?url=$1 [PT,L]
</IfModule>
So if I type in the URL domain.com/index/about I want to get index/about from $_GET['url']. But instead it is blank. If I type any other URL not starting with index, like domain.com/foo/bar I get the expected results.
I understand that this is due to RewriteCond %{REQUEST_FILENAME} !-f which ignores any Rewrite if a file with same filename exist.
So my RewriteRules gives me the results I want as long as URL doesn't involve the word index or other dir- or filename. And that is all fine, since I have no other dirs or files in the current dir.
So question is; Can I make it more specific, as to say ignore filename.php instead of just filename? Meaning that domain.com/index/about should work but not domain.com/index.php/about.
Side question: And why does domain.com/index/about not work anyways? I have no dir called index/about and no file called index/about. Why does it interpret index/something as index.php/something which makes no sense, as I cannot have a dir inside a file.

mod_rewrite - trouble with combination of rules

I've got the following rules to work which:
only act on files that exist
exclude any files that contain images|js|css in their uri
add trailing slash to request uri
Rewrite rules:
RewriteEngine on
DirectorySlash Off
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !/(images|js|css)$
RewriteRule ^(.*[^/.])$ /$1/ [R=301,L]
I now need to correctly redirect my home uri's like so:
http://www.example.com/sitemap/ -> http://www.example.com/index.php?page=sitemap
I've tried the following approach:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*[^/.])$ index.php?page=$1 [R=301,L,NC]
But I get a page not found, presumably because $1 is being fed something with a slash in it. I thought [^/] would remove it but apparently not.
Could someone explain where I am going wrong here please?
Use this rule -- it will rewrite /sitemap/ into /index.php?page=sitemap:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^/]+)/$ /index.php?page=$1 [QSA,L]
Put it into .htaccess into website root folder. If placed elsewhere it need to be tweaked a bit.
URL will stay the same. Existing query string will be preserved.
The trailing slash / must be present (i.e. /sitemap will not trigger this rule).
It will only rewrite if there is no such folder or file (i.e. if you have a folder named sitemap in your website root folder then no rewrite will occur).
It will only work for 1-folder deep URLs (e.g. /sitemap/, /help/, /user-account/ etc). It will not work for 2 or more folders in path (e.g. /account/history/).
RE: this line: RewriteCond %{REQUEST_URI} !/(images|js|css)$.
You said you want "exclude any files that contain images|js|css in their uri". Unfortunately the above pattern work differently -- it will match /something/css but will not match /css/something or /something/file.css.
If you want to match images|js|css ANYWHERE in URL straight after a slash, then remove $.

Rewrite rules confused

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]

Resources