调整public目录结构时修复DOCUMENT_ROOT问题
嘿,这个问题确实挺典型的——当你用mod_rewrite把请求转发到public子目录时,Apache默认不会自动更新DOCUMENT_ROOT,因为这个变量是在请求处理的早期阶段就确定的,重写规则是之后才执行的。不过有几个实用的办法能解决这个问题,看你有没有对应的权限:
方法1:直接修改Apache配置(推荐,如果你有权限)
如果你能访问虚拟主机配置文件(比如httpd-vhosts.conf)或者主httpd.conf,最干净的做法就是把DocumentRoot直接指向你的public目录:
DocumentRoot "/home/foo/public_html/public" <Directory "/home/foo/public_html/public"> AllowOverride All Require all granted </Directory>
这样一来,DOCUMENT_ROOT会直接被设置为/home/foo/public_html/public,连rewrite规则都可以省掉。当然,这个方法的前提是public_html里没有其他需要直接对外访问的文件——如果有的话,可能就得换别的方法了。
方法2:用mod_rewrite传递真实目录,在PHP中覆盖
如果只能修改.htaccess,可以通过rewrite规则设置一个自定义环境变量,然后在PHP代码里手动替换DOCUMENT_ROOT:
首先更新你的.htaccess,添加环境变量REAL_DOCUMENT_ROOT:
<IfModule mod_rewrite.c> RewriteEngine on RewriteRule ^$ public/ [L,E=REAL_DOCUMENT_ROOT:/home/foo/public_html/public] RewriteRule (.*) public/$1 [L,E=REAL_DOCUMENT_ROOT:/home/foo/public_html/public] </IfModule>
然后在PHP的入口文件(比如public/index.php)开头添加这段代码:
// 替换DOCUMENT_ROOT为真实的public目录 if (getenv('REAL_DOCUMENT_ROOT')) { $_SERVER['DOCUMENT_ROOT'] = getenv('REAL_DOCUMENT_ROOT'); }
这样所有PHP脚本里的DOCUMENT_ROOT就会指向正确的目录了,不过这只是在PHP层面的修改,Apache本身的环境变量还是原来的值,但对于PHP应用来说足够了。
方法3:PHP-FPM配置(针对FastCGI场景)
如果你的服务器用的是PHP-FPM,可以在对应的池配置文件(比如www.conf)里添加一行:
php_value[doc_root] = /home/foo/public_html/public
重启PHP-FPM服务后,DOCUMENT_ROOT就会被设置成这个值。不过这个方法需要服务器管理权限,而且会影响整个FPM池里的所有站点,所以要谨慎使用。
内容的提问来源于stack exchange,提问作者Álvaro González

