I have checked a large amount of existing answers regarding .htaccess redirects. However none of them have helped me.
What I want to accomplish is redirecting all request urls to /api/init.php. However I've only gotten so far to where my index page www.example.com simply gives me a file listing because of the missing index.php file, while every url request with a path is working.
How can I accomplish this with .htaccess without ending up with a directory listing on my landing page?
This is as far as I got:
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /api/init.php?path=$1 [NC,L,QSA]
Well your site root is a directory, so this rule you have excludes existing directories. What you could do is only exclude existing files, and allow existing directories to be handled by the PHP script. Like this:
RewriteEngine on
RewriteCond %{REQUEST_URI} !=/api/init.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ /api/init.php?path=$1 [L,QSA]
I removed the NC flag as it's not needed. I added a condition to prevent an unnecessary file-system check.
You don't have to pass the path on in a URL parameter, as you could get it from $_SERVER['REQUEST_URI'] in PHP (not the same as REQUEST_URI in mod_rewrite, in PHP it always has the original URI). If you wanted to do that then your rule becomes nice and simple:
RewriteEngine on
RewriteCond %{REQUEST_URI} !=/api/init.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ /api/init.php [L]
Because the query string will just be passed on unaffected (so QSA is not needed).
I have a few problems with our company website. My colleague left the .htaccess file inside the _control directory like this:
# Virtual site directory
#
# This script lets us make use of default
# versions of files used in a typical site.
# When a request on the site is made for a file
# that doesn't exist, instead of a 404 we rewrite
# the path to /_control/site/
#
# Any file in the directory this script is in will
# take precedence over this script, so this script
# only comes into play if the file does not exist.
# First, set up URL rewriting
Options +FollowSymLinks
RewriteEngine On
# Add trailing slash for directories
# TODO: fix if site not in root dir (e.g. DEV server)
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !.+\.(php|js|css|gif|jpg|jpeg|png)$ [NC]
RewriteCond %{REQUEST_URI} !.*/$
RewriteRule ^(.*)$ /$1/ [L,R=301]
# This Apache mod_rewrite rule checks to see
# if the requested file exists, if it doesn't
# then we rewrite to the respective site location.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !^.*/_control/(admin|common).*$
RewriteCond %{REQUEST_FILENAME} !^.*/_control/site/.*$
RewriteRule ^(.*)$ site/$1 [L]
The structure of my application looks like:
Everything was working OK but about a week ago, our mysite.com/admin and 404 page started redirecting to the hosting company's website. DaveG has already answered first part of the problem here: https://stackoverflow.com/a/26013322/1933380 and I was able to get the virtual directories working. I am still having problems with the 404 page. Am I missing something or making a mistake?
What you are doing now, is telling the webserver to look for all non-existing pages and directories in another folder (_control). This does not give a solution for typo's, non-existing pages etc. If you want to solve this, you could use:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !^.*/_control/(admin|common).*$
RewriteCond %{REQUEST_FILENAME} !^.*/_control/site/.*$
RewriteRule ^(.*)$ site/errhandler.php?file=$1 [L]
and make a file called errhandler.php, which displays a custom 404-page and (for example) give possible alternatives based on a database search or whatever. You could then use $_GET['file'] to display the original filename.
I'm using the Kohana framework. It has the following configuration of .htaccess file:
# Protect application and system files from being viewed
RewriteRule ^(?:application|modules|system)\b.* index.php/$0 [L]
# Allow any files or directories that exist to be displayed directly
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# Rewrite all other URLs to index.php/URL
RewriteRule .* index.php [PT]
I'm particulary interested in the second part Allow any files or directories that exist to be displayed directly. Can someone please elaborate in details on how it's configured?
It is due to 2 condition lines using RewriteCond directive that acts like if condition
RewriteCond %{REQUEST_FILENAME} !-f
Means if request is NOT for a valid file
RewriteCond %{REQUEST_FILENAME} !-d
Means if request is NOT for a valid directory
Both combined with RewriteRule below mean that if request is not a valid file or directory then forward every request to index.php
I need a rule in Apache that redirects not-found CSS files to another location based on their names in another folder. Like this:
Request: localhost/css/nonexistent.css
Response: localhost/css/g/nonexistent.css
If the CSS exists, just serve it like normal:
Request: localhost/css/existent.css
Response: localhost/css/existent.css
My project is on CakePHP which comes with the following rules by default:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php/$1 [QSA,L]
I mention it because whatever the new rule is, it should not break Cake's rules.
Thanks for the help.
Edit: Forgot to mention that the css/g/ file is an alias for a script (inside the Cake MVC stack) that generates the new css file and echoes it. Answers so far seem to do the redirection fine, but then it doesn't find the css/g/file.css either because it really doesn't exist.
Here is a rewrite rule adapted from this SO question and the Apache mod_rewrite docs.
The gist is: If the request is for a path that starts with /css/,get the filesystem path of the requested file and check if it exists. If id doesn't, rewrite the URL for your deeper directory. This should be placed before the rules you posted in your question.
RewriteCond %{REQUEST_URI} ^/css/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^/css/(.*) /css/g/$1
You can try first checking if the /css/g/ css file exists:
# Make sure it doesn't exist
RewriteCond %{REQUEST_FILENAME} !-f
# Make sure this is a request for a css file:
RewriteCond %{REQUEST_URI} ^/css/(.*)\.css$
# See if the /g/ version exists
RewriteCond %{DOCUMENT_ROOT}/css/g/%1.css -f
# rewrite if all conditions satisfied
RewriteRule ^css/(.*)$ /css/g/$1 [L]
The %1 in the 3rd condition backreferences the filename (sans .css extension) matched in the previous RewriteCond.
EDIT:
If the file css file is actually generated, then skip the checking of /g/ version and just pass it to the controller:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} ^/css/(.*)\.css$
RewriteRule ^css/(.*)$ index.php/css/g/$1 [L]
I have a small number of static sites where I simply want to hide the .html extension:
the URL /foo fetches the static file /foo.html
the browser still displays the URL /foo
The client can then send out bookmarks in the style example.com/foo rather than example.com/foo.html.
It sounds very simple, and I've used mod_rewrite happily before (say with WordPress or for redirects), but this is proving much harder to crack that I thought. Perhaps I'm missing something really obvious, but I can't find a solution anywhere and I've been at it all day!
We run our own server, so this can go wherever is the best place.
Addendum
The solution checked below worked fine. Then after running the site awhile I noticed two problems:
all pages began to appear unstyled. I reloaded, cleared the cache, etc., but still no-style. I've had this trouble before, and can't locate the source.
There's a directory AND an HTML file named 'gallery', so the /gallery link shows a directory listing instead of the HTML file. I should be able to sort that one, but further tips welcome :-)
Try this rule:
RewriteCond %{REQUEST_FILENAME}.html -f
RewriteRule !.*\.html$ %{REQUEST_FILENAME}.html [L]
This will rewrite all requests that can be mapped to an existing file when appending a .html.
The previous answers don't check if the requested path is a directory.
Here is the full rewrite condition which doesn't rewrite, if requested path is a directory (as stated by the original question):
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d # is not directory
RewriteCond %{REQUEST_FILENAME}\.html -f # is an existing html file
RewriteRule ^(.*)$ $1.html # rewrite index to index.html
To be SEO friendly and avoid double content, redirect the .html URLs:
# Redirects example.com/file.html to example.com/file
RewriteCond %{REQUEST_FILENAME} !-d # is not directory
RewriteCond %{REQUEST_FILENAME}\.html -f # is an existing html file
RewriteCond %{REQUEST_URI} ^(.+)\.html$ # request URI ends with .html
RewriteRule (.*)\.html$ /$1 [R=301,L] # redirect from index.html to index
If you need the same for scripts take a look here:
How can I use .htaccess to hide .php URL extensions?
The accepted solution do not works when the website is configured with a virtual host / document root.
There is the solution I used:
RewriteEngine on
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME}.html -f
RewriteRule !.*\.html$ %{REQUEST_FILENAME}.html [L]
Look at this post http://alexcican.com/post/how-to-remove-php-html-htm-extensions-with-htaccess/ I haven't tried it yet but the demonstration seems pretty convincing.
Options -MultiViews
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^\.]+)$ $1.php [NC,L]
Wow, I have seldom seen such an issue for which there exists so many "solutions" on the web, where people just throw up what "works for them" but for which few take time to read the documentation to figure out what it does. Many of the solutions given here don't work for virtual hosts, for example.
After much cross-referencing and reading, I want to contribute my own solution that "works for me". Hopefully it works for you, too. I didn't create it from scratch; I was inspired by all the other contributions (even though most of them did not "work for me" without modification).
RewriteEngine on
#if foo requested, return foo.html contents
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-d
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI}\.html -f
RewriteRule ^(.*)$ $1.html [L]
#redirect foo.html to foo
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-d
RewriteRule ^(.+)\.html$ $1 [R,L]
The [R] flag by default does a temporary (302) redirect; if you want a permanent redirect, use R=301 in place of R.
To remove .html extension from .*.html requests, you can use the following script in root/.htaccess :
RewriteEngine On
RewriteBase /
#1) externally redirect "/file.html" to "/file"
RewriteCond %{THE_REQUEST} ^[A-Z]{3,}\s([^.]+)\.html [NC]
RewriteRule ^ %1 [R=301,L]
#2) rewrite "/file" back to "/file.html"
RewriteCond %{REQUEST_FILENAME}.html -f
RewriteRule ^(.*?)/?$ $1.html [NC,L]
the url /foo fetches the static file /foo.html
the browser still displays the url /foo
Apache can do this without mod_rewrite, see documentation:
Multiviews
The effect of MultiViews is as follows: if the server receives a request for /some/dir/foo, if /some/dir has MultiViews enabled, and /some/dir/foo does not exist, then the server reads the directory looking for files named foo.*, and effectively fakes up a type map which names all those files, assigning them the same media types and content-encodings it would have if the client had asked for one of them by name. It then chooses the best match to the client's requirements.
Source: http://httpd.apache.org/docs/current/content-negotiation.html
Here is an example which allows us to store the file on disk as:
foo.html.php
But in the browser, refer to it as
foo.html
To make this work for you, I think you would just need to modify it a bit to match your existing requests, and check for an actual file in place with the .html extension.
# These are so we do not need the .php extension
RewriteCond %{REQUEST_FILENAME} (\.xul|\.html|\.xhtml|\.xml)$',
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME}.php -f',
RewriteRule ^(.*)$ $1.php',