You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
<?php$a = newPhar(__DIR__ . '/a.phar');
$a->addFromString(
'foo.php',
<<<'EOT'
<?php echo "this is foo.php\n";
EOT
);
$a->addFromString(
'bar.php',
<<<'EOT'
<?php echo "this is bar.php\n";
EOT
);
$a->setStub(
<<<'EOT'
<?php Phar::mapPhar('a.phar'); include 'phar://a.phar/foo.php'; rename('b.phar', 'a.phar'); include 'phar://a.phar/bar.php'; __HALT_COMPILER(); ?>
EOT
);
$a = newPhar(__DIR__ . '/b.phar');
$a->addFromString(
'bar.php',
<<<'EOT'
<?php /* Shift the offsets compared to a.phar. */ echo "this is bar.php\n";
EOT
);
$a->addFromString(
'foo.php',
<<<'EOT'
<?php echo "this is foo.php\n";
EOT
);
$a->setStub(
<<<'EOT'
<?php Phar::mapPhar('b.phar'); include 'phar://b.phar/foo.php'; rename('a.phar', 'b.phar'); include 'phar://b.phar/bar.php'; __HALT_COMPILER(); ?>
EOT
);
Running php a.phar resulted in this output:
this is foo.php
PHP Parse error: Unterminated comment starting line 2 in phar:///*redacted*/a.phar/bar.php on line 2
But I expected this output instead:
this is foo.php
this is bar.php
The reason for this appears to be that the file offsets and lengths are cached during the mapPhar(), but each time the phar is opened with phar://X.phar it is reopened from disk without validating that it's still the same phar / instead of reopening it from a cached file descriptor.
Right, and if I understand correctly: to fix this we should only use the cached file offsets if the file is still the same. The alternative of unconditionally using the cached offsets together with the cached phar would not work because that will still not allow auto-updating phars to work.
The alternative of unconditionally using the cached offsets together with the cached phar would not work because that will still not allow auto-updating phars to work.
Do you mean because of Windows not allowing to delete / rename a file that is still open?
Because my expectation would be that the state of the files within a Phar is internally consistent, independent of whether I load a file before or after the Phar is replaced on disk. It should not silently use a new version (an error would be fine, caching the actual contents would be preferred).
If I want to access the new contents, I would loadPhar() them.
I'm getting confused about this ticket, but I think I'm starting to understand your perspective. Let's make sure we're on the same page.
I understand that there is a bug here in that there's a mismatch between the cached offsets and when the contents are being read, resulting in the contents being garbled.
I saw two possible fixes:
"Detect" that the file has changed and throw away the cached offsets, rely only on the disk contents
Only rely on cached data, regardless of the change on disk
I thought the proper fix would be option 1, but you seem to imply the proper fix is option 2.
I suppose that option 1 is not viable for self-updating phars because the updater still needs to run the old code?
I would have to recheck how this works again internally, but I'm not so sure that the phar file contents are cached (e.g. if a particular file in the phar was never read before).
Description
The following code:
Running
php a.phar
resulted in this output:But I expected this output instead:
The reason for this appears to be that the file offsets and lengths are cached during the
mapPhar()
, but each time the phar is opened withphar://X.phar
it is reopened from disk without validating that it's still the same phar / instead of reopening it from a cached file descriptor.This is an issue for self-updating phars where the autoloader needs to load a class after the update has been performed.
PHP Version
PHP 8.3.14
Operating System
Ubuntu 24.04
The text was updated successfully, but these errors were encountered: