Rewrite all *.php to single index.php before php-fpm processes it (apache)

.htaccessapache-2.4fastcgimod-rewritephp-fpm

A legacy application is passed through Slim framework by passing all legacy PHP file requests to index.php in a .htaccess file. Further, a Symfony application is set up in a folder with an Alias set up.

VHost configuration with PHP-FPM

<VirtualHost *:80>
    ServerName example.com
    DocumentRoot /path/to/app/slim
    Alias /system /path/to/app/symfony
    <IfModule mpm_itk_module>
            AssignUserId web_user web_user
    </IfModule>
    <LocationMatch "^(.*\.php)$">
            ProxyPass fcgi://127.0.0.1:9001/path/to/app/slim
    </LocationMatch>
</VirtualHost>

Files for testing:

/path/to/slim/index.php

<?php echo "slim";

/path/to/slim/.htaccess

RewriteEngine On
RewriteBase /    
RewriteRule ^hello$ /hello.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]

/path/to/slim/hello.php:

<?php echo "hello";

/path/to/symfony/app.php

<?php echo "symfony";

/path/to/symfony/.htaccess:

DirectoryIndex app.php
<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteCond %{REQUEST_URI}::$1 ^(/.+)/(.*)::\2$
    RewriteRule ^(.*) - [E=BASE:%1]
    RewriteCond %{HTTP:Authorization} .
    RewriteRule ^ - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]

    RewriteCond %{ENV:REDIRECT_STATUS} ^$
    RewriteRule ^app\.php(?:/(.*)|$) %{ENV:BASE}/$1 [R=301,L]

    RewriteCond %{REQUEST_FILENAME} -f
    RewriteRule ^ - [L]

    RewriteRule ^ %{ENV:BASE}/app.php [L]
</IfModule>


Test Uri                 Expected Output           Actual Output

/hello.php               hello                     hello
----------------------------------------------------------------------
/test                    slim                      slim
----------------------------------------------------------------------
/test.php                slim                      404 error
                                                   [proxy_fcgi:error] [pid 18527] [client x.x.x.x:45357] AH01071: Got error 'Primary script unknown\n'
----------------------------------------------------------------------
/system/hello            symfony                   symfony
/system/app.php/hello    symfony                   symfony

I have tried this both on Ubuntu 16 and CentOs 7 with the same results. Using Apache 2.4, AllowOverride All and mod_rewrite enabled. PHP7-fpm

What else have I tried:

1)

ProxyPass fcgi://127.0.0.1:9001/path/to/app/slim/index.php

for /test.php shows "slim", however the request is then misinterpreted in slim framework as "/".

According to Apache documentation .htaccess should be processed first.

What is the best way to resolve this?

(Note: Bounty says I don't want to standardise Apache configuration. This is a typo.

I DO WANT TO standardise Apache configuration)

Best Answer

Your problem is the use of <LocationMatch> for proxying to php-fpm, which is applied to all URLs before checking whether a corresponding file exists. (ProxyPassMatch would do the same thing more elegantly, by the way.) To quote the documentation on <Location>:

<Location> sections operate completely outside the filesystem.

However, you obviously do want to check if the PHP file exists before passing it to php-fpm. This can be accomplished by using <FilesMatch> and SetHandler instead:

<FilesMatch \.php$>
    SetHandler "proxy:fcgi://127.0.0.1:9001/"
</FilesMatch>

(I myself am using unix sockets here, as in the documentation I linked to above, so I'm not 100% confident this is the right syntax for the URL.)

This way, only files will be redirected to php-fpm, and your mod_rewrite rules have a chance of being applied even to URIs ending in .php when the corresponding files don't exist.

Note also that using FallbackResource has no influence on this, because again the <LocationMatch> has priority and proxies even inexistent URIs to php-fpm. It only redirects those URIs that would otherwise use Apache's builtin 404 handler, but that doesn't kick in as you already noted.

Related Topic