PHP Phar - file_exists() 问题

Posted

技术标签:

【中文标题】PHP Phar - file_exists() 问题【英文标题】:PHP Phar - file_exists() issue 【发布时间】:2013-08-21 22:40:25 【问题描述】:

我的 Phar 脚本使用 fwrite 创建了一个新文件,它工作正常,它在 phar 之外创建新文件,与 phar 文件位于同一目录中。

但是当我使用 if(file_exists('file.php')) 时,它不会捡起它。

然后 include 和 require 就可以了。

有人知道这个问题吗? 测试和研究了一段时间似乎找不到解决方案。

【问题讨论】:

什么版本的 PHP? URL 包装器只能在版本 =>PHP 5.0.0 您是否尝试过file_exists() 文档中的以下建议:“注意:此函数的结果已缓存。有关详细信息,请参阅 clearstatcache()。”? 是的,我已经尝试过 clearstatcache() - 但缓存会将其存储为“存在”,我的问题是它没有找到它 - 所以这绝对不是罪魁祸首。 可以举例说明您的目录结构和运行脚本的位置,其中包括一些其他脚本以及写入结束的位置。 【参考方案1】:

在 PHAR 的存根处,您可以使用 __DIR__ 魔术常量来获取 PHAR 文件的文件夹。

考虑到这一点,您可以简单地使用

is_file(__DIR__ . DIRECTORY_SEPARATOR . $path);

检查文件是否存在于 PHAR 之外。

您只能从存根中执行此操作,并且仅当它是自定义存根时,而不是由 Phar::setDefaultStub() 生成的存根。如果您需要进一步检查文件,则必须以某种方式使该常量的值可用,例如全局变量,自定义非魔术常量或静态属性或其他文件,然后再进行咨询。

编辑:实际上,您也可以使用dirname(Phar::running(false)) 从 PHAR 中的任何位置获取 PHAR 的文件夹。如果您不在 PHAR 中,该函数将返回一个空字符串,因此无论您的应用程序是作为 PHAR 执行还是直接执行,它都应该可以正常工作,例如

$pharFile = Phar::running(false);
is_file(('' === $pharFile ? '' : dirname($pharFile) . DIRECTORY_SEPARATOR) . $path)

【讨论】:

使用__DIR__ 绝对行不通,不是来自自定义存根,甚至一点都没有。它将返回 phar 的当前工作目录,__FILE__ 将返回 phar 名称。【参考方案2】:

我今天遇到了同样的问题。经过几个小时的挖掘……我找到了答案。

你能先试试下面的脚本吗?

if(file_exists(realpath('file.php')));

如果文件存在,那么问题是

如果你只使用没有路径信息的文件名,php处理文件与phar stub有关。例如:

phar:///a/b/c/file.php

所以,你必须使用绝对路径来操作文件,例如:

/home/www/d/e/f/file.php

希望对您有所帮助。

标记

【讨论】:

【参考方案3】:

使用文件路径和 Phar 档案

在 PHP 中使用文件路径和 Phar 存档可能会很棘手。 Phar 文件中的 PHP 代码会将相对路径视为相对于 Phar 存档的相对路径,not 相对于当前工作目录。这是一个简短的例子:

假设你有以下文件:

phar/index.php
test.php
my.phar

index.php 文件位于 phar 目录中。它是 phar 存档的引导文件:

function does_it_exist($file)
  return file_exists($file) ? "true" : "false";

当 phar 文件包含在 PHP 脚本中时,将执行引导文件。我们的引导文件将简单地导致函数“does_it_exist”被声明。

让我们尝试在 test.php 中运行不同的代码,看看每次运行的结果如何:

//Run 1:
require_once 'phar/index.php';  //PHP file
$file = __DIR__ . "/index.php"; //absolute path
echo does_it_exist($file);      //prints "false"

//Run 2:
require_once 'phar/index.php';  //PHP file
$file = "index.php";            //relative path
echo does_it_exist($file);      //prints "false"

//Run 3:
require_once 'my.phar';         //phar file
$file = __DIR__ . "/index.php"; //absolute path
echo does_it_exist($file);      //prints "false"

//Run 4:
require_once 'my.phar';         //phar file
$file = "index.php";            //relative path
echo does_it_exist($file);      //prints "true"

查看运行 4。此代码包含 phar 文件并向函数传递相对路径。相对于当前工作目录,index.php 不存在。但是相对于 phar 存档的内容,它确实存在,这就是它打印“true”的原因!

【讨论】:

我知道,我知道。那不是问题。我的 phar 包使用 fwrite 在 phar 脚本之外创建了一个新文件。完美运行,创建了一个新文件。以后可以通过 include 或 require 读取此新内容,但 file_exists 无法“看到”它-这是我的问题-我认为这可能是 phar 中的错误 @Lan 回复了你的问题 谢谢,但如果 include('login.php') 或 require('login.php') 都找到并读取文件,那么 if(file_exists('login.php')) 肯定会返回 true - 肯定是因为它的 include/require 读取表明文件路径/位置是正确的,所以这不是问题吗? @Lan 更改了答案以更轻松地理解工作 这个答案来自mangstacular.blogspot.co.uk/2011/06/…【参考方案4】:

我可以通过调用Phar::interceptFileFuncs() 重现此行为。看来fopen写模式的调用没有被拦截,而stat相关的函数被拦截了。

因为即使在截取文件函数的 Phar 档案中,绝对文件名也被视为与文件系统相关:

[...] 假定绝对路径是尝试从文件系统加载外部文件。

...解决问题的一种方法是使用realpath()

if (file_exists(realpath($filename))  /* file exists on filesystem */ 

【讨论】:

【参考方案5】:

file_exists 在 php 中有几个问题,在特定情况下。

我建议您改用stat(),这是获取该信息的常用方法, 不只是在 php 中。另外不要忘记调用clearstatcache()清除缓存。

function FileExists($filename)

    clearstatcache(false, $filename);

    return false !== @stat($filename);

注意:我尽量避免使用抑制运算符@,但我认为这种特殊情况需要使用它:)

【讨论】:

【参考方案6】:

不确定是什么导致file_exists() 失败,但您可以尝试类似的方法

 function fileExists($path)
    //try to open the file, if it can be read the file exist
    return (@fopen($path,"r") == true); 
 

【讨论】:

啊,好主意。谢谢。之后我需要关闭它以使其更合法吗? 是的,当然!如果 fopen 函数成功,您可以在之后关闭它。打开文件,如果成功则关闭文件并返回true,否则返回false。

以上是关于PHP Phar - file_exists() 问题的主要内容,如果未能解决你的问题,请参考以下文章

打包phar文件过大的问题。

浅析phar反序列化漏洞攻击及实战

浅析phar反序列化漏洞攻击及实战

php php phar打包文件[php phar包装代码]

PHP中phar包的使用

为啥 PHP 中的 phar 写支持特别被锁定?