In Apache, I have a working .htaccess file that appends the .php extension to a requested website page so that, for example: https://{{domain}}/sales -> serves the content from https://{{domain}}/sales.php while to the visitor it looks like https://{{domain}}/sales
It's working flawlessly.
I, however, can't solve how to ALSO use the fancy 404.php page from the server.
Here's my current .htaccess file content:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^\.]+)$ $1\.php [NC,L]
Evidence: If I turn my .htaccess file off (rename it), the 404 page works well based on my httpd.conf settings. So, I'm almost positive it is this immature .htaccess file that is preventing me from serving the fancy 404 page when the sales.php page is not found.
What are the exact lines in httpd.conf:
DocumentRoot "/var/www/html/"
ErrorDocument 404 "/404.php"
Additionally, I have tried each of: (and reloaded httpd after)
ErrorDocument 404 "/var/www/html/{{virtualHostDir}}/404.php"
ErrorDocument 404 "/404.php"
ErrorDocument 404 "404.php"
I've even tried to add the ErrorDocument directly to the virtualHost settings, but to no avail.
And what actually happens when you get a 404 and the .htaccess file is in place?
I get a page with no html, it just says, "File not found."
DocumentRoot "/var/www/html/" ErrorDocument 404 "/404.php"
That looks correct. If the 404 error document is located at /var/www/html/404.php
then there's no obvious reason (from the given information) why this is not working as intended. It does not appear to be the contents of the .htaccess
file - although you could try an alternative approach (see below).
The path provided to the ErrorDocument
directive should be a document-root-relative URL-path - starting with a slash. (In order to trigger an internal subrequest to the respective error document.)
I've even tried to add the ErrorDocument directly to the virtualHost settings
However, if you are using VirtualHost containers then these settings should really be in the respective vHost(s). Anything in the vHost will override the main server config.
Obviously, if you make any changes to the server config / virtualhost then you'll need to restart Apache.
Since you are using .htaccess
anyway, you can also set the ErrorDocument
in .htaccess
- and this will in turn override the virtualhost / server config.
RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^([^\.]+)$ $1\.php [NC,L]
There's nothing particularly wrong with this... you are matching a requested URL-path that does not contain a dot and providing it does not already map to a file or directory, you are appending a .php
extension.
Just some notes regarding this:
You append the .php
extension regardless of the file "with a .php
extension" actually exists. This isn't necessarily wrong, it's just that the 404 is then triggered on /does-not-exist.php
instead of /does-not-exist
. You could instead check that the destination file exists. This would avoid having to check that the request does not already map to a file or directory.
The first condition that checks that the request does not map to a file is probably unnecessary, unless you have files which don't have file extensions (very unlikely I would think).
[^\.]
- There is no need to backslash escape a literal dot in a regex character class. (Although no harm in doing so, except readability IMO.)
$1\.php
- There is no need to backslash escape the literal dot in the RewriteRule
substitution. This argument is an "ordinary" string (not a regex), the dot carries no special meaning here. (Although, again, no harm in doing so, except readability.)
The NC
flag on the RewriteRule
is not required here since you are matching everything except a dot in the regex, which naturally includes both upper and lowercase letters anyway.
If this is all you are using mod_rewrite for then you could instead use MultiViews to handle your extensionless URLs. This is what MultiViews (part of mod_negotiation) does. Given a request for /path/to/foo
, if /path/to/foo.php
exists, mod_negotiation will serve that file. You would need to remove your existing mod_rewrite directives (since they would effectively conflict and be ignored anyway) and then enable MultiViews at the top of your .htaccess
file:
Options +MultiViews
Alternatively, try the following, taking into account the points I made above:
RewriteEngine On
RewriteCond %{DOCUMENT_ROOT}/$1.php -f
RewriteRule ^([^.]+)$ $1.php [L]
NB: I'm assuming your .htaccess
file is in the document root, ie. /var/www/html/.htaccess
?