PHP在使用include()函数包含相对路径时会检查哪些目录?

9

这很奇怪,有人总结出结论了吗?

有时它也会检查包含文件的目录。

但有时不会。

D:\test\1.php

<?php

include('sub\2.php');

D:\test\2.php

<?php

include('3.php');

3.php2.php在同一目录下。

上述方法可以工作,但是为什么呢?当前目录应该是D:\test,但它仍然可以找到位于D:\test\sub中的3.php。

更多故事(最终版)

大约一年前,我遇到了这个问题,然后我用以下硬编码解决了它:

Common.php:

if (file_exists("../../../Common/PHP/Config.inc"))
    include('../../../Common/PHP/Config.inc');

if (file_exists("../../Common/PHP/Config.inc"))
    include('../../Common/PHP/Config.inc');

if (file_exists("../Common/PHP/Config.inc"))
    include('../Common/PHP/Config.inc');

if (file_exists("Common/PHP/Config.inc"))
    include('Common/PHP/Config.inc');

Config.incCommon.php在同一目录中。


1
好问题!我可以在Windows和Linux上确认这一点。我不知道为什么会出现这种情况。 - Pekka
关于您的最后一个例子,如果“Config.inc”与“Common.php”在同一目录中,则可以简化为include(dirname(__FILE__).'/Config.inc'); - 这将始终起作用,无论include_path和包含“Common.php”的文件是哪个。如果没有机会在include_path(其中通常包括当前目录)中找到“Config.inc”,那么您可以简单地调用include 'Config.inc';,尽管这可能效率较低,因为首先搜索include_path(失败)。 - MrWhite
在您的第一个示例中,我假设 "D:\test\2.php" 应该是 "D:\test\sub\2.php" 吗?(否则 include('sub\2.php'); 将永远不起作用。) - MrWhite
我刚刚经历了你所描述的情况。我一直在我的包含文件中(其中两个文件存在于同一个子目录中)不带路径地包含文件,并且在多个服务器上都可以正常工作。但是在周五,突然有一台服务器无法正常工作了。现在我必须在包含文件中指定路径,否则它就找不到了。我不知道为什么会这样。所有服务器上的PHP版本完全相同。如果你解决了这个问题,我很想听听你的故事更新。 - Vincent
3个回答

2
如果您查看main/fopen_wrappers.c文件中PHP的源代码,您会发现:
/* check in calling scripts' current working directory as a fall back case
     */
    if (zend_is_executing(TSRMLS_C)) {
        char *exec_fname = zend_get_executed_filename(TSRMLS_C);
        int exec_fname_length = strlen(exec_fname);

        while ((--exec_fname_length >= 0) && !IS_SLASH(exec_fname[exec_fname_length]));
        if (exec_fname && exec_fname[0] != '[' &&
            exec_fname_length > 0 &&
            exec_fname_length + 1 + filename_length + 1 < MAXPATHLEN) {
            memcpy(trypath, exec_fname, exec_fname_length + 1);
            memcpy(trypath+exec_fname_length + 1, filename, filename_length+1);
            actual_path = trypath;

这个似乎是无条件执行的,因此将始终使与包含/文件打开脚本相同路径的文件可访问...作为在include_path中指定的所有可能性之后的最后选择。只有在include()中没有定义相对或绝对路径时才会发生。


我似乎不理解这段代码,有什么线索可以解释为什么有时它不检查所包含文件的目录? - user198729
我的问题是有时它找不到3.php,但我很难复现。但它与包含文件在同一个目录中。也许当include在函数/方法中时,我猜... - user198729
因此,澄清一下:在这种情况下它找不到任何3.php(不仅仅是“错误”的那个,而是根本没有)。 你不能轻易地重现它... 嗯。 它会在不同的服务器/版本/配置上发生吗? 还是像“Heisenbug”一样,在相同的机器上使用相同的代码而不需要触及似乎相关的任何东西就会发生? - VolkerK
是的。它发生在不同的服务器上,我不认为它是一种Heisenbug。 - user198729
是的,我做了;-) 但由于我没有更多线索,也许有一些信息可以添加。例如,“它发生在不同的服务器上”是应该让您点击原始问题的“编辑”按钮的内容。也许您已经注意到了一些/任何模式。php版本,在服务器上设置include_path的某些内容,phpoinfo()输出中“configure command”的一些显着特点...任何东西;-) 因为正如您从迄今为止所有答案中所看到的那样,php的这种行为并不是太明显的事情。 - VolkerK
显示剩余10条评论

1

它会检查当前路径和include_path中列出的目录。

您可以运行phpinfo()来查看您的包含路径。


这并没有解释我所描述的问题 :( - user198729
据我所知,这就是全部。请举一些文件何时被加载以及何时不被加载的示例。 - Pekka
如果我们不显式地更改目录(例如chdir()),在请求期间,getcwd()会发生变化吗?我马上举例说明。 - user198729
如果您所说的“当前路径”指的是 _当前工作目录_,那么它仅在包含在include_path中时检查CWD(默认情况下包括)。但是,如果您所说的“当前路径”是脚本所在的目录(即dirname(__FILE__) - 具有include语句并且不一定与CWD相同),则只有在无法在include_path中找到它时才会检查。 - MrWhite

1
有时候包含文件的目录是“当前工作目录”,有时候不是
可以使用getcwd()函数来检查当前目录

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