Removing .php extension except sub directory called enquire - .htaccess

Please assist me to stop this from removing the ".php" extension in sub directories eg: https://www.example.com/enquire/contactmail instead of: https://www.example.com/enquire/contactmail.php
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-d
\#####exclude /cp folder####
RewriteCond %{REQUEST_URI} !^/enquire
RewriteCond %{REQUEST_FILENAME}\\.php -f
RewriteRule ^(.\*)$ $1.php
RewriteCond %{THE_REQUEST} ^\[A-Z\]{3,9}\\ /((?!cp)\[^.\]+)\\.php
RewriteRule ^/?(.\*)\\.php$ /$1 \[NC,L,QSA,R=301\]
RewriteRule ^enquire/(.\*)$ contactmail.php?s=$1 \[NC,L,QSA\]
RewriteRule ^enquire/(\[0-9\]+)$ contactmail.php?a=$1 \[NC,L,QSA\]

As I understand you have a working solution in place to rewrite incoming requests without ".php" extension to internal resources with that "file name extension".
And now you ask how you can add an exception from that, so that the internal rewrite does not get applied to requests, that target resources inside certain folders in the requested path, physical or virtual folders.
If that is correct then indeed you should implement an exception for those requests. Exceptions should get implemented before more general rules. So further up in the configuration file since that is processed from top to bottom.
That should roughly be what you are looking for:
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-d
# exception for the /enquire request path
RewriteRule ^enquire/(\d+)$ contactmail.php?a=$1 [NC,END,QSA]
RewriteRule ^enquire/(.*)$ contactmail.php?s=$1 [NC,END,QSA]
# redirect requests that specify a ".php" extension
RewriteRule ^(.*)\.php$ $1 [NC,L,QSA,R=301]
# rewrite requests if a corresponding php file exists
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^ %{REQUEST_URI}.php

Just Use the blow .htaccess to remove the .php extension
IndexIgnore * # prevent directory listing
Order deny,allow
Allow from *
# ------------------------------------------
# Rewrite so that php extentions are not shown
RewriteEngine on
#.php URL Rewrite
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^(.*)$ $1.php

Related

Different .htaccess rewrite rules for new directory

My .htaccess currently has the following behaviour using the rewrite rules below:
https://example.com/abcd?lol=true
if file /abcd.php exists, open https://example.com/abcd.php?lol=true
if directory and file /abcd/index.php exist, open https://example.com/abcd/index.php?lol=true
else open https://example.com/index.php?lol=true
-> in all three cases the address bar must still show https://example.com/abcd?lol=true
RewriteEngine On
RewriteCond %{HTTPS} !=on
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
RewriteEngine on
RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC]
RewriteRule ^(.*)$ https://%1%{REQUEST_URI} [R=301,QSA,NC,L]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/$ /$1 [L,R=301]
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^(.*)$ $1.php [END]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ / [END]
Now to my question: I have a new directory /blog/, where the following must happen:
https://example.com/blog/abcd?lol=true
open https://example.com/blog/index.php?lol=true
-> the address bar must still show https://example.com/blog/abcd?lol=true so I can use php to read the abcd part, which could be an article name.
How can I append my .htaccess code to achieve this?
Aside: You're not actually doing anything for #2 (ie. "if directory and file /abcd/index.php exist...") - you are probably relying on default behaviour by mod_dir. However, if you request /abcd?lol=true and /abcd exists as a physical directory, there will be a 301 external redirect to append the trailing slash (ie. /abcd/?lol=true ) which will then result in /abcd/index.php being served. So, this does not strictly show /abcd?lol=true in the address bar as you suggest. Is that what you are seeing?
To implement the /blog/abcd?lol=true to /blog/index.php?lol=true rewrite then replace your last rule with the following:
# Prevent further processing if a file or directory is requested directly
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [END]
# Route requests to blog/index.php
RewriteRule ^blog/. blog/index.php [END]
# Everthing else is routed to "/index.php"
RewriteRule . index.php [END]
This separates out the filesystem checks into their own rule so you aren't doing this twice.
Your previous "last" rule:
RewriteRule ^(.*)$ / [END]
You were only rewriting to / and then relying on mod_dir issuing an internal subrequest for index.php (the DirectoryIndex). You should instead rewrite directly to index.php as required (no need for the slash prefix). The capturing pattern ^(.*)$ is unnecessary here.

How can I rewrite a 'subfolder' to a script?

I need to redirect a URL example.com/servers/1/ to a PHP script (example.com/serverinfo.php) that recieves the 1 part of the requested URL as a GET variable (or similar).
I currently have a rule RewriteRule ^([^/.]+)$ $1.php that rewrites URLs such as example.com/servers to example.com/[file].php, and tried to base the following rule off that:
RewriteRule ^/?servers/([0-9]+)$/ /serverinfo.php$
The new rule has no effect (other than causing the page's CSS to fail to load), what am I doing wrong?
You can use:
Options -MultiViews
RewriteEngine On
# handle /servers/123
RewriteRule ^/?servers/([0-9]+)/?$ /serverinfo.php?num=$1 [L,QSA,NC]
# add .php extension
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^(.+?)/?$ $1.php [L]

Htaccess files and url rewriting

I have 2 questions.
I am currently using wamp server to serve my website.
The homepage is 'localhost/prefix/index.php'
Question 1:
a. I would like it so my home page is:
'localhost/prefix/'
instead of
'localhost/prefix/index.php
b. I would like it so:
'localhost/prefix/admin/profile.php'
is
'localhost/prefix/admin/profile'
How do I go about doing this (I have googled and I am very confused by the syntax)?
Question 2
If I have a url like
'localhost/prefix/games?title=hi'
how can I make it so the url is like this:
'localhost/prefix/games/hi'
Thanks in advance!!
I really have got lost.
EDITED::///
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^(.*)$ $1.php [R]
Is what I have so far.. It does nothing... But everyone says it should! (the htaccess file is doing something because if I do something random, it throws up errors).
EDITED::///
This seems to remove .php and index.php from the url:
RewriteEngine On
RewriteBase /prefix/
# remove .php; use THE_REQUEST to prevent infinite loops
RewriteCond %{THE_REQUEST} ^GET\ (.*)\.php\ HTTP
RewriteRule (.*)\.php$ $1 [R=301]
# remove index
RewriteRule (.*)/index$ $1/ [R=301]
# remove slash if not directory
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} /$
RewriteRule (.*)/ $1 [R=301]
# add .php to access file, but don't redirect
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteCond %{REQUEST_URI} !/$
RewriteRule (.*) $1\.php [L]
Problem now is that my prefix base is not working so it ends up going to
localhost/something/something
rather than
localhost/prefix/something/something
Any ideas?
EDITED::///
I have sussed out that the above code actually works perfectly if the page i'm directing to is in a sub folder. so for example.. this will work:
localhost/prefix/admin/dashboard
But this (because the file is in the root directory, doesn't)
localhost/prefix/login.php
it redirects me to
localhost/login
Any ideas?
EDIT::///
If you are having problems getting it to work. close your browser down and restart... I had caching issues.
This code above will remove .php and also remove index.php.

Forcing the rewriting of URLs by hiding .php AND .htm(l) extensions and redirecting to extensionless URLs

here is my configuration:
http://domain.com (obviously fictitious name...) hosted on a server running Apache with mod_rewrite enabled
folder named "foo": (located at http://domain.com/foo/ and in which I want to put my .htaccess file) containing only 3 types of files .php, .htm, .html
.php files (for the sake of the example I will refer to one of them: phpfile.php)
.htm files (for the sake of the example I will refer to one of them: htmfile.htm)
.html files (for the sake of the example I will refer to one of them: htmlfile.html)
within the foo folder, no file has an equivalent with another extension or without extension (ie eg neither phpfile.htm nor phpfile.html nor phpfile exist in foo, only php.file.php does exist)
Here is what I am trying to achieve:
when entering http://domain.com/foo/phpfile.php or http://domain.com/foo/htmfile.htm or http://domain.com/foo/htmlfile.html in my browser's address bar and hitting "Enter":
I get redirected with a 301 to http://domain.com/foo/phpfile or http://domain.com/foo/htmfile or http://domain.com/foo/htmlfile (depending on the file I've chosen), that is to say that those latters are the URLs now displayed in the address bar
when entering http://domain.com/foo/phpfile or http://domain.com/foo/htmfile or http://domain.com/foo/htmlfile in my browser's address bar and hitting "Enter":
I don't get redirected, nothing changes in the address bar but instead the server just serves me the phpfile.php or the htmfile.htm or the htmlfile.html, depending on which one I requested
I have been trying hard on this, and sofar I've came with this content for my .htaccess file (located in the "foo" folder), which is unfortunately only working in the last of the two cases, in which I am interested (ie serving "phpfile.php" when I request "phpfile", serving "htmfile.htm" when I request "htmfile" or serving "htmlfile.html" when I request "htmlfile"), and which is ignoring the 301 redirections:
Options +FollowSymLinks
RewriteEngine on
RewriteBase /foo
# Redirect permanently the requests for existing .php files
# to extensionless files (non present on the server)
# so that phpfile.php gets redirected to phpfile
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} \.php$
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule (.*)\.php$ $1 [R=301,NC]
# Redirect permanently the requests for existing .htm(l) files
# to extensionless files (non present on the server)
# so that htmfile.htm gets redirected to htmfile
# so that htmlfile.html gets redirected to htmlfile
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} \.html?$
RewriteCond %{REQUEST_FILENAME}\.html? -f
RewriteRule (.*)\.html?$ $1 [R=301,NC]
# Matching requests for non existing extensionless files
# with their existing equivalent on the server
# so that domain.com/foo/phpfile will display
# the contents of domain.com/foo/phpfile.php,
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule (.*)$ $1.php [L]
# so that domain.com/foo/htmlfile will display
# the contents of domain.com/foo/htmlfile.html,
RewriteCond %{REQUEST_FILENAME}\.html -f
RewriteRule (.*)$ $1.html [L]
# so that domain.com/foo/htmfile will display
# the contents of domain.com/foo/htmfile.htm,
RewriteCond %{REQUEST_FILENAME}\.htm -f
RewriteRule (.*)$ $1.htm [L]
Thank you in advance for any help/ advice.
There's a logic flaw in the first two rules in that it's the php or html file that exists. The URI check is also in effect a duplicate of the rewrite rule pattern and !f implies !-d. You can also fold these into a single rule:
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^(.*?)\.(php|html?)$ $1 [R=301,NC]
The last two are OK, but I'd swap the order if html requests are more common than php
Why MultiViews doesn't help
Options +MultiViews implements a concept known as content negotiation, and in doing this Apache invokes a subquery to parse the filename root name. One of the things that it does is to scan the directory for known filename.extension combinations so in this case if xxx.php exists and your request is for xxx then it will substitute xxx.php and do an internal redirection, which then causes your first rule to fire, removing the .php extension and this causes the error that you see.
So (i) you need to disable multiviews, and (ii) ditto subqueries; (iii) detect and prevent retry loops. This is one solution which will do what you want:
Options +FollowSymLinks -MultiViews
RewriteEngine on
RewriteBase /foo
RewriteCond %{ENV:REDIRECT_END} =1
RewriteRule ^ - [L,NS]
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^(.*?)\.(php|html?)$ $1 [R=301,NC,NS]
RewriteCond %{REQUEST_FILENAME}\.html -f
RewriteRule (.*)$ $1.html [L,E=END:1,NS]
RewriteCond %{REQUEST_FILENAME}\.htm -f
RewriteRule (.*)$ $1.htm [L,E=END:1,NS]
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule (.*)$ $1.php [L,E=END:1,NS]
I would like thank Everybody for this post as it really helped me a lot and I used something like the one below and works for me ...
Options +FollowSymLinks -MultiViews
RewriteEngine on
RewriteBase /
RewriteCond %{ENV:REDIRECT_END} =1
RewriteRule ^ - [L,NS]
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^(.*?)\.(php|html?)$ $1 [R=301,NC,NS]
RewriteCond %{REQUEST_FILENAME}\.html -f
RewriteRule (.*)$ $1.html [L,E=END:1,NS]
RewriteCond %{REQUEST_FILENAME}\.htm -f
RewriteRule (.*)$ $1.htm [L,E=END:1,NS]
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule (.*)$ $1.php [L,E=END:1,NS]
This version works for me.
Thank you.
Cheers!

mod rewrite to remove file extension, add trailing slash, remove www and redirect to 404 if no file/directory is available

I would like to create rewrite rules in my .htaccess file to do the following:
When accessed via domain.com/abc.php: remove the file extension, append a trailing slash and load the abc.php file. url should look like this after rewrite: domain.com/abc/
When accessed via domain.com/abc/: leave the url as is and load abc.php
When accessed via domain.com/abc: append trailing slash and load abc.php. url should look like this after rewrite: domain.com/abc/
Remove www
Redirect to 404 page (404.php) when accessed url doesn't resolve to folder or file, e.g. when accessing either domain.com/nothingthere.php or domain.com/nothingthere/ or domain.com/nothingthere
Make some permanent 301 redirects from old urls to new ones (e.g. domain.com/abc.html to domain.com/abc/)
All php files sit in the document root directory, but if there is a solution that would make urls such as domain.com/abc/def/ (would load domain.com/abc/def.php) also work it would be great as well, but not necessary
So here is what I have at the moment (thrown together from various sources and samples from around the web
<IfModule mod_rewrite.c>
RewriteCond %{HTTPS} !=on
# redirect from www to non-www
RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
RewriteRule ^ http://%1%{REQUEST_URI} [R=301,L]
# remove php file extension
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{THE_REQUEST} ^GET\ /[^?\s]+\.php
RewriteRule (.*)\.php$ /$1/ [L,R=301]
# add trailing slash
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^.*[^/]$ /$0/ [L,R=301]
# resolve urls to matching php files
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*)/$ $1.php [L]
With this the first four requirements seem to work, whether I enter domain.com/abc.php, domain.com/abc/ or domain.com/abc, the final url always ends up being domain.com/abc/ and domain.com/abc.php is loaded.
When I enter a url that resolves to a file that doesn't exists I'm getting an error 310 (redirect loop), when really a 404 page should be loaded. Additionally I haven't tried if subfolders work, but as I said, that's low priority. I'm pretty sure I can just slap the permanent 301 redirects for legacy urls on top of that without any issues as well, just wanted to mention it. So the real issue is really the non working 404 page.
I've had problems with getting ErrorDocument to work reliably with rewrite errors, so I tend to prefer to handle invalid pages correctly in my rewrite cascade. I've tried to cover a fully range of test vectors with this. Didn't find any gaps.
Some general points:
You need to use the DOCUMENT_ROOT environment variable in this. Unfortunately if you use a shared hosting service then this isn't set up correctly during rewrite execution, so hosting providers set up a shadow variable to do the same job. Mine uses DOCUMENT_ROOT_REAL, but I've also come across PHP_DOCUMENT_ROOT. Do a phpinfo to find out what to use for your service.
There's a debug info rule that you can trim as long as you replace DOCROOT appropriately
You can't always use %{REQUEST_FILENAME} where you'd expect to. This is because if the URI maps to DOCROOT/somePathThatExists/name/theRest then the %{REQUEST_FILENAME} is set to DOCROOT/somePathThatExists/name rather than the full pattern equivalent to the rule match string.
This is "Per Directory" so no leading slashes and we need to realise that the rewrite engine will loop on the .htaccess file until a no-match stop occurs.
This processes all valid combinations and at the very end redirects to the 404.php which I assume sets the 404 Status as well as displaying the error page.
It will currently decode someValidScript.php/otherRubbish in the SEO fashion, but extra logic can pick this one up as well.
So here is the .htaccess fragment:
Options -Indexes -MultiViews
AcceptPathInfo Off
RewriteEngine On
RewriteBase /
## Looping stop. Not needed in Apache 2.3 as this introduces the [END] flag
RewriteCond %{ENV:REDIRECT_END} =1
RewriteRule ^ - [L,NS]
## 302 redirections ##
RewriteRule ^ - [E=DOCROOT:%{ENV:DOCUMENT_ROOT_REAL},E=URI:%{REQUEST_URI},E=REQFN:%{REQUEST_FILENAME},E=FILENAME:%{SCRIPT_FILENAME}]
# redirect from HTTP://www to non-www
RewriteCond %{HTTPS} !=on
RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
RewriteRule ^ http://%1%{REQUEST_URI} [R=301,L]
# remove php file extension on GETs (no point in /[^?\s]+\.php as rule pattern requires this)
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_METHOD} =GET
RewriteRule (.*)\.php$ $1/ [L,R=301]
# add trailing slash
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^.*[^/]$ $0/ [L,R=301]
# terminate if file exists. Note this match may be after internal redirect.
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^ - [L,E=END:1]
# terminate if directory index.php exists. Note this match may be after internal redirect.
RewriteCond %{REQUEST_FILENAME} -d
RewriteCond %{ENV:DOCROOT}/$1/index.php -f
RewriteRule ^(.*)(/?)$ $1/index.php [L,NS,E=END:1]
# resolve urls to matching php files
RewriteCond %{ENV:DOCROOT}/$1.php -f
RewriteRule ^(.*?)/?$ $1.php [L,NS,E=END:1]
# Anything else redirect to the 404 script. This one does have the leading /
RewriteRule ^ /404.php [L,NS,E=END:1]
Enjoy :-)
You'll probably want to check if the php file exists before adding the tailing slash.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^.*[^/]$ /$0/ [L,R=301]
or if you really want a tailing slash for all 404 pages (so /image/error.jpg will become /images/error.jpg/, which I think is weird):
RewriteCond %{ENV:REDIRECT_STATUS} !200
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^.*[^/]$ /$0/ [L,R=301]
I came up with this:
DirectorySlash Off
RewriteEngine on
Options +FollowSymlinks
ErrorDocument 404 /404.php
#if it's www
# redirect to non-www.
RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
RewriteRule ^ http://%1%{REQUEST_URI} [L,R=301,QSA]
#else if it has slash at the end, and it's not a directory
# serve the appropriate php
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/$ /$1.php [L,QSA]
#else if it's an existing file, and it's not php or html
# serve the content without rewrite
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{REQUEST_FILENAME} -f
RewriteCond %{REQUEST_URI} !(\.php)|(\.html?)$
RewriteRule ^ - [L,QSA]
#else
# strip php/html extension, force slash
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^(.*?)((\.php)|(\.html?))?/?$ /$1/ [L,NC,R=301,QSA]
Certainly not very elegant (env:redirect_status is quite a hack), but it passes my modest tests. Unfortunately I can't test the www redirection, as I'm on localhost, and has no real access to a server, but that part should work too.
You see, I used the ErrorDocument directive to specify the error page, and used the DirectorySlash Off request to make sure Apache doesn't interfere with the slash-appending fun. I also used the QSA (Query String Append) flag that, well, appends the query string to the request so that it's not lost. It looks kind of silly after the trailing slash, but anyhow.
Otherwise it's pretty straightforward, and I think the comments explain it pretty well. Let me know if you run into any trouble with it.
Create a folder under the root of the domain
Place a .htaccess in the above folder as RewriteRule ^$ index.php
Parse the URL
With PHP coding you can now strip the URL or file extension as required

Resources