How to avoid the need of typing .php on the url?

Viewed 129

I'm on MacOs Big Sur, using Apache and PHP. What I want is: not needing to put .php on the end of my files to load it.

For instance, instead of typing this on the URL:

127.0.0.1/public_html/home.php

I want just to type

127.0.0.1/public_html/home

To achieve this, I'm using this code in .htaccess:

RewriteEngine On
Options -Indexes 
DirectoryIndex home.php index.php 
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^(.+)$ $1.php [L]

The code above works on my hosting, but for some reason, it does not work on my development machine. Instead, a get a 404 error.

404 Not Found Message

The .htaccess file with the code is on the root of public_html folder.

What am I missing?

1 Answers

By typing some "nonsense" at the top of the .htaccess file and not getting an error (ordinarily you would get a 500 Internal Server Error) it would seem that .htaccess overrides were not enabled on the server. So, .htaccess files were effectively disabled - which they are by default on Apache 2.4.

To enable .htaccess overrides (to allow .htaccess to override the server config) you need to set the AllowOverride directive in the appropriate <Directory> container in the server config (or <VirtualHost> container). The default on Apache 2.4 is AllowOverride None.

With the directives as posted you would need a minimum of:

AllowOverride FileInfo Indexes Options

FileInfo for mod_rewrite, Indexes for DirectoryIndex and Options for Options and related directives.

Although it is common (and easier) to just set:

AllowOverride All

Reference:


RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^(.+)$ $1.php [L]

These directives are not strictly correct. Whilst they may work OK for the URLs you are testing, they would result in a rewrite-loop (500 error response) if you simply append a slash to your URLs (and there is no directory by that name), eg. /home/ (or /home/<anything>). This is because your condition that tests for the presence of the .php file is not necessarily the same as the URL-path you are rewriting to. See my answer to the following question on ServerFault for a thorough explanation of this issue: https://serverfault.com/questions/989333/using-apache-rewrite-rules-in-htaccess-to-remove-html-causing-a-500-error

Also, there's no need to check that the request does not map to a directory to then check if the request + .php extension maps to a file. If the request maps to a file then it can not also be a directory, so if the 2nd condition is true, the 1st condition must also be true and is therefore superfluous.

And there's no need to backslash-escape literal dots in the RewriteCond TestString - this is an "ordinary" string, not a regex.

So, these directives should be written like this instead:

RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI}.php -f
RewriteRule (.+) $1.php [L]

(RewriteBase should not be used here.)

You can further optimise this by excluding requests that already contain what looks like a file extension (assuming your URLs that need rewriting do not contain a dot near the end of the URL-path). For example:

RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI}.php -f
RewriteRule !\.\w{2,4}$ %{REQUEST_URI}.php [L]

(With this 2nd version, it does not matter if RewriteBase is set - it is not used.)

DirectoryIndex home.php index.php 

You gave an example URL of /public_html/home (to which .php is appended). However, this DirectoryIndex directive allows home.php to also be served when simply requesting the directory /public_html/. It should be one or the other, not both.

Related