PHP Phar - file_exists() issue

2019-04-07 22:03发布

问题:

My Phar script creates a new file with fwrite, which works fine, it creates the new file outside the phar, in the same directory as the phar file.

But then when i use if(file_exists('file.php')) it doesn't pick it up.

But then include and require do pick it up.

Anyone know about this problem? Been testing and researching for a while a can't seem to find a solution.

回答1:

At the PHAR's stub, you can use the __DIR__ magic constant to get the PHAR file's folder.

With that in mind, you can simply use

is_file(__DIR__ . DIRECTORY_SEPARATOR . $path);

To check for a file's existence outside the PHAR.

You can ONLY do this from the stub, and ONLY if it's a custom stub, as opposed to one generated by Phar::setDefaultStub(). If you need to check for files further down the line, you'll have to make that constant's value available somehow, like a global variable, a custom non-magical constant or a static property or something, which other files then consult with.

EDIT: Actually, you can also use dirname(Phar::running(false)) to get the PHAR's folder from anywhere in the PHAR. That function returns an empty string if you're not within a PHAR, so whether your application is executed as a PHAR or directly, it should work fine, e.g.

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


回答2:

Working with file paths and Phar archives

Working with file paths and Phar archives in PHP can be tricky. The PHP code inside of a Phar file will treat relative paths as being relative to the Phar archive, not relative to the current working directory. Here's a short example:

Say you have the following files:

phar/index.php
test.php
my.phar

The index.php file is located inside of the phar directory. It is the bootstrap file for the phar archive:

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

The bootstrap file is executed when the phar file is included from a PHP script. Our bootstrap file will simply cause the function "does_it_exist" to be declared.

Let's try running different code inside of test.php and see what the results are for each run:

//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"

Look at Run 4. This code includes the phar file and passes the function a relative path. Relative to the current working directory, index.php does not exist. But relative to the contents of the phar archive, it does exist, which is why it prints "true"!



回答3:

I meet the same issue today. After several hours digging ... I found the answer.

Can you try the following script first?

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

If the file exist, then the issue is

if you use only the filename without path information, php treat file is related to phar stub. for example:

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

So, you have to use absolute path to manipulate the file, for example:

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

Hope this help.

Mark



回答4:

I can reproduce this behavior by calling Phar::interceptFileFuncs(). It seems fopen calls in write mode are not intercepted, while stat-related functions are.

Since absolute filenames are treated as related to the filesystem even in Phar archives that intercept file functions:

[...] Absolute paths are assumed to be attempts to load external files from the filesystem.

...one way to deal with the problem is to use realpath():

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


回答5:

file_exists in php has several issues, in particular cases.

I recommend you to use stat() instead, which is commonly preffered way to obtain that info,
not just in php. Also don't forget to clear the cache by calling clearstatcache().

function FileExists($filename)
{
    clearstatcache(false, $filename);

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

Note : I try to avoid the suppress operator @ as much as I can but I see this particular case as neccessary to use it :)



回答6:

Not sure what is causing file_exists() to fail but you can try something like this

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