How to Redirect to a Certain File if It Exists, Else Redirect to 404 from .htaccess

.htaccesshttp-status-code-404mod-rewriteredirect

I have this tree:

libs/
html/
app/
uploads/
    files/
    images/
        male.png
        female.png
    .htaccess
    download.php
.htaccess
index.php

/.htaccess has this content:

<IfModule mod_rewrite.c>
    <IfModule mod_negotiation.c>
        Options -Indexes
    </IfModule>

    RewriteEngine On

    RewriteRule ^ index.php [END,L]
</IfModule>

I want /uploads/.htaccess to:

  • redirect to download.php

    • if existent file, but not this .htaccess or download.php
  • redirect 404

    • if don't match existent file
    • or match .htaccess or download.php
    • or match existent folder

Examples:

www.example.com/uploads - redirect 404
www.example.com/uploads/files - redirect 404
www.example.com/uploads/images- redirect 404
www.example.com/uploads/.htaccess - redirect 404
www.example.com/uploads/download.php - redirect 404
www.example.com/uploads/nonexistentfile - redirect 404

www.example.com/uploads/images/male.php - redirect download.php
www.example.com/uploads/images/female.php - redirect download.php

Best Answer

redirect to download.php

I assume you mean "rewrite", rather than an external "redirect".

I would assume your system (ie. server config) is already configured (using mod_authz_...) to return a 403 Forbidden when trying to access .htaccess directly. I would leave that as it is, unless you have a specific requirement to return a 404 instead.

redirect to 404

And just to clarify, you don't literally "redirect" to a 404, you simply "serve" a 404. If you redirected to a 404 then you would first be sending a 3xx response back to the client, which is undesirable.

In the /uploads/.htaccess file try the following:

RewriteEngine On

# Rewrite request to download.php
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule !download\.php$ download.php [L]

# Serve a 404 otherwise...
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^ - [R=404]

The first rule rewrites all requests that are not already for download.php and exist as physical files to download.php. (A request for .htaccess should return a 403, assuming the server is configured correctly.)

The second rule serves a 404 for all other "direct" requests. The initial condition that checks the REDIRECT_STATUS environment variable ensures we only check direct requests and not rewritten requests (by the earlier rewrite). So this includes:

  • direct requests to download.php (but not rewritten requests to download.php).
  • direct requests for directories.
  • The request does not map to a file (because the first rule would have failed).
Related Topic