Opened 3 years ago
Last modified 2 months ago
#59588 new defect (bug)
False returned instead of default value on get_option with failure of unserializing data.
| Reported by: |
|
Owned by: | |
|---|---|---|---|
| Milestone: | Awaiting Review | Priority: | normal |
| Severity: | normal | Version: | 6.3.2 |
| Component: | Widgets | Keywords: | has-patch has-unit-tests |
| Focuses: | Cc: |
Description
Hello, I noticed a bug with the ability to load the customize screen of any theme if there is a malformed option value set.
I noticed from wp-includes/class-wp-customize-widgets.php
<?php customize_register();
this performs an array_merge which throws an error with the 3rd argument being returned is not an array and instead false
in wp-includes/widgets.php
<?php wp_get_sidebars_widgets();
This calls
<?php $sidebars_widgets = get_option( 'sidebars_widgets', array() );
I found that the end of the function in the apply_filters (line 255) is calling maybe_unserialize in the call. The issue with this is if the option value is malformed and the serializing returns False. That gets passed back to when it is trying to merge the arrays. I added some code as a test and it worked after I changed to the following
<?php $data = maybe_unserialize($value); if (!$data && $default_value !== false && gettype($data) !== gettype($default_value)) $data = $default_value; return apply_filters( "option_{$option}", $data, $option ); }
The idea I tried to solve for is if a default value has been passed in but the value we are about to return is not what the receiving function is expecting then it should try to make sure it is at least passing back the expected type of the default value.
Attachments (1)
Change History (3)
This ticket was mentioned in PR #11500 on WordPress/wordpress-develop by @kalpeshh.
2 months ago
#1
- Keywords has-patch has-unit-tests added; needs-patch removed
## Problem
When an option exists in the DB with corrupted/truncated serialized data,
@unserialize()returnsfalse, whichget_option()passes back to the
caller instead of the provided$default_value.
## Solution
After calling
maybe_unserialize(), detect a failed unserialization:
stored value is serialized + result isfalse+ value is notb:0;
(the valid serialization of booleanfalse). In that case, fall back to
$default_valuevia thedefault_option_{$option}filter.
## Tests
Two new cases in
tests/phpunit/tests/option/option.php:
- Corrupted serialized data → default value is returned.
b:0;stored value →falseis correctly returned, not the default.
#2
@
2 months ago
I've created a patch for this issue.
The fix saves the raw DB value before calling maybe_unserialize(), then checks if unserialization failed (result is false, value was serialized, and value is not b:0; — the valid serialization of boolean false). In that case, $default_value is returned instead.
Two tests are included: one for corrupted serialized data returning the default, and one confirming a legitimately stored false still returns false.
PR: https://github.com/WordPress/wordpress-develop/pull/11500
option.php file with my code changes for example