sabre-io / dav

sabre/dav is a CalDAV, CardDAV and WebDAV framework for PHP
http://sabre.io
BSD 3-Clause "New" or "Revised" License
1.53k stars 346 forks source link

Baikal 0.91 PHP 7.4 ErrorException: non-numeric value #1430

Open 4b69 opened 2 years ago

4b69 commented 2 years ago

Since upgrading to Baikal 0.91 running Debian Bullseye with PHP 7.4, Baikal produces this error:

php-fpm7.4[1093]: ool www[1093]: ErrorException: A non-numeric value encountered in /var/www/baikal/vendor/sabre/dav/lib/CalDAV/Backend/PDO.php:984
php-fpm7.4[1093]: ool www[1093]: Stack trace:
php-fpm7.4[1093]: ool www[1093]: #0 /var/www/baikal/vendor/sabre/dav/lib/CalDAV/Backend/PDO.php(984): Baikal\Framework::exception_error_handler()
php-fpm7.4[1093]: ool www[1093]: sabre-io/Baikal#1 /var/www/baikal/vendor/sabre/dav/lib/CalDAV/Calendar.php(454): Sabre\CalDAV\Backend\PDO->getChangesForCalendar()
php-fpm7.4[1093]: ool www[1093]: sabre-io/Baikal#2 /var/www/baikal/vendor/sabre/dav/lib/DAV/Sync/Plugin.php(121): Sabre\CalDAV\Calendar->getChanges()
php-fpm7.4[1093]: ool www[1093]: sabre-io/Baikal#3 /var/www/baikal/vendor/sabre/dav/lib/DAV/Sync/Plugin.php(62): Sabre\DAV\Sync\Plugin->syncCollection()
php-fpm7.4[1093]: ool www[1093]: sabre-io/Baikal#4 /var/www/baikal/vendor/sabre/event/lib/WildcardEmitterTrait.php(89): Sabre\DAV\Sync\Plugin->Sabre\DAV\Sync\{closure}()
php-fpm7.4[1093]: ool www[1093]: sabre-io/Baikal#5 /var/www/baikal/vendor/sabre/dav/lib/DAV/CorePlugin.php(685): Sabre\DAV\Server->emit()
php-fpm7.4[1093]: ool www[1093]: sabre-io/Baikal#6 /var/www/baikal/vendor/sabre/event/lib/WildcardEmitterTrait.php(89): Sabre\DAV\CorePlugin->httpReport()
php-fpm7.4[1093]: ool www[1093]: sabre-io/Baikal#7 /var/www/baikal/vendor/sabre/dav/lib/DAV/Server.php(472): Sabre\DAV\Server->emit()
php-fpm7.4[1093]: ool www[1093]: sabre-io/Baikal#8 /var/www/baikal/vendor/sabre/dav/lib/DAV/Server.php(253): Sabre\DAV\Server->invokeMethod()
php-fpm7.4[1093]: ool www[1093]: sabre-io/Baikal#9 /var/www/baikal/vendor/sabre/dav/lib/DAV/Server.php(321): Sabre\DAV\Server->start()
php-fpm7.4[1093]: ool www[1093]: sabre-io/Baikal#10 /var/www/baikal/Core/Frameworks/Baikal/Core/Server.php(119): Sabre\DAV\Server->exec()
php-fpm7.4[1093]: ool www[1093]: sabre-io/Baikal#11 /var/www/baikal/html/dav.php(69): Baikal\Core\Server->start()
php-fpm7.4[1090]: ool www[1090]: sabre-io/Baikal#12 {main}
phil-davis commented 2 years ago

At https://github.com/sabre-io/dav/blob/master/lib/CalDAV/Backend/PDO.php#L984 I see:

if (null === $currentToken || $currentToken < $operation['synctoken'] + 1) {

And when I run the code, $operation['synctoken'] is a string (numeric string, thankfully). I am suspicious that strict_types=1 enabled for this code means that incrementing a string + 1 would not be allowed. But I don't think that strict_types in PHP has got so far as to check that sort of thing. I can't reproduce a problem when I execute that code locally.

Can you post the code that is around /var/www/baikal/vendor/sabre/dav/lib/CalDAV/Backend/PDO.php:984 on your system?

I would first like to make sure that I know the correct line of code that is crashing.

4b69 commented 2 years ago
                if (null === $currentToken || $currentToken < $operation['synctoken'] + 1) {
                    // SyncToken in CalDAV perspective is consistently the next number of the last synced change event in this class.
                    $currentToken = $operation['synctoken'] + 1;
                }

                ++$result_count;
                switch ($operation['operation']) {
                    case 1:
                        $result['added'][] = $uri;
                        break;
                    case 2:
                        $result['modified'][] = $uri;
                        break;
                    case 3:
                        $result['deleted'][] = $uri;
                        break;
                }
            }

Line 984 on my system is the same as in your quote.

I've had a further look and am only able to replicate the issue when trying to sync with Thunderbird (TbSync + Provider for CalDAV & CardDAV). The issue doesn't seem to occur with DavX5 on Andorid.

phil-davis commented 2 years ago

@4b69 are you able to temporarily try putting an explicit (int) cast in front of the $operation['synctoken'] uses?

                if (null === $currentToken || $currentToken < (int) $operation['synctoken'] + 1) {
                    // SyncToken in CalDAV perspective is consistently the next number of the last synced change event in this class.
                    $currentToken = (int) $operation['synctoken'] + 1;
                }

And if that does not help, it would be useful to see what the value of $operation['synctoken'] is - it is expected to always be a numeric string, but maybe it somehow has some mix of numbers and characters.

Note: the failing line is new code introduced in https://github.com/sabre-io/dav/pull/1248 which was released in https://github.com/sabre-io/dav/blob/master/CHANGELOG.md#422-2021-12-09

4b69 commented 2 years ago
                if (null === $currentToken || $currentToken < (int) $operation['synctoken'] + 1) {
                    // SyncToken in CalDAV perspective is consistently the next number of the last synced change event in this class.
                    $currentToken = (int) $operation['synctoken'] + 1;
                }

That fixes the issue instantly.

phil-davis commented 2 years ago

That fixes the issue instantly.

Thanks for the feedback. It would be great if you are able to find out what $operation['synctoken'] - put in some debug code like:

$x = $operation['synctoken'];
var_dump($x);

and somewhere on the server be able to see that var_dump($x) output in a log file or...

It will make us more sure of fixing it properly if we know what kind of data is happening at run-time.

4b69 commented 2 years ago

Using

ob_start();
var_dump($operation['synctoken']);
$data = ob_get_clean();
$fp = fopen("/tmp/phpdbg.txt", "w");
fwrite($fp, $data);
fclose($fp);

the output file contains:

string(4) "1076"

phil-davis commented 2 years ago

I was thinking that something like this is happening:

<?php

$x = "1076a";
$y = $x + 1;
var_dump($x);
var_dump($y);

NOTICE A non well formed numeric value encountered on line number 4
string(5) "1076a" int(1077) 

If the "number" has extra characters on the end (or even whitespace) then this sort of notice is emitted, and is becoming an exception.

But your string is a numeric string with 4 valid digits.

ByteHamster commented 1 year ago

This is an issue specific to sabre/dav, not Baikal. Moving to the sabre/dav repo.

zg commented 1 year ago

I'm experiencing this issue on Baikal 0.9.3.