PHP`require_once`包含错误的文件

时间:2015-06-18 09:48:16

标签: php linux ext4

我在这样的Linux Ubuntu 14.04-LTS机器上有一个开发树,有三个相同的分支:

main -+-- leonardo --- project --- htdocs -+- panel --- index.php
      |                                    |
      |                                    +- config.php
      |
      +-- federico --- project --- htdocs -+- panel --- index.php
      |                                    |
      |                                    +- config.php
      |
      +-- carlo ------ project --- htdocs -+- panel --- index.php
      |                                    |
      |                                    +- config.php
    ..... (you get my drift).

既没有软链接也没有硬链接config.php文件位于svn-ignore中,并且在所有分支

之间不同

有一个Apache服务器,每个开发人员都有一个virtualHost,所以我可以在http://leonardo.project.local或Federico的http://federico.project.local看到我的开发版本。

在调查当前的怪异时,这两个文件是:

<?php // this is panel/index.php
    echo "I am " . __FILE__ . "\n";
    echo "I will include " . realpath('../config.php') . "\n";
    require_once '../config.php';

<?php // this is config.php
    echo "I am " . __FILE__ . "\n";
    exit();

预期的输出当然是:

I am leonardo/project/htdocs/panel/index.php
I will include /var/www/main/leonardo/project/htdocs/config.php
I am leonardo/project/htdocs/config.php

但实际输出是:

I am leonardo/project/htdocs/panel/index.php
I will include /var/www/main/leonardo/project/htdocs/config.php
I am federico/project/htdocs/config.php

另外的奇怪之处在于

    echo "I will include " . realpath('../config.php') . "\n";
    require_once realpath('../config.php');

作品。

TL; DR require_oncerealpath不同意'../ config.php'的实际位置。

真奇怪的是,我没有看到 leonardo/project/htdocs/panel/中运行的脚本如何知道关于federico/project/htdocs/config.php;它应该上去四个目录,然后探索很多子目录。

我几乎开始怀疑这可能是文件系统甚至内核相关的东西。

文件系统为ext4,内核为3.13.0-55-generic #92-Ubuntu SMP Sun Jun 14 18:32:20 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux。该机器是最新VMware Workstation上的虚拟x64。

检查

  • PHP的include_path仅包含./usr/local/php5/pear
  • 如前所述,分支中没有文件是符号链接,所有涉及文件的inode计数表示没有交叉链接。文件确实不同。
  • 所有文件都在那里,它不是“最后一个包括”。
  • 从命令行,在leonardo ...面板中,我运行“cat ../config.php”,我得到了我的config.php,正如预期的那样。只有PHP才能包含错误的文件。
  • 重新启动Apache(以防万一)无效。我接下来会尝试重启整个虚拟机,但为了做到这一点,我需要冻结几个服务,这需要一段时间。
  • 昨天一切都很糟糕(我当时不在这里)。在过去三天内没有系统更新,没有重新启动,甚至没有远程登录。正常运行时间为8天。
  • 我是个白痴:通过检查集成测试日志,我可以知道这个开始发生的那一刻。已经要求他们,午饭后期待他们。

2 个答案:

答案 0 :(得分:3)

值得检查include_path设置的内容(可以使用get_include_path完成此操作)。

鉴于绝对和相对路径,

requireinclude的行为会有所不同。当你使用

require_once realpath('../config.php');

这样做:

require_once '/var/www/main/leonardo/project/htdocs/config.php';

哪种方式可以预期。

以下的奇怪之处:<​​/ p>

require_once '../config.php';
发生

是因为PHP将检查匹配文件的include路径中的每个条目并返回第一个匹配的条目。因此,可能首先检查federico配置的路径。

答案 1 :(得分:1)

您是否检查过任何潜在的操作码缓存及其设置? 在过去,我遇到了一些问题,例如没有检测到已更改的文件。

具体而言,如果opcache.use_cwd设置为零,则可能会出现

  

opcache.use_cwd 布尔

     

如果启用,OPcache会将当前工作目录附加到脚本键,从而消除文件之间可能发生的冲突   相同的基本名称。禁用此指令可提高性能,   但可能会破坏现有应用

如果发生这种情况,那么第一个用户或phpunit脚本访问另一个目录中的给定名称的文件(例如leonardo/config.php vs {{1将使用该文件“填充”缓存。 federico/config.php等文件系统功能不会受到影响,并将继续工作。使用绝对路径的引用将继续工作。 相对路径的引用将以一种非常阴险的方式被破坏

在你只有一个人工作之前,那个人已经根据他的需要准备了缓存,并且什么也没注意到。然后重新开始工作,然后开始加载他的文件。

在旁注中,该设置可能会导致无意的信息泄露,因为该设置是系统范围。所以你知道你的ISP有一个破坏的use_cwd,你知道另一个站点包含'../inc/credit_cards.php',你在你的站点中准备相同的路径并包含一个相同的文件名称。 realpath可能会让您使用其他站点的登录或数据库系统。 (没有检查过,但考虑到发生了什么,不明白为什么不这样做。)