Assistance with .htaccess - mod-rewrite

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.

Related

.htaccess - Check .jpg size and replace if match

I need to control all remotes .jpg matching sizes: 4456 and 4824. If match these bytes I need to replace with a default image. The below code is to replace a .jpg if doesn't exist.
RewriteCond %{REQUEST_URI} \.(jpeg|JPEG|jpg|JPG)$ [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule .*$ /default-image.jpg [L]
I need that if a example.com/*.jpg have size (4456 | 4824) then replace with the default-image.jpg.
In PHP this is working like a charm for my needs but I would prefer to set in .htaccess.
$link = 'https://example.com/test.jpg';
$check_image = get_headers($link, 1);
$bytes = $check_image["Content-Length"];
if ($bytes < 5000) { ...
You can do the following on Apache 2.4 using an Apache expression with mod_rewrite:
RewriteCond %{REQUEST_URI} !^/default-image\.jpg$
RewriteCond expr "filesize(%{REQUEST_FILENAME}) =~ /4456|4824/"
RewriteRule \.jpe?g$ /default-image.jpg [NC,L]
If the requested image does not exist then the filesize() function simply returns 0 (no error). So, to handle non-existent images as well, then you could just change the regex to include 0, ie. /0|4456|4824/.
Aside:
RewriteCond %{REQUEST_URI} \.(jpeg|JPEG|jpg|JPG)$ [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule .*$ /default-image.jpg [L]
In the first condition, there is no need to check jpeg|JPEG since you are using the NC (case-insensitive) flag on the directive. However, it is more optimal to perform this check in the RewriteRule pattern instead, rather than creating an additional condition.
There's no need to check that the request does not map to a directory (3rd condition), unless you also have directory names that end in .jpg etc. (unlikely). Filesystem checks are relatively expensive, so it is best to avoid them if possible.

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]

What does this Mod Rewrite do?

Can anybody tell me what this does?
RewriteRule .* .main.php [QSA,L]
From what I understand it will rewrite ANYTHING to main.php correct? But not so sure what the QSA,L does.
This is the whole .htaccess file, when I hit the main directory I get a 400 Bad Request error. Edit: Bad request went away when I added an ending slash in the browser to the root directory of this script.
RewriteEngine On
# Transfering to the main tranfer file
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
RewriteCond %{REQUEST_FILENAME} !\.css$
RewriteCond %{REQUEST_FILENAME} !\.js$
RewriteRule .* .main.php [QSA,L]
# nobody is allowed to access the access the INI file
<FilesMatch "\.inc.php$">
Order allow,deny
Deny from all
</FilesMatch>
QSA = Query String Append: append the existing query string to the re-written rule
L = Last Rule: last rule of the set, don't process any following RewriteRule
Check out the documentation for more.
Do you have a file that is named .main.php? The dot prefix worries me. Your rules read that unless the request is an exists, symbolic link, or it has a CSS or JS extension it goes to .main.php

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