Handling 'File Not Found' for Allowed PHP Files in .htaccess

I’m receiving a “File not found” error for allowed PHP files when they don’t exist.

Here’s an example of my .htaccess where I block all .php files except for specific ones:

<Files *.php>
    Order Deny,Allow
    Deny from all
</Files>

<FilesMatch "^(index|p2)\.php$">
    Order Allow,Deny
    Allow from all
</FilesMatch>

When I access site/p2.php, I get a “File not found” error. However, accessing site/p3.php (which isn’t allowed) returns the standard error page.

How can I make it return the standard error page if the PHP file doesn’t exist while keeping it allowed?

Can something global be done in /etc/apache2/apache2.conf to fix this?

this is from grok.
I don’t know if it’s valid. I don’t use apache.

The issue you’re encountering stems from how Apache processes the and directives in your .htaccess file, combined with its behavior when a file doesn’t exist. When you try to access site/p2.php and it doesn’t exist, Apache triggers a 404 error before applying the allow rule, but because of the Deny from all on *.php, it might still interfere depending on server configuration. Meanwhile, site/p3.php (not explicitly allowed) correctly hits the Deny from all rule and shows the standard error page.

To ensure that non-existent but “allowed” PHP files (like p2.php) return the standard 404 error page instead of a generic “File not found” message, while keeping your security restrictions intact, you can refine your approach. Here’s how:

Fix in .htaccess

Your current .htaccess is mostly correct, but you can tweak it to handle non-existent files better by ensuring the deny rule doesn’t override the standard error handling for allowed files. Try this:

apache

# Deny access to all .php files by default
<Files *.php>
    Order Deny,Allow
    Deny from all
</Files>

# Explicitly allow specific PHP files
<FilesMatch "^(index|p2)\.php$">
    Order Allow,Deny
    Allow from all
</FilesMatch>

# Ensure 404 errors are handled by the standard error page
ErrorDocument 404 /path/to/your/404page

Key Points:

  1. ErrorDocument: Adding an ErrorDocument 404 directive ensures that when a file like p2.php isn’t found, Apache serves your custom 404 page (or the default one if not customized) instead of a vague “File not found” message. Replace /path/to/your/404page with the actual path to your error page (e.g., /404.html or /index.php if it handles errors dynamically).

  2. Order of Rules: The allow rule overrides the <Files *.php> deny rule for matching files, but if the file doesn’t exist, Apache’s default behavior kicks in. The ErrorDocument directive helps standardize the response.

Why This Works:

  • For site/p2.php (allowed but non-existent), Apache will first check if it exists. If not, it triggers a 404 and uses the ErrorDocument setting.

  • For site/p3.php (not allowed), the Deny from all rule applies, and Apache denies access before even checking existence, showing the standard forbidden error (usually 403).

Global Fix in /etc/apache2/apache2.conf

If you want a server-wide solution (affecting all sites hosted on the server), you can configure Apache’s global error handling in /etc/apache2/apache2.conf (or a similar config file, depending on your distribution). Add or modify the ErrorDocument directive there:

apache

ErrorDocument 404 /error/404.html

Steps:

  1. Edit /etc/apache2/apache2.conf (requires root access, e.g., sudo nano /etc/apache2/apache2.conf).

  2. Add the ErrorDocument 404 line in the block for your web root (e.g., <Directory /var/www/html>), or globally outside any specific directory block.

  3. Ensure the path (e.g., /error/404.html) points to a valid file relative to the server root.

  4. Restart Apache: sudo systemctl restart apache2.

Notes:

  • This global setting will apply to all virtual hosts unless overridden by a local .htaccess file with its own ErrorDocument.

  • Your .htaccess deny/allow rules will still work as intended, but non-existent allowed files will now consistently trigger the 404 page.

Testing and Debugging

  • Clear your browser cache or use incognito mode to test.

  • Check Apache’s error logs (e.g., /var/log/apache2/error.log) for clues if the behavior isn’t as expected.

  • Ensure the files index.php and p2.php exist in the correct directory if you expect them to work.

Alternative Approach with Rewrite Rules

If the above doesn’t fully resolve it (e.g., due to server-specific quirks), you could use mod_rewrite for more control:

apache

RewriteEngine On

# Allow only specific PHP files, deny others
RewriteCond %{REQUEST_URI} !^(.*)/(index|p2)\.php$
RewriteRule \.php$ - [F]

# Optionally redirect non-existent allowed files to 404
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(index|p2)\.php$ - [R=404,L]

This uses mod_rewrite to forbid all .php files except index.php and p2.php, and explicitly triggers a 404 for non-existent allowed files. Place this in your .htaccess and ensure RewriteEngine is enabled (sudo a2enmod rewrite && sudo systemctl restart apache2).

Conclusion

For your specific case, adding ErrorDocument 404 to .htaccess is the simplest fix. If you manage the server and want consistency across all sites, apply it in apache2.conf. Either way, your allow/deny logic remains intact, and non-existent allowed files will show the standard error page. Let me know if you need help testing this!

That syntax is deprecated and should be avoided. Apache has a guide on how to use the new directives. It is a good resource for Authorization and related elements.

https://httpd.apache.org/docs/2.4/upgrading.html

I went to /etc/apache2/apache2.conf and added the following code at the end:

# Global rule to force 404 for non-existent .php files
<Directory /home/*/web/*/public_html/>
	<IfModule mod_rewrite.c>
		RewriteEngine On
		RewriteOptions Inherit
		RewriteCond %{REQUEST_FILENAME} !-f
		RewriteRule \.php$ - [R=404,L]
	</IfModule>
</Directory>

It seems to have resolved the issue.

1 Like