MultiViews is *too* tolerant of bad URLs - apache

When I enable MultiViews, if I visit bad URLs, the my page (index.php) is still reached, when I want the user to get a 404 error instead. I'm trying to figure out how to fix this without creating rules in my .htaccess.
For example, "www.mydomain.com/index/blah/blah", visits index.php, but I want it to fail due to the extraneous trailing garbage URL components. Similarly for "/contact/blah/awuihda/hiu", which shows the content of contact.php, should give a 404 error, because "/blah/awuihda/hiu" doesn't exist.
If I disable MultiViews it works fine, but then I can't abbreviate the URL as much as I want to (for example, can't type "/contact" to bring up "contact.php").

You could just use the following so the .php extension is not required, which is the usual approach:
RewriteEngine on
# Remove .php if it's present with a 301 redirect
RewriteRule ^(.+)\.php$ $1 [R=301,L]
# If a request doesn't exist as a directory, file or symlink
# and it does exist with .php appended, rewrite to that
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^(.+)$ $1.php [L]
I know it's adding a rule to .htaccess but it's a one off that works for everything and also means you're not hitting potential duplicate content allowing the same thing to be served with or without .php (or indeed with anything at all trailing after it as in your examples). Hope it's useful.
It could go in main server config but would need altering.

I found a solution which works for me.
Options -Indexes SymLinksIfOwnerMatch -MultiViews
RewriteEngine On
RewriteBase /
RewriteCond %{THE_REQUEST} ^[A-Z]{3,}\s([^.]+)\.php [NC]
RewriteRule ^ %1 [R=301,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^([^\.]+)$ $1.php [NC,L]
Source: link

Related

Chaining multiple required rewrites in .htaccess

I have at present 2 rewrites that are supposed to occur on any given url,
The first redirects any url matching the pattern %DOMAIN%/mcc-* to show.php?id=mcc-*
The second redirects any url without the .php extension to the page as if it had one.
The first rewrite gets called and works, but the second does not.
I have tried swapping the places of the rewrites, but the result is the same, the 'Add Extension' rewrite is never called, even on pages that don't redirect to show.php
ErrorDocument 404 /error/404.php
Options All -Indexes -MultiViews
RewriteEngine On
# Silent Redirect from any url ending with mcc-* to show.php?id=mcc-*
# This works as intended.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(mcc-[\d]+)/?$ show.php?id=$1 [QSA,NC]
# Allow urls to not include the .php extension
# This is not not being called.
RewriteBase /
RewriteCond %{REQUEST_URI}/$1.php -f [NC]
RewriteRule ^(.+?)/?$ $1.php [L]
Is there someway to get both of these conditionals to run, or at the very least run the second if the first doesn't match?
With your shown samples please try following .htaccess rules file. Please make sure to clear your browser cache before testing your URLs.
ErrorDocument 404 /error/404.php
Options All -Indexes -MultiViews
RewriteEngine ON
# Allow urls to not include the .php extension
# This is not not being called.
RewriteBase /
RewriteCond %{DOCUMENT_ROOT}/$1.php -f [NC]
RewriteRule ^(.+?)/?$ $1.php [L]
# Silent Redirect from any url ending with mcc-* to show.php?id=mcc-*
# This works as intended.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(mcc-[\d]+)/?$ show.php?id=$1 [QSA,NC]

.htaccess extensionless pages, 404 when extension is included

I'm in the process of cleaning my page's URLs by removing their file extensions, and the web is quick to offer the following .htaccess code:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^(.*)$ /$1.php
It works, but one can still access files by adding .php at the end like before. I don't want this! Idealy I want every visited page ending with .php to be perceived as what's typed just without the .php part. Would this be achieveable?
To sum up:
www.page.com/example.php displays 404
www.page.com/example displays example.php
Thanks in advance.
You're probably not still looking for an answer here, but just in case someone stumbles across this, here's how you do that:
First, do an external redirect:
## hide .php extension
## To externally redirect /dir/foo.php to /dir/foo
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{THE_REQUEST} ^[A-Z]{3,}s([^.]+).php [NC]
RewriteRule ^ %1 [R,L,NC]
Then, do a internal redirect:
## To internally forward /dir/foo to /dir/foo.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*?)/([a-zA-Z0-9_-]+)/([0-9]+)$ /new/$1.php?ID=$3 [L]
That'll get you there! If it doesn't work, make sure these are at the top of your htaccess file:
RewriteEngine On
RewriteOptions inherit
Options +FollowSymlinks
Options -Multiviews
That's it! I explain the coding on my blog: http://kimjoyfox.com/writing-seo-friendly-urls-using-htaccess/

RewriteRule not working fine

I wrote the following rule in .htaccess
Options +FollowSymLinks
RewriteEngine on
RewriteRule ^(.*)/$ profile.php?business=$1
When i enter the URL like
http://www.abc.com/mujeeb/
page is correctly transfered to profiles page and page looks fine.
But i enter this in URL
http://www.abc.com/mujeeb
page doesn't show.
Can you please tell why? Or write the rule for this? i tried many times but not sucessful.
Mujeeb.
page doesn't show. because you specified that you RewriteRule is applied to the URL's ending with / at the end. Rewrite it as
RewriteRule ^(.*)/?$ profile.php?business=$1 [L]
And I hope that you have additional RewriteCond statements in order to prevent the infinite loop with redirects.
ps: basically you can prevent loop in two way
1) checks that requested url does not correspond to the existing file or directory. it is, probably, the best way to do (read comments to the second method)
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/?$ profile.php?business=$1 [L]
2) checks that you are requesting not the file from RewriteRule. This method is not good, because for each request, even for existing files and directories, it calls profile.php script
RewriteCond %{REQUEST_URI} !profile\.php$
RewriteRule ^(.*)/?$ profile.php?business=$1 [L]
It is because you check for the trailing slash with ^(.*)/$. If you add a question mark, the trailing slash will be optional.
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^(.*)/?$ profile.php?business=$1
The RewriteCond is neccessary to make sure the Rule will only be applied once. Otherwise Apache will be caught in an infinite loop.
Try this:
Options +FollowSymLinks
RewriteEngine on
RewriteRule ^(.*)[/]?$ profile.php?business=$1
That makes the last slash optional.
Well you rule is checking for a trailing slash in URI and that's the reason /mujeeb/ works but /mujeeb does not. Change your code to:
Options +FollowSymLinks -MultiViews
# Turn mod_rewrite on
RewriteEngine On
# If the request is not for a valid file
#RewriteCond %{REQUEST_FILENAME} !-d
# If the request is not for a valid directory
#RewriteCond %{REQUEST_FILENAME} !-f
# your rule without trailing slash
RewriteRule ^(.*)$ profile.php?business=$1 [L,QSA]
Plenty of good answers already. My answer is a bit different.
This is what I usually do. If the requested URL doesn't end with a /, I make the browser redirect to a URL with the trailing /. This is consistent with the default behaviour of Apache (due to mod_dir). So, this is how I solve this problem.
RewriteEngine On
# Canonicalize http://example.com/mujeeb to http://example.com/mujeeb/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)([^/])$ /$1$2/ [R=307,L]
# Let profile.php process http://example.com/mujeeb/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/$ profile.php?business=$1

htaccess remove index.php from url

I have a problem whereby google has indexed some pages with the wrong url.
The url they are indexing is:
http://www.example.com/index.php/section1/section2
I need it to redirect to:
http://www.example.com/section1/section2
.htaccess isn't my forte, so any help would be much appreciated.
The original answer is actually correct, but lacks explanation. I would like to add some explanations and modifications.
I suggest reading this short introduction https://httpd.apache.org/docs/2.4/rewrite/intro.html (15mins) and reference these 2 pages while reading.
https://httpd.apache.org/docs/2.4/mod/mod_rewrite.html
https://httpd.apache.org/docs/2.4/rewrite/flags.html
This is the basic rule to hide index.php from the URL. Put this in your root .htaccess file.
mod_rewrite must be enabled with PHP and this will work for the PHP version higher than 5.2.6.
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*) /index.php/$1 [L]
Think %{REQUEST_FILENAME} as the the path after host.
E.g. https://www.example.com/index.html, %{REQUEST_FILENAME} is /index.html
So the last 3 lines means, if it's not a regular file !-f and not a directory !-d, then do the RewriteRule.
As for RewriteRule formats:
So RewriteRule (.*) /index.php/$1 [L] means, if the 2 RewriteCond are satisfied, it (.*) would match everything after the hostname. . matches any single character , .* matches any characters and (.*) makes this a variables can be references with $1, then replace with /index.php/$1. The final effect is to add a preceding index.php to the whole URL path.
E.g. for https://www.example.com/hello, it would produce, https://www.example.com/index.php/hello internally.
Another key problem is that this indeed solve the question. Internally, (I guess) it always need https://www.example.com/index.php/hello, but with rewriting, you could visit the site without index.php, apache adds that for you internally.
Btw, making an extra .htaccess file is not very recommended by the Apache doc.
Rewriting is typically configured in the main server configuration
setting (outside any <Directory> section) or inside <VirtualHost>
containers. This is the easiest way to do rewriting and is recommended
To remove index.php from the URL, and to redirect the visitor to the non-index.php version of the page:
RewriteCond %{THE_REQUEST} ^GET.*index\.php [NC]
RewriteRule (.*?)index\.php/*(.*) /$1$2 [R=301,NE,L]
This will cleanly redirect /index.php/myblog to simply /myblog.
Using a 301 redirect will preserve Google search engine rankings.
RewriteEngine On
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /(.*)index\.php($|\ |\?)
RewriteRule ^ /%1 [R=301,L]
Assuming the existent url is
http://example.com/index.php/foo/bar
and we want to convert it into
http://example.com/foo/bar
You can use the following rule :
RewriteEngine on
#1) redirect the client from "/index.php/foo/bar" to "/foo/bar"
RewriteCond %{THE_REQUEST} /index\.php/(.+)\sHTTP [NC]
RewriteRule ^ /%1 [NE,L,R]
#2)internally map "/foo/bar" to "/index.php/foo/bar"
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.+)$ /index.php/$1 [L]
In the spep #1 we first match against the request string and capture everything after the /index.php/ and the captured value is saved in %1 var. We then send the browser to a new url.
The #2 processes the request internally. When the browser arrives at /foo/bar , #2rule rewrites the new url to the orignal location.
Steps to remove index.php from url for your wordpress website.
Check you should have mod_rewrite enabled at your server.
To check whether it's enabled or not - Create 1 file phpinfo.php at your root folder with below command.
<?php
phpinfo?();
?>
Now run this file - www.yoursite.com/phpinfo.php and it will show mod_rewrite at Load modules section.
If not enabled then perform below commands at your terminal.
sudo a2enmod rewrite
sudo service apache2 restart
Make sure your .htaccess is existing in your WordPress root folder, if not create one .htaccess file
Paste this code at your .htaccess file :-
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
Further make permission of .htaccess to 666 so that it become writable and now you can do changes in your wordpress permalinks.
Now go to Settings -> permalinks -> and change to your needed url format.
Remove this code /index.php/%year%/%monthnum%/%day%/%postname%/
and insert this code on Custom Structure: /%postname%/
If still not succeeded then check your hosting, mine was digitalocean server, so I cleared it myself
Edited the file /etc/apache2/sites-enabled/000-default.conf
Added this line after DocumentRoot /var/www/html
<Directory /var/www/html>
AllowOverride All
</Directory>
Restart your apache server
Note: /var/www/html will be your document root
Do the following steps
1. Make sure that the hosting / your pc mod_rewrite module is active. if not active then try to activate in a way, open the httpd.conf file. You can check this in the phpinfo.php to find out.
change this setting :
#LoadModule rewrite_module modules/mod_rewrite.so
to be and restart wamp
LoadModule rewrite_module modules/mod_rewrite.so
2. Then go to .htaccess file, and try to modify to be:
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)\?*$ index.php/$1 [L,QSA]
if above does not work try with this:
RewriteEngine on
# if a directory or a file exists, use it directly
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# otherwise forward it to index.php
RewriteRule . index.php
3. Move .htaccess file to root directory, where is index.php there.
www OR root folder
- index.php
- .htaccess
Some may get a 403 with the method listed above using mod_rewrite. Another solution to rewite index.php out is as follows:
<IfModule mod_rewrite.c>
RewriteEngine On
# Put your installation directory here:
RewriteBase /
# Do not enable rewriting for files or directories that exist
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /index.php/$1 [L]
</IfModule>
I have used many codes from the above mentioned sections for removing index.php form the base url. But it was not working from my end. So, you can use this code which I have used and its working properly.
If you really need to remove index.php from the base URL then just put this code in your htaccess.
RewriteCond %{THE_REQUEST} ^GET.*index\.php [NC]
RewriteRule (.*?)index\.php/*(.*) /$1$2 [R=301,NE,L]
This will work, use the following code in .htaccess file
RewriteEngine On
# Send would-be 404 requests to Craft
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !^/(favicon\.ico|apple-touch-icon.*\.png)$ [NC]
RewriteRule (.+) index.php?p=$1 [QSA,L]
I don't have to many bulky code to give out just a little snippet solved the issue for me.
i have https://example.com/entitlements/index.php rather i want anyone that types it to get error on request event if you type https://example.com/entitlements/index
you will still get error since there's this word "index" is contained there will always be an error thrown back though the content of index.php will still be displayed properly
cletus post on "https://stackoverflow.com/a/1055655/12192635" which
solved it
Edit your .htaccess file with the below
to redirect people visiting https://example.com/entitlements/index.php to 404 page
RewriteCond %{THE_REQUEST} \.php[\ /?].*HTTP/
RewriteRule ^.*$ - [R=404,L]
to redirect people visiting https://example.com/entitlements/index to 404 page
RewriteCond %{THE_REQUEST} \index[\ /?].*HTTP/
RewriteRule ^.*$ - [R=404,L]
Not withstanding we have already known that the above code works with already existing codes on stack see where i applied the code above just below the all codes at it end.
# The following will allow you to use URLs such as the following:
#
# example.com/anything
# example.com/anything/
#
# Which will actually serve files such as the following:
#
# example.com/anything.html
# example.com/anything.php
#
# But *only if they exist*, otherwise it will report the usual 404 error.
Options +FollowSymLinks
RewriteEngine On
# Remove trailing slashes.
# e.g. example.com/foo/ will redirect to example.com/foo
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)/$ /$1 [R=permanent,QSA]
# Redirect to HTML if it exists.
# e.g. example.com/foo will display the contents of example.com/foo.html
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}.html -f
RewriteRule ^(.+)$ $1.html [L,QSA]
# Redirect to PHP if it exists.
# e.g. example.com/foo will display the contents of example.com/foo.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^(.+)$ $1.php [L,QSA]
RewriteCond %{THE_REQUEST} \.php[\ /?].*HTTP/
RewriteRule ^.*$ - [R=404,L]
RewriteCond %{THE_REQUEST} \index[\ /?].*HTTP/
RewriteRule ^.*$ - [R=404,L]
try this, it work for me
<IfModule mod_rewrite.c>
# Enable Rewrite Engine
# ------------------------------
RewriteEngine On
RewriteBase /
# Redirect index.php Requests
# ------------------------------
RewriteCond %{THE_REQUEST} ^GET.*index\.php [NC]
RewriteCond %{THE_REQUEST} !/system/.*
RewriteRule (.*?)index\.php/*(.*) /$1$2 [R=301,L]
# Standard ExpressionEngine Rewrite
# ------------------------------
RewriteCond $1 !\.(css|js|gif|jpe?g|png) [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /index.php/$1 [L]
</IfModule>
For more detail
create .htaccess file on project root directory and put below code for remove index.php
RewriteEngine on
RewriteCond $1 !^(index.php|resources|robots.txt)
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php/$1 [L,QSA]

How to rewrite /foo-bar to foo-bar.html but /foo/bar to foo-bar.html using mod_rewrite?

How to rewrite /foo-bar to foo-bar.html but /foo/bar to foo--bar.html using mod_rewrite?
In other words, replace all slashes in the request URI with --, then append .html.
I wrote the following code:
RewriteEngine On
RewriteBase /
# Take care of /foo/bar and /foo-foo/bar-bar
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([a-z0-9-]+)/([a-z0-9-]+)/?$ $1--$2.html [L]
# Take care of /foo, or /foo-bar-baz-whatever-no-slashes
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([a-z0-9-]+)/?$ $1.html [L]
This seems to work on some servers but on mine it seems to mess up the rewrites:
The requested URL /foo.html/bar was not found on this server.
It seems to append the .html too early.
Any ideas on how to fix this, and what is causing it to fail on this particular server?
I'm not sure why your example isn't working. Supplying the apache vesion you are using would help a lot. I was able to replicate the issue with Apache/2.2.14
If you remove the RewriteBase Directive and go with
Apache/2.2.14
RewriteEngine On
# Take care of /foo/bar and /foo-foo/bar-bar
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^/([a-z0-9-]+)/([a-z0-9-]+)/?$ /$1--$2.html [L]
# Take care of /foo, or /foo-bar-baz-whatever-no-slashes
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^/([a-z0-9-]+)/?$ /$1.html [L]
you should have better luck.
In the future look turn up your log level for easier debugging of what's going on.
#don't leave this on in production
RewriteLog "/private/var/log/apache2/rewrite.log"
RewriteLogLevel 5
One case where this seems to happen is when MultiViews is enabled, but AcceptPathInfo is set to Off (or Default and the handler doesn't accept path info), and foo.html exists.
Apache notices that your request for /foo/bar doesn't point to a real resource, and maps it to /foo.html with the path info of /bar. Because path info is not allowed, Apache returns a 404 for the request. Likewise, mod_rewrite doesn't perform a rewrite because /foo.html now is an existing file.
The solution for this scenario would be to turn off MultiViews in your .htaccess file:
Options -MultiViews