php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #79121 is_writable not working for path in phar archive, regardless of phar.readonly
Submitted: 2020-01-15 17:11 UTC Modified: 2020-01-23 08:33 UTC
From: alex at 1stleg dot com Assigned:
Status: Open Package: PHAR related
PHP Version: 7.2.26 OS: Ubuntu 18.04.3 LTS
Private report: No CVE-ID: None
 [2020-01-15 17:11 UTC] alex at 1stleg dot com
Description:
------------
is_writable seems to be incapable of detecting if a path within a phar archive can be written to.

Test script:
---------------
pharstub.php

<?php
Phar::interceptFileFuncs();
set_include_path("phar://archive.phar" . PATH_SEPARATOR . get_include_path());
include "public/index.php";
__HALT_COMPILER();



public/index.php

<?php
if (is_writable("phar://archive.phar/folder")) {
    die("yes");
} else {
    die("no");
}


create-phar.php

#!/bin/env php
<?php
$phar = new Phar('archive.phar');
$phar->addEmptyDir('folder/');
$phar->buildFromIterator(new RecursiveIteratorIterator(new RecursiveDirectoryIterator("public/", FilesystemIterator::SKIP_DOTS)), ".");
$phar->setStub(file_get_contents("pharstub.php"));
$phar->compressFiles(Phar::GZ);

Expected result:
----------------
I would expect that is_writable will return true under some circumstance for folders within a phar.  Currently it will return false regardless of phar.readonly = off or chmod 0777 of the internal folder or chmod 0777 of the phar archive.  

Actual result:
--------------
Phar does not appear to be ready for production, or really anything outside of a novelty application.

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2020-01-22 17:47 UTC] alex at 1stleg dot com
Just to further add to this:

var_dump($configDir, is_dir($configDir), is_readable($configDir), realpath($configDir), scandir($configDir));

string(8) "./config"
bool(true)
bool(true)
bool(false)
bool(false)

Needless to say, I am not very excited about these issues.
 [2020-01-23 00:02 UTC] alex at 1stleg dot com
The really effed up part is that include  "phar:///path/to/archive.phar/folder/file.php" will not work, but is_file( "phar:///path/to/archive.phar/folder/file.php") works just fine.  Can we pick a method for resolving files in a phar archive across all file functions?  There is really no way to get phar to do anything useful beyond using "./" as a path.  After 20 years of PHP it is really time to move on to something mature.
 [2020-01-23 01:15 UTC] alex at 1stleg dot com
Also broken, include path ".";

For example:

lets say the php path is "." and in my pwd, folder exists file with file.php.

include "folder/file.php"; // works as expected.

include "./folder/file.php"; // shits it's pants.

Not sure we could screw up path handling any more than it is.
 [2020-01-23 01:33 UTC] alex at 1stleg dot com
Now I am randomly getting "unable to create temporary file"

WHAT THE EF!  I am done with this.  go back and rewrite it with a brain.  PS this captcha is bullshit.
 [2020-01-23 06:15 UTC] alex at 1stleg dot com
I will update as I discover more issues, example code is available in the same repo.

https://github.com/kwhat/dumpsterfire-phar/blob/master/index.md
https://github.com/kwhat/dumpsterfire-phar/blob/master/phar.md
 [2020-01-23 08:33 UTC] nikic@php.net
> Also broken, include path ".";
> 
> For example:
>
> lets say the php path is "." and in my pwd, folder exists file with file.php.>
>
> include "folder/file.php"; // works as expected.
>
> include "./folder/file.php"; // shits it's pants.
>
> Not sure we could screw up path handling any more than it is.

It's really hard to tell from these ramblings, but if I understand correctly, you are talking about plain files here, not phars, right?

In that case, you do realize that those two paths refer to different things? "./folder/file.php" is relative to the current working directory, while "folder/file.php" is relative to the include_path and the including script as a fallback.

My immediate suspicion would be that are are confusing the "current working directory" and the "directory of the including script". Both paths will work against the cwd (if "." is in the include path), but only the first path against the directory of the current script.

I recommend using __DIR__ relative paths to avoid this kind of confusion.
 [2020-01-23 19:05 UTC] alex at 1stleg dot com
The https://github.com/kwhat/dumpsterfire-phar/blob/master/index.md file is run using the arguments specified using index.php as the entry point and public/ as the document root/cwd.  This is the baseline for how I would expect stuff to work, everything is normal except for glob() a phar:// path.  The glob maybe broken for other reasons and it is really the smallest of these issues.

When we look at https://github.com/kwhat/dumpsterfire-phar/blob/master/phar.md we can see what didn't match up to our index.md baseline.  Glob experiences a number of new failures for the relative paths, which are expected.

 * "../config/": For some reason this is found while using the phar... I don't believe it should have been.
 * phar.readonly: This is empty string, it is specified in the cli ini as phar.readonly = Off.  According to the docs, this should come from the ini but can only be set with -d.
 * is_writeable: This doesn't appear to work when using phar.
 * include "./config/" vs "config/" This makes some sense, except for is_dir/is_file "./config/" returning true when within the phar.

If we take a look at https://github.com/kwhat/dumpsterfire-phar/blob/master/create-phar.php:

 * @unlink('/tmp/archive.phar'): Sometimes phar archive updating will cause a failure depending on the change.
 * $phar->compressFiles(Phar::GZ): Causes failure to create temp file error when compressing phar of any meaningful size.
 * $phar->buildFromIterator does not update the $phar objects contents. Start/Stop buffering has no effect.  The only workaround I found was `$phar = new Phar($phar->getPath())`
 [2023-01-03 10:29 UTC] Gail1985Marshall at gmail dot com
Try defining the full path.

$path = '.';
if (!empty($pharPath = \Phar::running(false))) {
    $path = dirname($pharPath);
} 

$this->fileSystem->dumpFile(
    $path.'/testfile.txt',
    'my test content'
);

(https://www.myhealthatvanderbilt.net/)github.com
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Mon Dec 09 14:01:27 2024 UTC