Conversation
The signature of `fread()` has changed from PHP 7.3 to 7.4
| //Parse by chunks not to use too much memory | ||
| do { | ||
| $stream_data = fread($stream, 1048576); | ||
| if (!xml_parse($xml, $stream_data === false ? '' : $stream_data, feof($stream))) { |
There was a problem hiding this comment.
That sounds like a PHPStan bug. PHP 7.3 returns false on failure too: https://3v4l.org/SfHsD
Maybe add a comment or ignore this specific error?
There was a problem hiding this comment.
At some point around PHP ~7.4, the documented signature for fread() has changed from returning string to returning string|false, and in older versions, it used to be string|null.
Anyway, if $stream_data is falsy, it does not make sense to attempt any XML parsing
There was a problem hiding this comment.
AFAICS, it was never claiming null, not even in PHP 3. It did appear to return it prior to 4.3.5 patch release but that’s probably not even worth a footnote. Even before PHP 7.0, examples were using strict comparison to Edit: the check is for false: php/doc-en@877e82bfopen handle but the same applies here.
But I agree that this should be safe remain equally safe, if ugly. I believe the only possible values that match the “real” type signature and == false are:
''– the ternary will not change it'0'– I guess this can only occur for pathological XML files, where the last chunk consists of a single0(e.g.'<a>' . str_repeat('f', 1048576 - strlen('<a></a>')) . '</a>0'). This change will mask an error in this case but I would consider the failure recoverable so the new behaviour is actually better, if unexpected.false– this can only happen on stream failure and PHP was probably already silently casting it to an empty string. Edit:feofwill also returnfalsein this case, so if this ever occurs, we get an infinite loop on PHP 7. Not sure if this can even happen in practice, perhaps if/tmpsuddenly unmounts. But the issue existed before this change as well.
There was a problem hiding this comment.
Apparently, phpstan/phpstan-src#3105 is responsible.
Just tested fread with a handle to a file from a network mount, unmounting in the middle, and it behaves as described in the PR:
On PHP 8.2.20 and 8.0.30, fread will return:
Notice: fread(): Read of 8192 bytes failed with errno=2 No such file or directory in /home/jtojnar/Projects/selfoss/read-bytes.php on line 8
bool(false)On PHP 7.4.33, it will return (no notice):
bool(false)On PHP 7.3.33, it will return (no notice):
string(0) ""Test source code
<?php
declare(strict_types=1);
$fh = fopen('/run/user/1000/gvfs/sftp:host=xxxxx/home/jtojnar/bar', 'r');
$i = 0;
do {
$buf = fread($fh, 4096);
var_dump($buf);
sleep(5);
} while ($i++ < 5);
fclose($fh);So it turns out not just the docs but also the behaviour changed.
There was a problem hiding this comment.
Great job for doing a precise test 👍🏻
In any case, I think the current PR would make the behaviour more robust AND pass with PHPStan
There was a problem hiding this comment.
While you were at it, did you check the feof() behaviour?
There was a problem hiding this comment.
Yes, feof appears to return true after unmounting on all tested versions. So the infinite loop is probably not an issue. I only managed to get feof and fread both return false when I fclosed the handle (which probably falls under bogus resource mentioned in phpstan/phpstan-src#3105).
The signature of
fread()has changed from PHP 7.3 to 7.4