Skip to content

Fix PHPStan for PHP 7.3#869

Merged
mblaney merged 6 commits intosimplepie:masterfrom
FreshRSS:fix-phpstan-php7
Jul 22, 2024
Merged

Fix PHPStan for PHP 7.3#869
mblaney merged 6 commits intosimplepie:masterfrom
FreshRSS:fix-phpstan-php7

Conversation

@Alkarex
Copy link
Contributor

@Alkarex Alkarex commented Jun 18, 2024

The signature of fread() has changed from PHP 7.3 to 7.4

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))) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

Copy link
Contributor Author

@Alkarex Alkarex Jun 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comments added: 3bf0734

Copy link
Member

@jtojnar jtojnar Jun 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 false: php/doc-en@877e82b Edit: the check is for fopen 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 single 0 (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: feof will also return false in 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 /tmp suddenly unmounts. But the issue existed before this change as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment simplified 215365a

Copy link
Member

@jtojnar jtojnar Jun 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Contributor Author

@Alkarex Alkarex Jun 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While you were at it, did you check the feof() behaviour?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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).

@grimmdude grimmdude mentioned this pull request Jun 23, 2024
@mblaney mblaney merged commit b9e2529 into simplepie:master Jul 22, 2024
@Alkarex Alkarex deleted the fix-phpstan-php7 branch July 22, 2024 07:42
@Art4 Art4 added this to the 1.9.0 milestone Sep 30, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants