通过将旧版 PHP 文件请求传递到 .htaccess 文件中的 index.php,旧版应用程序将通过 Slim 框架传递。此外,在文件夹中设置 Symfony 应用程序并设置别名。
使用 PHP-FPM 的 VHost 配置
<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>
测试文件:
/路径/到/slim/index.php
<?php echo "slim";
/路径/到/slim/.htaccess
RewriteEngine On
RewriteBase /
RewriteRule ^hello$ /hello.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
/路径/到/slim/hello.php:
<?php echo "hello";
/路径/到/symfony/app.php
<?php echo "symfony";
/路径/到/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
我在 Ubuntu 16 和 CentOs 7 上都尝试过,结果相同。使用 Apache 2.4,AllowOverride All 和 mod_rewrite 启用。PHP7-fpm
我还尝试了什么:
1)ProxyPass fcgi://127.0.0.1:9001/path/to/app/slim/index.php
/test.php 显示“slim”,但是该请求在 slim 框架中被误解为“/”。
根据Apache 文档 .htaccess
应先进行处理。
解决这个问题的最佳方法是什么?
(注:Bounty 说我不想标准化 Apache 配置。这是一个打字错误。
我确实想标准化 Apache 配置)
答案1
您的问题是使用<LocationMatch>
php-fpm 进行代理,该代理适用于所有 URL前检查相应的文件是否存在。(ProxyPassMatch
顺便说一下,这样做会更优雅。)引用文档<Location>
:
<Location>
部分操作完全在文件系统之外。
然而你显然做想要在将 PHP 文件传递给 php-fpm 之前检查该文件是否存在。这可以通过使用<FilesMatch>
和SetHandler
反而:
<FilesMatch \.php$>
SetHandler "proxy:fcgi://127.0.0.1:9001/"
</FilesMatch>
(我自己在这里使用 unix 套接字,如我上面链接到的文档中所述,所以我不能 100% 确信这是 URL 的正确语法。)
这样,只有文件将被重定向到 php-fpm,并且当相应文件不存在时,您的 mod_rewrite 规则甚至有可能被应用于以 .php 结尾的 URI。
还要注意,使用FallbackResource
对此没有影响,因为再次具有<LocationMatch>
优先级,甚至将不存在的 URI 代理到 php-fpm。它仅重定向那些原本会使用 Apache 内置 404 处理程序的 URI,但正如您已经指出的那样,这不会启动。
答案2
乍一看,您似乎在虚拟主机中没有 AllowOverride 指令,因此文件未被读取是正常的,但我仍然想知道:
如果您可以访问虚拟主机,为什么还要使用 .htaccess?您只是想用它让自己的生活更复杂(您似乎已经这样做了)。
忘记.htaccess 和所有那些重写指令并在您的虚拟主机中添加这行简单的代码:
FallBackResource /index.php
这实际上将在一行中完成所有 5 个重写指令所执行的相同操作。
关于 ”主要脚本未知“,检查 fpm 所说的内容,你可能指向路径错误,fpm 配置不正确
请记住尽可能避免在每个目录上下文中定义指令,以避免噩梦和持续的头痛。
答案3
您声称请求就像/test
工作,但/test.php
事实并非如此。
发生这种情况时,是否总是/test.php
不存在,并且请求以 结尾.php
? 如果是这样,您可以做的是指示浏览器自动发出另一个请求,剥离该.php
部分。
可以通过以下方式实现:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule (.*)\.php$ $1 [R]
按照http://httpd.apache.org/docs/current/mod/mod_rewrite.html#rewriterule,该R
选项将发出一个redirect
。
我不会信任.htaccess
,并将其直接放入服务器的配置中,在<LocationMatch "^(.*\.php)$">
您已经拥有的配置中,并在其中的指令之前ProxyPass
。