.htaccess rewrite cond and rule cannot firgure out extra slash at end - apache

I've been googling around stack overflow trying to figure this out but have had no joy and keep getting errors no matter what I try.
i am currently using this code to rewrite the address to remove extensions, I got it from a SO post a while ago for simple websites:
RewriteEngine on
# To externally redirect /dir/foo.html to /dir/foo
RewriteCond %{THE_REQUEST} ^[A-Z]{3,}\s([^.]+)\.html [NC]
RewriteRule ^ %1 [R=301,L]
# To internally forward /dir/foo to /dir/foo.html
RewriteCond %{REQUEST_FILENAME}.html -f
RewriteRule ^ %{REQUEST_URI}.html [L]
# To externally redirect /dir/foo.html to /dir/foo
RewriteCond %{THE_REQUEST} ^[A-Z]{3,}\s([^.]+)\.phtml [NC]
RewriteRule ^ %1 [R=301,L]
# To internally forward /dir/foo to /dir/foo.html
RewriteCond %{REQUEST_FILENAME}.phtml -f
RewriteRule ^ %{REQUEST_URI}.phtml [L]
(i use phtml files as ui files and php for background files, hence the second block)
This works fine for me but now i am on a site where i would like to feed get variables to a page for bookmarking etc and do not want the address to be some thing like www.website.com/page?var=0
i have managed to get my testing site to load www.website.com/page/ using code from another SO post, but only if i enter that url, it will not rewrite if i go to page.html and will not load the attached files css, js (i understand this is because the files have a relative path) Edit: I now understand this is to do with -f || !-f;
code:
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.html -f
RewriteRule ^([^/]+)/$ $1.html
RewriteRule ^([^/]+)/([^/]+)/$ /$1/$2.html
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !(\.[a-zA-Z0-9]{1,5}|/)$
RewriteRule (.*)$ /$1/ [R=301,L]
I am fine with either having or not having a trailing slash, but I do want to add it when there are variables, like page?var=0 to page/var=0 without the images, js and css stopping. of course if it can all be with a slash then all the better.
Thanks
Edit: Also needs to work when the website and .htaccess are in a subfolder, like: mysite.com/example/websitedemonstration/page

This one seems to work fine for me, give it a try:
Options +FollowSymLinks -MultiViews
RewriteEngine On
RewriteBase /
# To externally redirect /dir/foo.html to /dir/foo
RewriteCond %{THE_REQUEST} ^[A-Z]{3,}\s([^.]+)\.(html|phtml) [NC]
RewriteRule ^ %1 [R=301,L]
# To internally forward /dir/foo to /dir/foo.html
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.html -f
RewriteRule ^([^/]*)/?$ $1.html [L]
# To internally forward /dir/foo to /dir/foo.phtml
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.phtml -f
RewriteRule ^([^/]*)/?$ $1.phtml [L]

Related

How to revert .htaccess changes

Im running apache with xampp. I've done some changes to hide files' type at link. After a while I noticed that adding href with directory, adds same directory again to link like so:
/dir into /dir/dir and then dir/dir/dri ....
and for hrefs at current directory, it sends me to certain page - page that was in script for .htaccess. Guess it's been because my IDE autosaves file as I add it and it had overriden defaults before I've set the right properties.
Code that I put to .htaccess:
RewriteEngine On
# Unless directory, remove trailing slash
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^/]+)/$ http://example.com/folder/$1 [R=301,L]
# Redirect external .php requests to extensionless URL
RewriteCond %{THE_REQUEST} ^(.+)\.php([#?][^\ ]*)?\ HTTP/
RewriteRule ^(.+)\.php$ http://example.com/folder/$1 [R=301,L]
# Resolve .php file for extensionless PHP URLs
RewriteRule ^([^/.]+)$ $1.php [L]
Can I somehow revert this changes / go back to default?
If I delete file, try to override with similar code it still doesn't fix the problem.
DirectorySlash Off
RewriteEngine on
RewriteCond %{THE_REQUEST} \s/+(.*?/)?(?:index)?(.*?)\.(php|html)[\s?/] [NC]
RewriteRule ^ /%1%2 [R=302,L,NE]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^(.*) /$1.php [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME}\.html -f
RewriteRule ^(.*) /$1.html [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !\/$
RewriteRule ^(.*) %{REQUEST_URI}/ [L,R=302]
This works - Extension goes off and works with new files and directories. Previous one I can't repair...

mod_rewrite omit html extension loop

I have the following scenario:
Two frontcontrollers in a web directory (document root):
web/frontend.php # handles all *.html requests
web/backend.php # direct calls only
Rewriting is easy so far:
RewriteCond %{REQUEST_URI} !^/backend.php
RewriteRule (.+)\.html$ /frontend.php [L]
So now when I call example.org/backend.php I'm in the backend, nothing special happens. And when I call something like example.org/ or example.org/team/john.html it is handled by frontend.php.
Works so far!
Now I want the possibility to omit the *.html extension so that example.org/team/john is internally handled as example.org/team/john.html.
RewriteCond %{REQUEST_FILENAME}.html -f
RewriteRule !.*\.html$ %{REQUEST_URI}.html [L]
Last but not least I want to redirect requests to john.html to john to avoid duplicate content.
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} -f
RewriteCond %{REQUEST_URI} ^(.+)\.html$
RewriteRule (.*)\.html$ /$1 [R=301,L]
Every part works on it's own but put together I get a loop, which doesn't surprise me but I don't know how to avoid this. I searched the docs, tried several flags and conditions but I'm totally stuck and I need help.
Here is the whole .htaccess file:
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteBase /
# extend html extension internally
RewriteCond %{REQUEST_FILENAME}.html -f
RewriteRule !.*\.html$ %{REQUEST_URI}.html [L]
# redirect example.html to example
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} -f
RewriteCond %{REQUEST_URI} ^(.+)\.html$
RewriteRule (.*)\.html$ /$1 [R=301,L]
# frontcontroller
RewriteCond %{REQUEST_URI} !^/backend.php
RewriteRule (.+)\.html$ /frontend.php [L]
</IfModule>
Any help would be great.
To avoid a loop, you can use THE_REQUEST
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} -f
RewriteCond %{THE_REQUEST} "\.html "
RewriteRule ^(.*)\.html$ /$1 [R,L]
Unrelated, but you can simplify your rules. First one
RewriteCond %{REQUEST_URI} !^/backend.php
RewriteRule (.+)\.html$ /frontend.php [L]
You already check for (.+)\.html, so you can omit the RewriteCond. Next, you don't use the captured part (.+). Replace it with . to ensure it's not empty. This gives then
RewriteRule .\.html$ /frontend.php [L]
Second one, unless you have *.html.html files in your site, you don't need to check for !html and can just use ^ for the RewriteRule pattern
RewriteCond %{REQUEST_FILENAME}.html -f
RewriteRule ^ %{REQUEST_URI}.html [L]
The loop is because of the multiple internal redirections, You can use END flag to prevent the rewrite loop
RewriteRule ^(.+)\.html$ /$1 [L,R=301]
RewriteCond %{REQUEST_FILENAME}.html -f
RewriteRule !.*\.html$ %{REQUEST_URI}.html [END]

How to avoid rewrite and redirection loop in .htaccess

I am trying this code in my .htaccess file but for some reason when I try a file /1.html in browser, it enters into redirection loop requesting /1 again and again.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^\.]+)$ $1.html [L]
RewriteBase /
RewriteCond %{REQUEST_URI} \.html$
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^(.*)\.html$ $1 [R=302,L]
I have gone through apache documentation and only got that apache can restart processing rewrite rules in some cases. Can anyone help.
Your both rules are doing opposites and will indeed cause infinite looping. To fix you need one redirect rule based on THE_REQUEST variable, as it represents original request received by Apache from your browser and it doesn't get overwritten after execution of other rewrite rules:
RewriteEngine On
## hide .html extension
# To externally redirect /dir/foo.html to /dir/foo
RewriteCond %{THE_REQUEST} \s/+(.+?)\.html [NC]
RewriteRule ^ /%1 [R,L]
## To internally redirect /dir/foo to /dir/foo.html
RewriteCond %{REQUEST_FILENAME}.html -f
RewriteRule ^(.+?)/?$ $1.html [L]

How to remove php extension and also redirect extensions to no extension form

How can I have this in my htaccess:
/page.php => redirects to /page
/page => shows the page.php
/index => redirects to root
And how to remove trailing slashes from all URLs, specially the root one?
Although, I'm not familiar enough with Apache configs, but I could find these codes:
# To remove .php extension
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^\.]+)$ $1.php [NC,L]
# To remove trailing slashes
RewriteRule ^(.*)/$ /$1 [L,R=301]
# To redirect /index to root (not sure if it works correctly)
RewriteCond %{THE_REQUEST} ^.*/index
RewriteRule ^(.*)index.php$ /$1 [R=301,L]
Could you please help me with the scenario and have it in one small code?
Thanks
According to answers, I could solve the problem using the codes below in my .htaccess file:
# To remove .php extension
RewriteCond %{THE_REQUEST} ^[A-Z]{3,}\ (.*)\.php [NC]
RewriteRule ^ %1 [R=301,L]
# To remove trailing slash
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/$ $1 [R=301,L]
# To check whether the file exists then set it back internally
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^.*$ $0.php [L]
# To redirect /index to root
RewriteCond %{THE_REQUEST} ^.*/index
RewriteRule ^(.*)index.php$ /$1 [R=301,L]
Now, I got a new problem and that is when I browse the files with a trailing slash, it redirects me to somewhere else and occurs a 404 (page not found) response, like this:
http://domain.tld/page/ => http://domain.tld/page/home/user/public_html/domain.tld/page
Also, if I move the second part to the end or even remove it completely, the server sends me a 500 (internal server error) response.
Finally with a little research, I could find the solution for previous problem using this advice:
https://stackoverflow.com/a/27264788/5420319
So, I've changed one of the codes from this:
# To remove trailing slash
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/$ $1 [R=301,L]
To this:
# To remove trailing slash
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} /(.*)/$
RewriteRule ^ /%1 [R=301,L]
And I also moved this part to the top regardless of being effective.
According the the answers and my own research, this would be the final answer:
# To remove trailing slash
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} /(.*)/$
RewriteRule ^ /%1 [R=301,L]
# To remove .php extension
RewriteCond %{THE_REQUEST} ^[A-Z]{3,}\ (.*)\.php [NC]
RewriteRule ^ %1 [R=301,L]
# To check whether the file exists then set it back internally
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^.*$ $0.php [L]
# To redirect /index to root
RewriteCond %{THE_REQUEST} ^.*/index
RewriteRule ^(.*)index.php$ /$1 [R=301,L]
Redirecting page.php to /page:
RewriteCond %{THE_REQUEST} ^[A-Z]{3,}\ /page\.php [NC]
RewriteRule ^ /page [R=301,L]
Now, setting back internally to page.php:
RewriteRule ^page$ /page.php [NC,L]
Remove trailing slashes:
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/$ $1 [R=301,L]
Now, checking whether a file for /some/page/foo such that /some/page/foo.php exists:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^.*$ $0.php [L]
A cleaned up and simplified version of the accepted answer is:
# To remove trailing slash
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/$ $1 [R=301,L]
# To remove .php extension
RewriteRule ^(.*)\.php$ $1 [R=301,L]
# To check whether the file exists then set it back internally
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-f
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME}.php -f
RewriteRule ^.*$ $0.php [L]
Options +FollowSymLinks
RewriteEngine on
AddHandler php5.3-fastcgi php
SetEnv no-gzip dont-vary
RewriteRule ^([a-z]+)$ index.php?page=$1 [QSA,L]
RewriteRule ^([a-z]+)/([a-z0-9]+)$ index.php?page=$1&subpage=$2 [QSA,L]
RewriteRule ^([a-z]+)/([a-z0-9]+)/([a-z0-9]+)$ index.php?page=$1&subpage=$2&module=$3 [QSA,L]
RewriteRule ^([a-z]+)/([a-z0-9]+)/([a-z0-9]+)/([a-z0-9]+)$ index.php?page=$1&subpage=$2&module=$3&submodule=$4 [QSA,L]
You can play with that.

htaccess on multidomain setup: other domains don't work

I have a multidomain setup that looks like this on my server … this is a model of the structure:
.htaccess
***my-website
.htaccess
index.php
projects.php
jobs.php
some-project.php
another-project.php
some-job.php
another-job.php***
other-domain
other-domain
other-domain
I have two goals:
1.) The root .htaccess file should just make sure, that my main-domain which is /my-website is run/executed automatically when entering www.my-website.com. Due to the fact that I have a multidomain ftp-server I need do specify that. That is working already.
2.) In my sub-directory /my-website I need some different rules, especially regarding better url design and the omittance of .php extension.
So in /my-website I want to neglect all .php suffixes.
And I want to "fake" directories like /jobs /projects which are actually not directories but php-files themselves.
This is what I have so far thanks to #anubhava in this thread.
DocumentRoot/.htaccess:
RewriteEngine On
RewriteBase /
RewriteRule ^projects/(.+?\.php)$ /$1 [L,NC]
RewriteRule ^jobs/(.+?\.php)$ /$1 [L,NC]
RewriteRule ^(downloads/.+)/?$ assets/$1 [L,NC]
# add .php extension
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{DOCUMENT_ROOT}/$1\.php -f [NC]
RewriteRule ^(.+?)/?$ $1.php [L]
RewriteCond %{REQUEST_URI} !^/my-website/
RewriteCond %{DOCUMENT_ROOT}/my-website%{REQUEST_URI} -f [OR]
RewriteCond %{DOCUMENT_ROOT}/my-website%{REQUEST_URI} -d
RewriteRule ^(.*)$ /my-website/$1 [L]
/my-website/.htaccess:
RewriteEngine On
RewriteBase /my-website/
# add .php extension
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{DOCUMENT_ROOT}/my-website/$1\.php -f [NC]
RewriteRule ^(.+?)/?$ $1.php [L]
However I have the problem now when using this, that in my-website the links without a trailing .php wont work. I want my links to work like /projects but run/exectute /projects.php in my-website. However this doesn't work at the moment, i get a 404.
I also want /projects/some-project to run/execute /some-project.php (where the projects directory doesn't actually exist) which doesn't work either, also 404.
So, to sum it up.
All my domains work now! So my multidomain-setup is save and handeld.
However inside /my-website I want all links to work without trailing .php and with this "faked" directories
So right now this works …
www.my-website.com // works
www.other-domain.com // works
www.my-website.com/projects // doesn't work without trailing .php
www.my-website.com/projects.php // works (runs projects.php)
www.my-website.com/projects/some-project // doesn't work (should run some-project.php)
www.my-website.com/projects/some-project.php // works (runs some-project.php)
Have root .htaccess like this:
RewriteEngine On
RewriteBase /
## COMMENT out these 2 rules
# RewriteRule ^projects/(.+?\.php)$ /$1 [L,NC]
# RewriteRule ^jobs/(.+?\.php)$ /$1 [L,NC]
RewriteRule ^(downloads/.+)/?$ assets/$1 [L,NC]
# add .php extension
RewriteCond %{DOCUMENT_ROOT}/my-website/$1\.php -f [NC]
RewriteRule ^(?:[^/]+/)?([^/]+)/?$ my-website/$1.php [L]
RewriteCond %{HTTP_HOST} ^(www\.)?my-website\.com$ [NC]
RewriteCond %{REQUEST_URI} !^/my-website/ [NC]
RewriteRule ^(.*)$ my-website/$1 [L]
# add .php extension 2
RewriteCond %{DOCUMENT_ROOT}/$1\.php -f [NC]
RewriteRule ^(?:[^/]+/)?([^/]+)/?$ $1.php [L]
/my-website/.htaccess:
RewriteEngine On
RewriteBase /my-website/
# add .php extension
RewriteCond %{DOCUMENT_ROOT}/my-website/$1\.php -f [NC]
RewriteRule ^(?:[^/]+/)?([^/]+)/?$ $1.php [L]
DocumentRoot/.htaccess:
RewriteBase /
RewriteRule ^projects/(.+?\.php)$ /$1 [L,NC]
RewriteRule ^jobs/(.+?\.php)$ /$1 [L,NC]
RewriteRule ^(downloads/.+)/?$ assets/$1 [L,NC]
# add .php extension for REQUEST_FILENAME existing in /
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{DOCUMENT_ROOT}/$1\.php -f [NC]
RewriteRule ^(.+?)/?$ $1.php [L]
# Check if REQUEST_URI is existing as file or directory in /my-website
RewriteCond %{REQUEST_URI} !^/my-website/
RewriteCond %{DOCUMENT_ROOT}/my-website%{REQUEST_URI} -f [OR]
RewriteCond %{DOCUMENT_ROOT}/my-website%{REQUEST_URI} -d
RewriteRule ^(.*)$ /my-website/$1 [L]
# Check if REQUEST_URI is existing as file.php in /my-website
RewriteCond %{REQUEST_URI} !^/my-website/
RewriteCond %{DOCUMENT_ROOT}/my-website%{REQUEST_URI}.php -f
RewriteRule ^(.*)$ /my-website/$1 [L]
/my-website/.htaccess:
RewriteEngine On
RewriteBase /my-website/
# To internally forward /dir/foo to /dir/foo.php
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^(.+?)/?$ $1.php [L]