Redirect loop due to htaccess file - apache

The problem I'm having is that the first URL works and the second one doesn't.
http://www.example.com/podcasts
http://www.example.com/podcast
They're both HTML files, so adding .html to the second one will make it work. It's only when the html extension is stripped away (which is what I want to happen) that the redirect problem appears.
I think the issue is that "podcast" is both a folder and an html file. In other words, there is a folder called "podcast" and there is also a file called podcast.html, the extension of which is automatically stripped away (which was my intention).
So how can I fix this redirect issue? I would like the folder and the html to still have the same names and the html extension to be be stripped away, as it is now.
Here's a copy of my .htaccess file (edit: added L flags)
RewriteEngine On
RewriteBase /
#removing trailing slash
RewriteRule ^(.*)/$ $1 [R=301,L]
#non www to www
RewriteCond %{HTTP_HOST} !^www\.
RewriteRule ^(.*)$ http://www.%{HTTP_HOST}/$1 [R=301,L]
#shtml
AddType text/html .html
AddHandler server-parsed .html
#html
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^\.]+)$ $1.html [NC,L]
#index redirect
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /index\.html\ HTTP/
RewriteRule ^index\.html$ http://example.com/ [R=301,L]
Pretty sure that the RewriteRule pertaining to %{REQUEST_FILENAME} !-f is causing the issue. The loop doesn't occur for a 404 error.
Ideas?

Try putting this under your HTML section.
RewriteCond %{REQUEST_FILENAME} !-d
Your -f flag will prevent files from being considered in the rule, but this will exclude directories.

Related

How to .htaccess pseudo-static + hidden extension?

Why can't I use the following?
RewriteRule ^(.*)$ $1.html [L]
.htaccess file:
RewriteRule ^(.*)$ index.php [L]
RewriteCond %{SCRIPT_FILENAME} !-f
RewriteCond %{SCRIPT_FILENAME} !-d
RewriteRule ^(.*)$ $1.html [L]
RewriteRule ^(.*)$ index.php [L]
RewriteCond %{SCRIPT_FILENAME} !-f
RewriteCond %{SCRIPT_FILENAME} !-d
RewriteRule ^(.*)$ $1.html [L]
The first rule rewrites everything to index.php. The directives that follow are effectively ignored.
However, the second rule also rewrites everything (same pattern ^(.*)$ - obvious conflict), that doesn't map to an existing file or directory to append a .html extension. This second rule is more restrictive.
It seems that what you want to do is:
Append the .html extension to URLs that would map to .html files.
Rewrite all other requests that (I assume) do not map to physical files and directories to index.php.
Additional assumptions
The .htaccess file is located in the document root.
Requested URLs that should map to .html files do not contain dots in the URL-path. Therefore, dots in the URL-path indicate file extensions only.
If you literally rewrite everything else to index.php (as you were doing) then it will also rewrite all your static resources (CSS, JS, images, etc.), so I assume you want to make exceptions for static resources and anything that would otherwise map to a file or directory.
Try the following instead:
RewriteEngine On
# Append the ".html" extension if the target file exists
RewriteCond %{DOCUMENT_ROOT}/$1.html -f
RewriteRule ^([^.])$ $1.html [L]
# Rewrite other requests that don't map to files/directories to index.php
RewriteCond %{SCRIPT_FILENAME} !-f
RewriteCond %{SCRIPT_FILENAME} !-d
RewriteRule !\.(?:css|js|jpg|png|gif)$ index.php [L]

Apache Rewrite urls - remove .html and return 404 if .html is present

I am adding a directory to a website that is served with Apache 2 that I want to drop the .html extension from incoming requests. In /new-directory I have a .htaccess file containing:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^\.]+)$ $1.html [NC,L]
So with this rule /new-directory/page works, but /new-directory/page.html also works, which I don't want. I want all pages in new-directory/ and sub-directories to only serve pages without .html, and return a 404 not found if a page.html request comes in.
These are new pages so I don't care about redirecting.
Edit:
Forgot to mention that there is only one file in /new-directory (/new-directory/dhandler) - a Perl script that parses the incoming url if there is a matching database entry. There are no files to match so I can drop that condition.
Figured it out, my fault that I didn't explain that there is only one default file handler in /new-directory which lead to some confusion, see edit above - anyway this worked:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^\.]+)$ $1.html [NC,L]
RewriteCond %{THE_REQUEST} .*\.html[\s\?]{1}
RewriteRule .*\.html$ - [R=404,L]
What messed me up was that sometimes these urls will have query strings so I have to check for both space and ? to match .html in %{THE_REQUEST}.
EDIT: If someone has actual .html files in a directory(instead of one file that dynamically handles all requests like I do) then they should probably add:
RewriteCond %{REQUEST_FILENAME} -f
right after 'RewriteEngine On' To make sure that the incoming request matches an existing file in /new-directory.
You need a couple of rules to do this:
RewriteBase /
RewriteCond %{REQUEST_FILENAME}.html -f
RewriteRule (.*) $1.html [NC,L]
RewriteCond %{THE_REQUEST} .*\.html\s
RewriteRule .*\.html$ - [R=404,L]
The first one checks that there is actually an html file that corresponds to the request. If it does, it will internally rewrite the request to that.
The second rule will redirect anything that ends .html to a 404 not found.
Place this code in /new-directory/.htaccess:
RewriteEngine On
RewriteBase /new-directory/
RewriteCond %{THE_REQUEST} /(?:index)?(.*?)\.html[\s?] [NC]
RewriteRule ^ %1 [R=301,L,NE]
RewriteCond %{REQUEST_FILENAME} !-d
#RewriteCond %{DOCUMENT_ROOT}/new-directory/$1\.html -f [NC]
RewriteRule ^(.+?)/?$ $1.html [L]

trailing slashes in 301 redirect

I've tried to look through the multiple mod_rewrite questions, so I apologize if this is a duplicate.
I'm trying set it so that if you go to domain.com/about.php it removes .php and if you go to domain.com/about it simply remains like that.
Options +FollowSymlinks
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)$ /$1.php [L,QSA]
RewriteRule ^(.*)/$ /$1 [L,R=301]
So, right now if you go to domain.com/about it displays the page, but if you go to domain.com/about.php it doesn't remove the extension.
Additionally, I have 301 redirects
redirect 301 /our-clients http://www.domain.com/about-ourclients
That works perfect, but if the user goes to domain.com/our-clients/ with the trailing slash, they are directed to about-ourclients.php
Any advice on how to rewrite my rules?
This should do the job:
Options +FollowSymlinks
RewriteEngine On
RewriteBase /
# remove .php ONLY if requested directly
RewriteCond %{THE_REQUEST} (\.php\sHTTP/1)
RewriteRule ^(.+)\.php$ /$1 [R=301,L,QSA]
# remove trailing slash ONLY if it is not an existing folder
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/$ /$1 [L,R=301]
# rewrite to FILENAME.php if such file does exist and is not a folder
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^(.*)$ /$1.php [L,QSA]
It will redirect all direct requests to php files: /something.php will be redirected to /something
Will remove the trailing slash IF requested resource is not directory. So if you requesting /home/ and you do have such folder, then it will NOT be redirected to /home.
Will internally rewrite requests to the same named PHP file IF it does exist. If you are requesting /about and you have /about.php then it will do rewrite; If you have no /about.php then nothing happens (well, at least not on these rules -- if you have more rules then such request can be matched later .. or 404 error page will be shown).
If you are requesting /about, you have /about.php and you also have /about folder, then request will go into folder. If you do not want this to happen ( /about should always be rewritten to /about.php) then you need to remove RewriteCond %{REQUEST_FILENAME} !-d from last block. But since you have exactly the same condition in your current .htaccess then I assume it is desired behaviour.

.htaccess Rewrite Within Directory - Hide PHP extension and force trailing slash

I'm trying to hide the .php extension from my files as well as force a trailing slash on the resulting URLs.
Example: A request to /about.php would become /about/ and requests to /about would go to /about/.
The following rewrite code worked perfectly when I was in the root of my hostdomain:
RewriteEngine On
RewriteRule ^(.*)/$ /$1.php [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !(.*)/$
RewriteRule ^(.*)$ http://edit.mydomain.org/$1/ [R=301,L]
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /(.*)\.php\ HTTP/ [NC]
RewriteRule .+ http://edit.mydomain.org/%1 [R=301,QSA]
However, I need to move my files into a directory of this host name. Adding a directory name to the rules and having the .htaccess in the directory itself didn't work at all and seems to cause a endless redirect.
I looked around StackOverflow and other websites and tried numerous examples and ended up with many different errors with the most common being:
Everything is an endless redirect.
Everything except the directory home page is a 500 Error.
about.php redirects to /about but there's no redirect to /about/ and /about/ displays a 500 Error.
Everything working, but the home page (of the directory) index.php when accessed without a filename goes into an endless redirect.
Things redirect to edit.mydomain.org/home/username/public_html/mydomain.org/edit/pagename.php which obviously doesn't exist.
Thanks for any help! I really need to keep these files in a directory although the .htaccess could go into the host name root if its needed.
The directory for this would be edit.mydomain.org/dave/
Save this as a .htaccess and put it in the 'dave' directory
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !\..+$
RewriteCond %{REQUEST_URI} !/$
RewriteRule ^(.*)$ http://edit.mydomain.org/dave/$1/ [R=301,L]
RewriteRule ^(.*)/$ $1.php [L]
This works for me
RewriteBase /
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.html -f
RewriteRule ^(.*)$ $1.html

Multiple RewriteConds and RewriteRule Stacked Together

I have this apache rewrite rule:
RewriteEngine on
RewriteBase /
RewriteCond %{HTTP_HOST} mycompany.com
RewriteRule ^$ http://mycompany.com/login [L]
# we check if the .html version is here (caching)
RewriteRule ^$ index.html [QSA]
RewriteRule ^([^.]+)$ $1.html [QSA]
RewriteCond %{REQUEST_FILENAME} !-f
# no, so we redirect to our front web controller
RewriteRule ^(.*)$ index.php [QSA,L]
The only thing I can make sense of is if it's mycompany.com, then the script will redirect to http://mycompany.com/login. If not, then ...
I can't figure out already.
Any idea what does the above script say?
Something quite interesting, not easy to understand.
A google search on the comment texts inside the code gave interesting results: http://www.google.com/search?q=%22%23+we+check+if+the+.html+version+is+here+%28caching%29%22
Edit: if we look at the last lines and knowing that Symfony uses caching (it creates local files with .html extension in the same directories as the URL shows 'em) I can try to explain the lines here
If the requested url is something like http://yoursite.com/blabla/ we try to open an index.html file in that directory. If the file is not there, another cycle of rewriting will happen and the last Cond will be hit (where the file does not exist)
RewriteRule ^$ index.html [QSA]
If something more is in the url, like http://yoursite.com/blabla/blblbl, try to find a file blblbl.html
RewriteRule ^([^.]+)$ $1.html [QSA]
This is the collector of all urls that did not match any of the previous rules or the cached file did not exist:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php [QSA,L]