PHP相对路径:我能配置吗?

7

tl;dr: 如何使PHP从当前文件的角度解释包含/要求语句中的相对路径?

这是关于PHP相对路径问题的又一个问题。请容忍我,因为我找不到针对我特定需求的解决方案。

考虑以下目录树和文件:

[www]:
    index.php
    config.php
    [webroot]:
        home.php

index.php需要home.php,可以在webroot中找到:

require('webroot/home.php');

home.php需要config.php,后者位于父目录中:

require('../config.php');

我的问题是,在本地开发环境(Ubuntu 14.04 LTS / 15.10)中无法运行此代码,但在生产环境中却可以完美运行。所有提到的环境都在运行 Apache 2 和 PHP 5。
奇怪的是,当我在我的 Vagrant 虚拟机(Ubuntu 12.04 LTS)中运行它并从主机访问时,它可以在本地正常运行。但现在,我不能在这里运行虚拟机。

那么,为什么这些环境的行为会如此不同?
这使我相信,一定有一种方法可以更改 PHP 解释相对路径的方式。我目前正在使用一个超过 6GB 的 PHP 项目,像上面的示例一样编写,并且我真的需要避免重写每个 include/require 语句(使用 dirname(__FILE__) 等),以及可能造成的 git 合并冲突。

编辑:我刚想起来我曾在这里提出过这个问题:PHP:包含已包含的文件


2
如果你有6GB以上的PHP代码,那么你做错了什么。或者说,这些代码是从某个编译时模板生成的机器代码,而更改模板将会影响所有文件。 - IMSoP
3
现有的代码库有多大?您不需要重写所有历史记录,因此请减去“.git”文件夹的大小。即使如此,我怀疑那里实际上没有那么多代码,可能还包括一些图像等内容。整个Linux内核解压后只有约600MB(由52,000个文件组成)。尽管如此,我已按照您提出的问题回答了。 - IMSoP
很抱歉,但是你不能把这件事情归咎于 PHP,只能归咎于依赖相对路径的人。仅仅因为你/他们不理解这些路径被如何解释,并不意味着 PHP 解释它们的方式是错误的。 (顺便说一句,现代大多数 PHP 框架和应用程序几乎没有硬编码包含路径,因为类自动加载会替你处理它们。) - IMSoP
DOC_ROOT 实际上是 /var/www/html,但我不确定这是否相关(问题中的路径都是虚构的),因为我只想知道如何改变相对路径的视角。我不知道如何阅读 .htaccess,但如果您需要,我可以将其包含在问题中。 - Gui Imamura
抱歉回复晚了。在我的虚构结构中,它指向/www。在我的生产系统中,它指向/var/www/html,而在我的开发系统中,它实际上是/home/user/Documents/project(这是一个同步到vagrant机器的文件夹,它也将其视为/var/www/html)。 - Gui Imamura
显示剩余5条评论
5个回答

5

用于解析相对URL的路径是由include_path配置选项配置的,该选项有一个专门的函数可以在运行时设置:set_include_path

请注意,要搜索的路径集可能包括. ,代表“当前工作目录”,可以使用chdir设置并通过getcwd读取。您还可能需要更改此设置,以使明确的相对路径(如./foo.php../foo.php)正常工作。

(我原本想建议您改用__DIR__$_SERVER['DOCUMENT_ROOT'],但您提到您不想重写现有代码。我仍然建议其他人阅读此内容时,在每个包含文件中显式说明路径与何处相关,以避免出现奇怪的错误和潜在的安全漏洞。)


你好,感谢您的时间。我刚刚尝试将 include_path="." 添加到 php.ini 文件中,并在项目关键文件开头添加了 set_include_path(get_include_path() . PATH_SEPARATOR . ".");,但仍然出现相同的错误。您认为我漏掉了什么吗? - Gui Imamura
@GuiImamura 你尝试过输出 getcwd() 吗?.__DIR__的含义不同,它与写入include的文件不相关;它是"当前工作目录",就像在shell中使用cd时一样。 - IMSoP
getcwd() 给我项目的根目录,而不是我写 getcwd 的文件路径。是否有一种方法可以在每次包含/需要时将其更改为当前文件? - Gui Imamura
正如我在回答中所说,您可以使用chdir设置工作目录。但是,值得检查一下工作服务器的设置(使用echo get_include_path()echo getcwd()),并让它们与新服务器上的设置相匹配。因为除非有魔法一直在改变工作目录,否则您也不需要在新服务器上进行任何操作。 - IMSoP
chdir 的作用与 dirname(__FILE__) 相同。我认为没有办法使其成为每个 include/require 的默认设置,或者有吗? - Gui Imamura
2
@GuiImamura 就像我所说的,要么你的工作服务器已经执行了这样的默认操作,要么你不需要一种方法来执行它。你需要做的就是匹配两个服务器之间的配置。 - IMSoP

2
如果您想覆盖现有的功能,您需要安装外部库或使用命名空间。这两种方法都需要额外的工作。我猜安装额外的库可能根本不是一个选项。
您可以尝试使用set_include_path添加这些文件夹的路径。
或者,您可以添加一个全局变量和几个全局函数,如下所示,用于所有要求和包含重载,但您仍然必须在整个项目中查找/替换包含、要求、include_once、require_once的实例,并将它们替换为“include_rel”...
$include_rel_path = '.';

function include_rel($path){
    global $include_rel_path;

    $my_path = $include_rel_path;

    //TODO maybe need to check for drive letters?
    if(strpos($path, '/') === 0) { //absolutepath
        $include_rel_path = preg_replace('/\/[^\/]*$/','',$path);
        include($path);
    } else { //relative path
        $include_rel_path .= preg_replace('/\/[^\/]*$/','',$path);
        include($my_path.'/'.$path);
    }
    $include_rel_path = $my_path;
}

1
<?php 
 $path = $_SERVER['DOCUMENT_ROOT'];
 $path .= "/Folder/File.php";
 include_once($path);
?>

那应该就可以了 :)

1
你需要使用auto_prepend_file。如果PHP作为Apache模块运行,则将.htaccess文件的路径指向你的config.php文件,任何访问的PHP文件都会自动在其内容前添加配置文件的内容。
对于.htaccess
php_value auto_prepend_file /full/path/to/file/config.php

如果您的服务器使用CGI,则在php.ini中设置此指令,或者请记住,这仅适用于PHP作为CGI运行的服务器。您需要在php.ini文件中添加编辑,或将其放入.user.ini文件中,但不包括php_value部分。
auto_prepend_file /full/path/to/file/config.php

Nginx 中,您可以在服务器配置中的 location ~ \.php$ 内添加此行。
fastcgi_param PHP_VALUE "auto_prepend_file=/full/path/to/file/config.php";

请告诉我,如果问题没有得到解决。

我相信这会解决我的问题,如果它有效的话。请再详细解释一下:我只需要在根目录(www)中创建一个.htaccess文件,并将第一个代码放入其中? - Gui Imamura
谢谢您的输入,但它仍然给我同样的错误。在没有CGI的情况下使用apache2。 - Gui Imamura
可能是一些设置问题,.htaccess 文件正常工作吗? - Vineet1982

-1

index.php:

chdir('webroot');
require_once('home.php');

嗨。我需要一种在PHP解释器中设置默认值的方法,这样我就不必更改数百行代码,而且它还需要在包含/要求之后chdir回到原来的位置。 - Gui Imamura
这个行不通吗?如果应用程序的入口点通常是home.php,那么从home.php中echo getcwd()将读取/path/to/webroot。 - Progrock

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接