3

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)

jdog
  • 121
  • 7
  • 29

3 Answers3

2

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.

jplitza
  • 329
  • 1
  • 10
1

At first sight you don't seem to have AllowOverride directive in the virtualhost, so it is normal the file is not being read, still I wonder:

Why are you using .htaccess if you have access to the virtualhost? You are just looking to complicate your life (as you seem to be doing already) using it.

Forget about .htaccess and all those rewrite directives and add this simple line in your virtualhost:

FallBackResource /index.php

This will essentially do the same thing all your 5 rewrite directives do, in one single line.

About "primary script unknown", check what fpm has to say, you may be pointing to the wrong path and configuring fpm incorrectly

Remember to avoid defining your directives in per-dir context whenever possible to avoid nightmares and constant headaches.

Daniel Ferradal
  • 2,415
  • 1
  • 8
  • 13
  • Thanks for the response. Allowed is set and the htaccess file is processed. I only have access to the vhost file through a service provider. Finally I want to be able to drop in frameworks into Ansible folder without having to change vhost and merge the htaccess rules manually – jdog Jan 27 '17 at 18:16
  • @jdog fallbackresource can also be used inside .htaccess. My answer about primay script unknown still stands, review paths and fpm logs – Daniel Ferradal Jan 27 '17 at 18:35
  • Primary script unknown is triggered because somefile.php does not exist in the web folder. This is because I want it processed with index.php. I have Slim framework3 running there, which is picking up the filename correctly on mod_php. This setup is to wrap a legacy application into Slim framework for CSRF protection and managed thin-out with strangling pattern approach. I would prefer to solve this for php-fpm, as it is widely applicable to many of my projects. – jdog Jan 27 '17 at 21:01
  • this is why you should use FallBackResource and clearly you still aren't, apache won't find it in the documentroot and send the request to your index.php. Make sure you are landing where you think you are landing, and once you do, review fpm logs if you still get primary script unknown. – Daniel Ferradal Jan 30 '17 at 20:51
0

You claim that requests like /test work, but /test.php don't.

When this happens, is it always the case that /test.php doesn't exist, and is a request that ends with .php? If so, what you could do is instruct the browser to automatically make another request, stripping the .php part.

Which can be accomplished with:

RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule (.*)\.php$ $1 [R]

As per http://httpd.apache.org/docs/current/mod/mod_rewrite.html#rewriterule, the R option would issue a redirect.

I wouldn't trust .htaccess, and put it directly into the configuration of the server, within the <LocationMatch "^(.*\.php)$"> which you already have, and prior to the ProxyPass directive within it.

cnst
  • 13,848
  • 9
  • 54
  • 76