Skip to content

PHP 8.1 fatals when attempting to unserialize empty mysqli_result from PHP 8.0 #10893

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
brandonpayton opened this issue Mar 21, 2023 · 7 comments

Comments

@brandonpayton
Copy link

Description

Given a mysqli connection $mysqli_connection, an empty mysqli_result instance can be created like new mysqli_result( $mysqli_connection ). Such an empty instance is serialized differently between PHP 8.0 and PHP 8.1, and PHP 8.1 fatals when attempting to deserialize the PHP 8.0 representation.

In PHP 8.0, serialize( new mysqli_result( $mysqli_connection ) ) yields the string:

O:13:"mysqli_result":5:{s:13:"current_field";N;s:11:"field_count";N;s:7:"lengths";N;s:8:"num_rows";N;s:4:"type";N;}

The following code in PHP 8.1:

<?php
var_dump(
    unserialize(
        'O:13:"mysqli_result":5:{s:13:"current_field";N;s:11:"field_count";N;s:7:"lengths";N;s:8:"num_rows";N;s:4:"type";N;}'
    )
);

Resulted in this output (tested via WP-CLI's wp shell command):

Fatal error: Uncaught TypeError: Cannot assign null to property mysqli_result::$current_field of type int in phar:///usr/local/bin/wp-cli/vendor/wp-cli/shell-command/src/WP_CLI/Shell/REPL.php(46) : eval()'d code:1

But I expected output like this instead:

object(mysqli_result)#8072 (0) {
}

PHP 8.0 produces output like that above, but PHP 8.1 fatals. This means that PHP 8.1 can fatal when attempting to unserialize data serialized by PHP 8.0.

PHP Version

PHP 8.1.17

Operating System

No response

@damianwadley
Copy link
Member

mysqli_result isn't reliably serializable to begin with.

https://www.php.net/manual/en/function.serialize.php

Note that many built-in PHP objects cannot be serialized. However, those with this ability either implement the Serializable interface or the magic __serialize()/__unserialize() or __sleep()/__wakeup() methods. If an internal class does not fulfill any of those requirements, it cannot reliably be serialized.

And I don't know if it's still the case, but it used to be said that serialized representations are not guaranteed to be compatible between PHP versions.

@Girgias
Copy link
Member

Girgias commented Mar 21, 2023

AFAIK we never provided any guarantee that serialization/unserialization worked across versions.

@brandonpayton
Copy link
Author

mysqli_result isn't reliably serializable to begin with.

mysqli_result does seem like an odd thing to serialize. At Automattic, we ran into this issue due to serialization done by a third party plugin, and WordPress plugins can do all kinds of arbitrary things.

And I don't know if it's still the case, but it used to be said that serialized representations are not guaranteed to be compatible between PHP versions.

AFAIK we never provided any guarantee that serialization/unserialization worked across versions.

For the sake of discussion...

In practice, it seems desirable for serialization/unserialization to work across versions because it reduces the friction and risk with upgrading to new PHP versions.

WordPress, in particular, stores serialized representations of PHP data and unserializes that data all the time. When we switch sites to new major/minor PHP versions on WordPress.com, we do not worry about WordPress breaking due to unserialization fatals.

Perhaps serialization of mysqli_result is an edge case, but if a new PHP version broke unserialization of common PHP data types, it would likely cause major problems for WordPress sites. WordPress is not PHP but is a common PHP user.

Is there a point at which it might make sense to make such a guarantee, at least for certain core types?

@damianwadley
Copy link
Member

Is there a point at which it might make sense to make such a guarantee, at least for certain core types?

The "certain core types" do make the guarantee - more or less - by implementing Serializable or whatever else is required. The ones that don't either (a) should, and it's valid to request it be added, or (b) should not, and they shouldn't be serialized at all. However, there are still some internal serialization representations that are still in play.

And yes, mysqli_result is a weird thing to serialize...

Honestly, for a need to generically serialize data, I'd say that JSON is the way to go: take the data you want and store it in the format you want. That said, developers will still eventually face the same sorts of problems as PHP has: sometimes the serialization format needs to change.

@brandonpayton
Copy link
Author

Thanks for the helpful discussion, @damianwadley! I'll go ahead and close this.

@vikramparth
Copy link

@brandonpayton I'm curious how you worked around this on your side? I'm seeing the same issue as well when using WP CLI with PHP 8.2.

@brandonpayton
Copy link
Author

brandonpayton commented May 13, 2025

@brandonpayton I'm curious how you worked around this on your side? I'm seeing the same issue as well when using WP CLI with PHP 8.2.

@vikramparth, this response is quite late, but in our case, we just deleted the WordPress options with the problematic values (they were no longer relevant anyway) and re-ran our processing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants