htaccess rewriterule - .htaccess

A fairly basic htaccess question, but I don't use it much, so i have no idea.
I want to check if the requested file exists. If it does, forward to one page, and if not forward to another page and pass the requested path as GET.
Thanks in advance.

RewriteEngine On
# check if requested file or directory exists
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
# if not, pass it to index.php
RewriteRule ^(.*) index.php?page=$1 [QSA]
As Gumbo suggested, you can repeat the condition without the ! if you also want to rewrite the URL when a file exists. Maybe you want to 'protect' your real files and folders with this method.

Use the -f expression in a RewriteCond condition to test if the given path points to an existing regular file:
RewriteEngin on
# file exists
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^ one-page [L]
# file does not exist
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ another-page [L]
The initial requested URI should then be available in an environment variable.

Related

How to mod_write query param to path for arbitrarily long path?

I'm building a simple API with apache and I want to map /really/long/path/api/captions.php?caption_id=blah to /really/long/path/api/captions/blah. It's important to NOT have to specify a full path in the rewrite rule because I want this to work no matter where I deploy this code to. However, I can't find/figure out a working example of .htaccess rewrite rules that enable me to match based upon only the final part of the extension.
So, assuming that I have, say, captions.php in a dir called api, what .htaccess file do I need to include in api to accomplish this transform without having /really/long/path/ anywhere therein?
(I also want to be able to map /really/long/path/api/captions.php to /really/long/path/api/captions/ and /really/long/path/api/captions.)
I've tried all sorts of wildcard-like syntax; here's one of those non-working attempts:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*?)/?captions/(.*?)/?$ /captions.php?caption_id=$1 [L]
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /captions\.php\?caption_id=([^\&\ ]+)
RewriteRule ^(.*?)/?captions\.php$ /captions/%1? [L,R=301]
Thanks!
Got there in the end. This is all that was needed:
RewriteEngine On # Turn on the rewriting engine
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^captions/?$ captions.php [NC,L]
RewriteRule ^captions/(.*)/?$ captions.php?caption_id=$1 [NC,L]

How can I rewrite an already rewritten file if it is not found

I need to rewrite a URL for an image file. This is the easy part and looks like this:
RewriteRule ^img[/]?(/[^.]+)?$ - [L]
RewriteRule ^img/([A-Za-z0-9_-\s]+)/([A-Za-z0-9_\-\s\.]+)?$ cache/$1-$2 [L]
However if the image file is not found in that cache directory I need to rewrite this again to a PHP script that will create the image and save it in that cache directory.
I tried the following rewrite, but it doesn't work as intended. Instead all image URLs are rewritten to the PHP file regardless if the file exists in the cache or not.
#RewriteCond cache/%{REQUEST_FILENAME} !-f
#RewriteCond cache/%{REQUEST_FILENAME} !-d
#RewriteRule ^cache/([A-Za-z0-9_\s]+)-([A-Za-z0-9_\-\s\.]+)?$ createimg.php?type=1&hash=$1&filename=$2 [L]
Any ideas? Thanks.
Since after the first rule, the same rules will be matched with the new url, the url already contains "cache/". %{REQUEST_FILENAME} and other magic variables are updated accordingly. Therefore you don't need to put "cache/" in front of the variable.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^cache/([A-Za-z0-9_\s]+)-([A-Za-z0-9_\-\s\.]+)?$ createimg.php?type=1&hash=$1&filename=$2 [L]

.htaccess doesn't rewrite relative to the root directory

I have tried to create an .htaccess file to do following:
Direct www.domain.com/name or www.domain.com/name/ to www.domain.com/page.php?id=name
and www.domain.com/name/2 or www.domain.com/name/2/ to www.domain.com/page.php?id=name&pg=2
my .htaccess looks like this:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
# If the request is not for a valid directory
RewriteCond %{REQUEST_FILENAME} !-d
# If the request is not for a valid file
RewriteCond %{REQUEST_FILENAME} !-f
# If the request is not for a valid link
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^([a-z0-9-_\.]+)/?$ page.php?id=$1 [L]
RewriteRule ^([a-z0-9-_\.]+)/([a-z0-9]+)/?$ page.php?id=$1&pg=$2 [L]
</IfModule>
The problem is, that when I actually use a slash after name it thinks of it as a directory and looks for pages in www.domain.com/name/.. But I am still able to $_GET the variables based on id and pg.
Can anyone tell me what I have done wrong? I prefer that the URL in the address bar stays clean as www.domain.com/name/2/.
Also i have another question.. I have tried to rewrite the other URLS without luck.
If they write: www.domain.com/page.php?id=name&pg=2 and want to change the address bar URL to be be clean again, but that completely went wrong for me. Is there any specific way to do this by using what I have already made?
Thanks in advance for your help.
EDIT
The solution was based on PHP and not .htaccess. The answer was found based on this question: Stylesheet does not load after using RewriteRule and include . My problem was caused by PHP including relative to the public URL and directory. I have been forced to define a main URL variable to place before any foreign includes.
RewriteCond is only applicable to the very next RewriteRule.
Have your code this way:
RewriteEngine On
RewriteBase /
# If the request is for a valid directory
RewriteCond %{REQUEST_FILENAME} -d [OR]
# If the request is for a valid file
RewriteCond %{REQUEST_FILENAME} -f [OR]
# If the request is for a valid link
RewriteCond %{REQUEST_FILENAME} -l
RewriteRule ^ - [L]
# external redirect from actual URL to pretty one
RewriteCond %{THE_REQUEST} \s/+page\.php\?id=([^\s&]+) [NC]
RewriteRule ^ %1? [R=302,L]
RewriteRule ^([\w.-]+)/?$ page.php?id=$1 [L,QSA]
RewriteRule ^([\w.-]+)/([\w.-]+)/?$ page.php?id=$1&pg=$2 [L,QSA]

What does this .htaccess code mean?

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule .* ./index.php
I think it means if the url doesn't match a file or directory on the server go to /index.php?
Can anybody confirm?
Yes is the short answer. But usually ./index.php has an [L,QSA] suffix/qualifier, so the query part of a URI request is also passed on to it.
What this is doing:
RewriteCond %{REQUEST_FILENAME} !-d
If it can't find a directory with the name
RewriteCond %{REQUEST_FILENAME} !-f
If it can't find a file with the name
RewriteRule .* ./index.php
Load the index.php next to the .htaccess file.
To answer Anthony's question regarding what would happen if it where removed1 2,
It would try and access the directory or file. If it fails, instead of defaulting to the index.php it would simply give the default web servers 404 error.
Right now, it allows the application to either show the default page, or handle the request through it in some fashion.

htaccess infinite redirect

I'm working on a legacy codebase, with three different folders of images. An image could be in any one of the three folders, in a pretty much random manner.
I initially attempted to check for file existence within PHP; however, images are being displayed in tons of places, and I'm hoping I can just achieve the same thing with an htaccess file. However, so far no luck.
Here's what I've got so far:
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^Folder_1/(.*)$ Folder_2/$1 [L,NC]
RewriteRule ^Folder_2/(.*)$ Folder_3/$1 [L,NC]
What I'd like to happen is for any image request that doesn't exist, check the other two folders, in any order, for its existence. So, if someone requests Folder_3/image.png, it'll check Folder_1/image.png, then Folder_2/image.png
Any suggestions for how to write the htaccess file?
Use the [N] flag to start rewriting from the top again.
In case you weren't able to get it to work based on Ignacio's suggestion, I'd suggest something like this, which, although a bit convoluted, seems to work:
RewriteEngine on
# If the request points to a real resource, just end here
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d [OR]
RewriteCond %{REQUEST_FILENAME} -l
RewriteRule ^ - [L]
# Check the other two directories
# First, figure out which directory we're currently in and capture the rest
RewriteCond $1|Folder_1|Folder_2|Folder_3 ^([^\|]+)\|(.*?)\|?\1\|?(.*)$
# Now break them up into two folders
RewriteCond %2|%3 ([^\|]+)\|([^\|]+)
# Check the first alternate folder to see if it exists there
RewriteCond %{DOCUMENT_ROOT}/%1/$2 -f [OR]
# If not, make the second option move to the first back reference
RewriteCond %2 ^(.*)$
# Check the second alternate folder to see if it exists there
# (or check the first option again if it succeeded..we could condition
# this out in that case, but I don't know if it's worth adding)
RewriteCond %{DOCUMENT_ROOT}/%1/$2 -f
# If so rewrite to the correct alternate folder
RewriteRule ^([^/]+)/(.*)$ /%1/$2
A RewriteCond directive does only belong to the very next RewriteRule directive. That means you would need to place these RewriteCond directives in front of each RewriteRule:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^Folder_1/(.+) Folder_2/$1 [L,NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^Folder_2/(.+) Folder_3/$1 [L,NC]
By the way: Your second condition %{REQUEST_FILENAME} !-d is probably useless as it only tests for an existing directory.

Resources