Block access to all php files in subdirectory

.htaccessapache-2.2apache-2.4Apache2

I need to block access to all .php files in a subdirectory of my web root. I know that I could create a .htaccess in this subdirectory and use the following:

<FilesMatch "\.(?i:php)$">
<IfModule !mod_authz_core.c>
Order allow,deny
Deny from all
</IfModule>
<IfModule mod_authz_core.c>
Require all denied
</IfModule>
</FilesMatch>

However, for the sake of transparency / simplicity I really need to do the blocking from the web root .htaccess and NOT via one in the subdirectory.

If I were to block a specific file from the root .htaccess I would use this:

<Location /wp-includes/somefile.php>
<IfModule !mod_authz_core.c>
Order allow,deny
Deny from all
</IfModule>
<IfModule mod_authz_core.c>
Require all denied
</IfModule>
</FilesMatch>

I've read that you can't use LocationMatches in the .htaccess, so is there another way that I can do this (without creating a .htaccess for the sub-directory?

UPDATE
It appears that <Location> can't be used in .htaccess either.

Best Answer

The <Location> (and <LocationMatch>) directives match against the URL-path, not strictly the filesystem path, so it's not necessarily recommended to use this to control access anyway (in the server config).

If you have access to the server config then you would just use the relevant <Directory> container.

Without using a .htaccess in the subdirectory you could use mod_setenvif to set an environment variable conditionally based on the requested URL and then block based on this env var.

For example:

SetEnvIf Request_URI "^/subdirectory/.+\.php$" BLOCK

<IfModule !mod_authz_core.c>
  Order deny,allow
  Deny from env=BLOCK
</IfModule>
<IfModule mod_authz_core.c>
  <RequireAll>
    Require all granted
    Require not env BLOCK
  </RequireAll>
</IfModule>

I reversed the Order directive (Apache 2.2), otherwise, without an additional Allow directive, everything would be blocked.

The Apache 2.4 directives need to be inside a <RequireAll> container, first granting all access (otherwise everything is blocked) and then denying access conditionally when the BLOCK env var is set. You can't have a negated Require directive - in an implied <RequireAny> container - as it won't have any effect (in fact, this results in a 500 error).

Note that this blocks URLs, not strictly "files". It blocks requests that look like .php files in /subdirectory - regardless of whether they actually exist as physical files.


Alternatively, you could use mod_rewrite (Apache 2.2 and 2.4) at the top of your root .htaccess file:

RewriteEngine On

RewriteRule ^subdirectory/.+\.php$ - [F]

This simply blocks (403 Forbidden) all URLs that end in .php that are in the requested /subdirectory. If you specifically need to only return a 403 for URLs that map to real files then you can include an additional condition (although this is probably unnecessarily wasteful):

RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^subdirectory/.+\.php$ - [F]

Change F to R=404 if you wanted to return a 404 instead.