8

I manage a large number of PHP applications using front controllers and the following htaccess file:

FallbackResource /index.php

Yes, that is the entire file (for each application)!

However, a few of the sites are in subfolders, necessitating the following change:

FallbackResource /subfolder/index.php

As you could probably guess, the / at the beginning means that the path is relative to the site/vhost, and here the path needs to be relative to the directory.

(If I were using mod_rewrite for this instead of mod_dir, I would have to add a RewriteBase to each subdirectory as needed, in a similar fashion.)

I thought that I could get around this by doing:

FallbackResource index.php # No slash!

However, when the site's rewrites contain slashes, for example, if the application is /store/ and the path within it is products/1234, then Apache looks for /store/products/index.php instead of /store/index.php and returns a 500 with the following message in the log:

Request exceeded the limit of 10 subrequest nesting levels due to probable configuration error. Use 'LimitInternalRecursion' to increase the limit if necessary. Use 'LogLevel debug' to get a backtrace.

I would have thought that the FallbackResource path is relative to the .htaccess file in which it is configured, but it seems that it is actually relative to the requested URL.

Is there a way to have FallbackResource act the way that I expected?


I can use it the way it is if that's the answer, but it would make it a lot easier to manage the sites that I have if this can be done. The sites use the same basic code with different themes and database connections, and the way it works now I have to modify the htaccess file every time we deploy a new version of the code (because it is checked into Git). If we can make it that someone doesn't have to remember to make this modification every time, that would be really great.

Moshe Katz
  • 3,112
  • 5
  • 28
  • 43
  • Relative URLs are almost always bad news. You generally should avoid them when possible, and avoid site designs which encourage or even require them (such as using subdirectories instead of subdomains for unrelated content). – Michael Hampton Apr 10 '14 at 02:48
  • @MichaelHampton I know they're bad. All of our new sites are in subdomains. But I still have to support legacy sites this way (I don't have control over DNS for some of them), and I'm trying to find a way to make that easier. – Moshe Katz Apr 10 '14 at 02:52

4 Answers4

1

I don't think this is possible to do easily. I've tried various combinations of DirectoryMatch and LocationMatch in the main configuration files using the newish variable interpolation available in these two directives.

Although something like FallBackResource index.html is entirely valid configuration, I share Michael Hampton's concern that any use of relative URLs can cause problems. In the case of FallBackResource index.html for a particular directory tree, index.html must always be present otherwise you will get the recursion loop you describe for requests where index.html cannot be found.

In your case you would need a top level .htaccess file with FallBackResource /index.html, then FallBackResource /subfoldername/index.html in each relevant sub folder.

A simple script to generate these is probably safest.

Unbeliever
  • 2,336
  • 1
  • 10
  • 19
  • Thanks for trying, but this doesn't really help. The issue here is not handling the lack of presence a file, but forwarding all unmatched requests to a PHP application. The question is because some PHP applications reside in a subfolder. – Moshe Katz Oct 09 '16 at 14:03
  • Well change `index.html` to `index.php` or whatever your controller script is (Sorry, I was just pasting my local test config). I still think it will work. Otherwise you'll need to use mod_rewrite :( – Unbeliever Oct 09 '16 at 14:36
0

Aside: Solution using mod_rewrite

Using mod_rewrite you can avoid the dependency (hard-coding) of the parent directory.

(If I were using mod_rewrite for this instead of mod_dir, I would have to add a RewriteBase to each subdirectory as needed, in a similar fashion.)

You would not need to add RewriteBase here. In fact, you should avoid adding a RewriteBase directive in this scenario. (Don't copy the stock WordPress front-controller pattern.) And then use a relative substitution string (in the RewriteRule directive) to the front-controller. Relative substitution strings are relative to the directory that contains the .htaccess file. So, this is certainly an acceptable workaround to using FallbackResource that avoids having a dependence on the parent directory, if you are prepared to use mod_rewrite.

And if you are already using mod_rewrite for other rewrites then using mod_rewrite for the front-controller pattern as well is arguably the preferred solution anyway.

The mod_rewrite solution is used in combination with mod_dir's DirectoryIndex. Requests for the "root" directory itself are handled by mod_dir, not mod_rewrite. (That is, "root" of the application - the subdirectory - not necessarily the "document root" of the vHost.)

For example, with everything (including index.php and .htaccess) located inside the /subfolder directory:

# /subfolder/.htaccess

DirectoryIndex index.php

RewriteEngine On

RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . index.php [L]

The first RewriteRule directive is simply an optimisation and is not strictly necessary to make it "work". This rule avoids an unnecessary filesystem check after having rewritten the request to index.php. Alternatively, on Apache 2.4, you can use the END flag instead of L on the last rule.

In the absence of a RewriteBase directive, the last RewriteRule directive (that uses a relative substitution string) rewrites the request to /subfolder/index.php (the directory in which the .htaccess file is located).


Even in situations when you do need to know the name of the parent directory, this can be calculated, again using mod_rewrite.

MrWhite
  • 12,647
  • 4
  • 29
  • 41
0

The sites about which I originally asked this question are no longer live, but here's what i ended up doing.

I ended up moving these sites to a server running Nginx, where all configuration is done in the config files of the server using a try_files directive. It was much easier to manage that way.

Moshe Katz
  • 3,112
  • 5
  • 28
  • 43
0

I believe a work around using DirectoryIndex instead of FallbackResource might also work. The following will match /a/script/ to the file /some/path/to/a/script/index.py then /some/path/to/a/script/index.html then /some/path/to/subfolder/index.py and finally /some/path/index.py. This relies upon DirectoryIndex honouring absolute paths.

ScriptAlias / "/some/path/to/"
<Directory "/some/path/to/">
  Options +ExecCGI
  AddHandler cgi-script .py
  DirectoryIndex index.py index.html 
  # Appending  /index.py seems to work whereas FallbackResource does not
  DirectoryIndex /subfolder/index.py
  DirectoryIndex /index.py
  FallbackResource /index.py
  Require all granted
</Directory>

Repeated calls to DirectoryIndex are appended to previous calls. In my case FallbackResource was not working and i stumbled upon this as a solution. The above is for CGI/Python files but I believe it will work in your scenario as well.

Carel
  • 109
  • 6