forked from php/php-src
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Make buildFromIterator() work with custom SplFileInfo objects
While it is possible to return a custom SplFileInfo object in the iterator used by buildFromIterator(), the data is not actually used from that object, instead the data from the underlying internal structure is used. This makes it impossible to override some metadata such as the path name and modification time. The main motivation comes from two reasons: - Consistency. We expect our custom methods to be called when having a custom object. - Support reproducibility. This is the original use case as requested in [1]. Add support for this by calling the getMTime() and getPathname() methods if they're overriden by a user class. [1] theseer/Autoload#114.
- Loading branch information
Showing
5 changed files
with
385 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
--TEST-- | ||
buildFromIterator with user overrides 001 - getMTime() | ||
--EXTENSIONS-- | ||
phar | ||
--INI-- | ||
phar.readonly=0 | ||
phar.require_hash=0 | ||
--CREDITS-- | ||
Arne Blankerts | ||
Niels Dossche | ||
--FILE-- | ||
<?php | ||
|
||
class MySplFileInfo extends SplFileInfo { | ||
public function getPathname(): string { | ||
echo "[Pathname]\n"; | ||
return parent::getPathname(); | ||
} | ||
|
||
public function getMTime(): int|false { | ||
echo "[MTime]\n"; | ||
return 123; | ||
} | ||
|
||
public function getCTime(): int { | ||
// This should not get called | ||
echo "[CTime]\n"; | ||
return 0; | ||
} | ||
|
||
public function getATime(): int { | ||
// This should not get called | ||
echo "[ATime]\n"; | ||
return 0; | ||
} | ||
} | ||
|
||
class MyIterator extends RecursiveDirectoryIterator { | ||
public function current(): SplFileInfo { | ||
echo "[ Found: " . parent::current()->getPathname() . " ]\n"; | ||
return new MySplFileInfo(parent::current()->getPathname()); | ||
} | ||
} | ||
|
||
$workdir = __DIR__.'/001'; | ||
mkdir($workdir . '/content', recursive: true); | ||
file_put_contents($workdir . '/content/hello.txt', "Hello world."); | ||
|
||
$phar = new \Phar($workdir . '/test.phar'); | ||
$phar->startBuffering(); | ||
$phar->buildFromIterator( | ||
new RecursiveIteratorIterator( | ||
new MyIterator($workdir . '/content', FilesystemIterator::SKIP_DOTS) | ||
), | ||
$workdir | ||
); | ||
$phar->stopBuffering(); | ||
|
||
|
||
$result = new \Phar($workdir . '/test.phar', 0, 'test.phar'); | ||
var_dump($result['content/hello.txt']); | ||
var_dump($result['content/hello.txt']->getATime()); | ||
var_dump($result['content/hello.txt']->getMTime()); | ||
var_dump($result['content/hello.txt']->getCTime()); | ||
|
||
?> | ||
--CLEAN-- | ||
<?php | ||
$workdir = __DIR__.'/001'; | ||
@unlink($workdir . '/test.phar'); | ||
@unlink($workdir . '/content/hello.txt'); | ||
@rmdir($workdir . '/content'); | ||
@rmdir($workdir); | ||
?> | ||
--EXPECTF-- | ||
[ Found: %shello.txt ] | ||
[Pathname] | ||
[MTime] | ||
object(PharFileInfo)#%d (2) { | ||
["pathName":"SplFileInfo":private]=> | ||
string(%d) "phar://%shello.txt" | ||
["fileName":"SplFileInfo":private]=> | ||
string(%d) "hello.txt" | ||
} | ||
int(123) | ||
int(123) | ||
int(123) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
--TEST-- | ||
buildFromIterator with user overrides 002 - errors in getMTime() | ||
--EXTENSIONS-- | ||
phar | ||
--SKIPIF-- | ||
<?php | ||
if (PHP_INT_SIZE != 8) die("skip: 64-bit only"); | ||
?> | ||
--INI-- | ||
phar.readonly=0 | ||
phar.require_hash=0 | ||
--CREDITS-- | ||
Arne Blankerts | ||
Niels Dossche | ||
--FILE-- | ||
<?php | ||
|
||
class MySplFileInfo1 extends SplFileInfo { | ||
public function getMTime(): int|false { | ||
echo "[MTime]\n"; | ||
return PHP_INT_MAX; | ||
} | ||
} | ||
|
||
class MySplFileInfo2 extends SplFileInfo { | ||
public function getMTime(): int|false { | ||
echo "[MTime]\n"; | ||
return false; | ||
} | ||
} | ||
|
||
class MySplFileInfo3 extends SplFileInfo { | ||
public function getMTime(): int|false { | ||
echo "[MTime]\n"; | ||
throw new Error('Throwing an exception inside getMTime()'); | ||
} | ||
} | ||
|
||
class MyIterator extends RecursiveDirectoryIterator { | ||
public function current(): SplFileInfo { | ||
static $counter = 0; | ||
$counter++; | ||
echo "[ Found: " . parent::current()->getPathname() . " ]\n"; | ||
if ($counter === 1) { | ||
return new MySplFileInfo1(parent::current()->getPathname()); | ||
} else if ($counter === 2) { | ||
return new MySplFileInfo2(parent::current()->getPathname()); | ||
} else if ($counter === 3) { | ||
return new MySplFileInfo3(parent::current()->getPathname()); | ||
} | ||
} | ||
} | ||
|
||
$workdir = __DIR__.'/002'; | ||
mkdir($workdir . '/content', recursive: true); | ||
file_put_contents($workdir . '/content/hello.txt', "Hello world."); | ||
|
||
for ($i = 0; $i < 3; $i++) { | ||
echo "--- Iteration $i ---\n"; | ||
try { | ||
$phar = new \Phar($workdir . "/test$i.phar"); | ||
$phar->startBuffering(); | ||
$phar->buildFromIterator( | ||
new RecursiveIteratorIterator( | ||
new MyIterator($workdir . '/content', FilesystemIterator::SKIP_DOTS) | ||
), | ||
$workdir | ||
); | ||
$phar->stopBuffering(); | ||
} catch (Throwable $e) { | ||
echo $e->getMessage(), "\n"; | ||
} | ||
} | ||
|
||
?> | ||
--CLEAN-- | ||
<?php | ||
$workdir = __DIR__.'/002'; | ||
@unlink($workdir . '/content/hello.txt'); | ||
@rmdir($workdir . '/content'); | ||
@rmdir($workdir); | ||
?> | ||
--EXPECTF-- | ||
--- Iteration 0 --- | ||
[ Found: %shello.txt ] | ||
[MTime] | ||
Entry content/hello.txt cannot be created: timestamp is limited to 32-bit | ||
--- Iteration 1 --- | ||
[ Found: %shello.txt ] | ||
[MTime] | ||
Entry content/hello.txt cannot be created: getMTime() failed | ||
--- Iteration 2 --- | ||
[ Found: %shello.txt ] | ||
[MTime] | ||
Throwing an exception inside getMTime() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
--TEST-- | ||
buildFromIterator with user overrides 003 - errors in getPathname() | ||
--EXTENSIONS-- | ||
phar | ||
--INI-- | ||
phar.readonly=0 | ||
phar.require_hash=0 | ||
--CREDITS-- | ||
Arne Blankerts | ||
Niels Dossche | ||
--FILE-- | ||
<?php | ||
|
||
class MyGlobIterator extends GlobIterator { | ||
public function getPathname(): string { | ||
var_dump(parent::getPathname()); | ||
throw new Error('exception in getPathname()'); | ||
} | ||
} | ||
|
||
class MyIterator extends RecursiveDirectoryIterator { | ||
public function current(): SplFileInfo { | ||
echo "[ Found: " . parent::current()->getPathname() . " ]\n"; | ||
return new MyGlobIterator(parent::current()->getPath() . '/*'); | ||
} | ||
} | ||
|
||
$workdir = __DIR__.'/003'; | ||
mkdir($workdir . '/content', recursive: true); | ||
file_put_contents($workdir . '/content/hello.txt', "Hello world."); | ||
|
||
$phar = new \Phar($workdir . "/test.phar"); | ||
$phar->startBuffering(); | ||
try { | ||
$phar->buildFromIterator( | ||
new RecursiveIteratorIterator( | ||
new MyIterator($workdir . '/content', FilesystemIterator::SKIP_DOTS) | ||
), | ||
$workdir | ||
); | ||
} catch (Throwable $e) { | ||
echo $e->getMessage(), "\n"; | ||
} | ||
$phar->stopBuffering(); | ||
|
||
?> | ||
--CLEAN-- | ||
<?php | ||
$workdir = __DIR__.'/003'; | ||
@unlink($workdir . '/content/hello.txt'); | ||
@rmdir($workdir . '/content'); | ||
@rmdir($workdir); | ||
?> | ||
--EXPECTF-- | ||
[ Found: %shello.txt ] | ||
string(%d) "%shello.txt" | ||
exception in getPathname() |
Oops, something went wrong.