如何在PHP中以编程方式确定文档根?

如何在PHP中以编程方式确定文档根?,php,apache,configuration,Php,Apache,Configuration,我最近遇到了一个问题——网络主机上配置错误的apache。这意味着所有依赖$\u服务器['DOCUMENT\u ROOT']的脚本都会中断。我发现的最简单的解决方法就是在一些共享的全局include文件中设置变量,但不要忘记它是一件痛苦的事情。我的问题是,如何通过编程确定正确的文档根 例如,在一台主机上,设置如下: $_SERVER['DOCUMENT_ROOT'] == '/htdocs' 真正的文档根是: test.example.com -> /data/htdocs/exampl

我最近遇到了一个问题——网络主机上配置错误的apache。这意味着所有依赖
$\u服务器['DOCUMENT\u ROOT']
的脚本都会中断。我发现的最简单的解决方法就是在一些共享的全局include文件中设置变量,但不要忘记它是一件痛苦的事情。我的问题是,如何通过编程确定正确的文档根

例如,在一台主机上,设置如下:

$_SERVER['DOCUMENT_ROOT'] == '/htdocs'
真正的文档根是:

test.example.com -> /data/htdocs/example.com/test
www.example.com -> /data/htdocs/example.com/www
我想要一个从
www.example.com/blog/
(路径
/data/htdocs/example.com/www/blog
)运行的脚本,以获得
/data/htdocs/example.com/www
的正确值

在另一台主机上,设置有点不同:

$_SERVER['DOCUMENT_ROOT'] == '/srv'
test.example.com -> /home/virtual_web/example.com/public_html/test
www.example.com -> /home/virtual_web/example.com/public_html/www

有什么解决办法吗?或者,唯一的办法就是永远不要依赖
$\u SERVER['DOCUMENT\u ROOT']
并修复我在网站上运行的所有软件?在主机端解决这个问题似乎不是一个选项,我还没有遇到一个配置正确的主机。我得到的最好的结果是指向www.example.com的文档根,它至少在open_basedir中-他们使用了另一个命名方案,www.example.com将指向
/u2/www/example_com/data/www/

PHP应该将当前目录设置为脚本所在的目录,因此,只要没有中断,您就应该能够使用
$\u SERVER['SCRIPT\u FILENAME']
getcwd()
计算出文档根目录。(我记不清所有的$服务器变量了,phpinfo()中可能有更有用的东西。)

在PHP5中,有一个神奇的常量
\uuu FILE\uuu
,它包含它出现的文件的绝对路径。您可以将其与dirname结合使用来计算文档根

您可以将如下语句放入配置文件中

define ('DOCUMENT_ROOT', dirname(__FILE__));

这样就可以了,不需要修改所有脚本

您可以在使用运行任何脚本之前运行PHP文件


$\u SERVER
只是一个数组,您可以修改它并设置正确的
$\u SERVER['DOCUMENT\u ROOT']

为什么不要求您的Web主机正确配置其服务器

这类事情往往会在代码中静静地徘徊,在有人最终修复服务器之前永远不会被删除(但仍处于活动状态)。一切都会再次破裂


或者,把你的东西搬到一个能用的地方。如果这被打破了,谁知道你接下来会发现什么。

这就是为什么人们使用htaccess和/或查询字符串通过bootstrap/index.php虹吸所有内容的原因之一。你可以使用上面提到的
dirname(\uuu文件\uu)
技巧,以这种方式获得应用程序的公共基础

如果您太过深入,无法切换到单个入口点,我看到人们做的一件事是在脚本中有一个公共头,它沿着目录树查找一个对基本目录唯一的文件:

function findAppBase( $dir ) {
    if( file_exists( "$dir/unique_file.txt" ) ) {
        return $dir;

    return findAppBase( dirname( $dir ) );
}

$base = findAppBase( dirname( __FILE__ ) );
该代码尚未经过测试,可能有一种更巧妙的方法使用
$\u ENV
$\u SERVER
中的vars,它将根据以下内容执行您想要的操作…


我不得不更改basename/realpath技巧,因为它在我的主机上返回了一个空字符串。相反,我使用
SCRIPT\u文件名
。这可能不再适用于IIS(但使用$\u服务器变量的原始脚本也可能不适用)。

我安装的一些脚本“太聪明了”,知道它们安装在哪个目录(相对于理论文档根目录),并将其附加到文档根目录(从数据库获取后)。我仍然需要修改每个目录的代码来剥离目录。。。或者不使用?诀窍是使用文件的绝对名称(来自magic常量,或者来自服务器变量),并将其与从脚本\u name到文档根的绝对路径的知识相结合。从PHP5.3这也是
\uuuu DIR\uuuu
使用它代替
dirname(\uu文件\uuuu)
。但这只是返回当前文件的文件夹,它不一定是Web服务器的实际根文件夹。是的@Chuck,你是对的,但是,如果你不能依赖$server配置(如果不是真正强制的话,我不会依赖它的所有值),并且没有常量,你必须求助于解决方法。我提出的这个方案是为了解决这个非常特殊的问题,最好是给出一个解决方案的提示。每次运行这个脚本都没用。每次运行这个脚本都没用。最好使用一些.htaccess来处理它,而不是设置它。你可以在.htaccess中使用php_值来设置auto_prepend_文件,但是问题的作者提到了IIS服务器,我认为它不支持这个。实际上,我不关心IIS,只是最初的解决方案应该是“独立于平台的”,我不确定以后它是否还能用。但是自动前置看起来很有趣,谢谢你的提示!我不确定是否可以正确配置主机,这似乎是mod_vhost_别名的问题(根据对的评论)。谢天谢地,这不是问题,我只有一个入口点。只是我在多个域和主机上运行相同的软件,我必须为每个域修复它。我宁愿向上游提交一个补丁,这样我就不必再关心它了。
$localpath=getenv("SCRIPT_NAME");
$absolutepath=getenv("SCRIPT_FILENAME");
$_SERVER['DOCUMENT_ROOT']=substr($absolutepath,0,strpos($absolutepath,$localpath));