Media: Guard the image size lookup in image_constrain_size_for_editor() - #13032
Media: Guard the image size lookup in image_constrain_size_for_editor()#13032mukeshpanchal27 wants to merge 1 commit into
image_constrain_size_for_editor()#13032Conversation
…r()`. [63177] replaced `in_array( $size, array_keys( $_wp_additional_image_sizes ), true )` with `isset( $_wp_additional_image_sizes[ $size ] )`. The two are not equivalent when `$size` is not a valid array key type: `in_array()` accepts any value and returns `false`, while using the same value as an array offset emits a diagnostic. On PHP 8.5, a `null` size now emits "Using null as an array offset is deprecated", a float emits an implicit conversion notice, and an object throws a `TypeError`. All three were silent before [63177]. `$size` reaches this line unfiltered from public API, via `wp_get_attachment_image_url()`, `wp_get_attachment_image_src()` and `image_downsize()`. Only `is_array()` is handled earlier in the function. This checks that `$size` is a valid array key type before performing the lookup, which restores the previous behaviour while keeping the constant-time lookup. Follow-up to [63177]. See #65842. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the Core Committers: Use this line as a base for the props when committing in SVN: To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
Test using WordPress PlaygroundThe changes in this pull request can previewed and tested using a WordPress Playground instance. WordPress Playground is an experimental project that creates a full WordPress instance entirely within the browser. Some things to be aware of
For more details about these limitations and more, check out the Limitations page in the WordPress Playground documentation. |
What?
[63177] replaced
in_array( $size, array_keys( $_wp_additional_image_sizes ), true )withisset( $_wp_additional_image_sizes[ $size ] )inimage_constrain_size_for_editor().The two forms are not equivalent when
$sizeis not a valid array key type. This PR guards the lookup so that such values fall through to the unconstrained branch, as they did before [63177].Why?
in_array( ..., true )accepts any value and simply returnsfalsefor one that could never be an array key. Using that same value as an array offset does not:$sizenullfalseDeprecated: Using null as an array offset is deprecated, use an empty string instead(PHP 8.5)1.5falseDeprecated: Implicit conversion from float 1.5 to int loses precisionnew stdClassfalseTypeError: Cannot access offset of type stdClass in isset or emptyfalseWarning: Resource ID#n used as offset, casting to integerThe
isset()behaviour is confirmed by PHP's own test,Zend/tests/isset/isset_array.phpt. Thenullcase is the PHP 8.5 deprecation of null as an array offset, which WordPress now runs in CI.$sizereaches this line unfiltered from public API:Only
is_array()is handled earlier, at the top of the function.Passing
nullas an image size is invalid per the documentedstring|int[]type, but it is common in the wild — typicallywp_get_attachment_image_src( $id, $atts['size'] ?? null )and similar — and it was silently harmless before [63177].It was caught by the Gutenberg plugin's PHP 8.5 CI running against Core trunk, where the Cover block passed
$attributes['sizeSlug'] ?? null:That call site is now fixed in Gutenberg (WordPress/gutenberg#81444), but that fixes one caller. The behaviour change in Core affects all of them. Core's bundled copy in
src/wp-includes/blocks/cover.phpstill passesnulland will pick the fix up on the next Gutenberg package sync.Why this guard?
stringandintare exactly the two types PHP accepts as array keys, so the guard expresses the precondition theisset()lookup actually has: is this value usable as an offset at all? Both checks are constant-time, so the improvement from [63177] is preserved.is_string()alone would cover every realistic case, sinceadd_image_size()documents$nameasstring. But a size registered with a purely numeric name gets its array key cast toint, and the pre-[63177]in_array( ..., true )did match anintargument against it, so includingis_int()avoids quietly narrowing that.No lower bound is applied to the
intcase. Negative integers are valid array keys and produce no diagnostic on PHP 8.5 — verified on 8.5.9:So a
$size >= 0condition would add nothing for PHP 8.5 safety while excluding a size registered asadd_image_size( '-5' ), whose key PHP casts toint -5.There is precedent for guarding in the same file:
image_get_intermediate_size()already hasif ( ! $size || ... ) { return false; }, which is the only reason the equivalent! empty( $imagedata['sizes'][ $size ] )lookup further down has never hit this.Testing Instructions
Two tests are added to
tests/phpunit/tests/image/size.php:test_constrain_size_for_editor_additional_image_size()— a registered additional image size still constrains the dimensions, so the guard does not over-restrict.test_constrain_size_for_editor_invalid_size()— a data provider coveringnull,false,'',0,1.5, and an object; each must return the unconstrained dimensions.Verified on PHP 8.5.9. Reverting only the
media.phpchange and re-running gives three errors, all pointing at the changed line:With the patch applied, on PHP 8.5.9:
--filter Tests_Image_Size— 20 tests, 54 assertions, OK--group media— 862 tests, 2415 assertions, OK (7 skipped)--group image— 284 tests, 680 assertions, OK (6 skipped)Note for reviewers
The other six changes in [63177] were reviewed against the same criterion and are safe:
class-theme-installer-skin.php— guarded by! empty()dashboard.php,link-template.php—intblog IDs againstintarray keysnav-menus.php— explicit(int)castssitemaps.php— guarded truthyblock-editor.phpis the only other one worth a second look:$default_sizecomes fromget_option( 'image_default_size' ), so a corrupt non-scalar option value would now fatal rather than fall back to'large'. That seems too unlikely to be worth changing, but it is the same class of issue, so flagging it here rather than folding it into this PR.The general rule for this pattern: swapping
in_array( $key, array_keys( $array ), true )forisset( $array[ $key ] )is only safe when$keyis guaranteed to be a valid array key type.Trac ticket: https://core.trac.wordpress.org/ticket/65842
Use of AI Tools
AI assistance: Yes
Tool(s): Claude Code
Model(s): Claude Opus 5
Used for: Investigating the root cause of the Gutenberg CI failure, drafting the patch and the unit tests, drafting this description, and running the test suites quoted above on PHP 8.5.9. The guard condition was changed at my direction. I have reviewed the change and take responsibility for it.
This Pull Request is for code review only. Please keep all other discussion in the Trac ticket. Do not merge this Pull Request. See GitHub Pull Requests for Code Review in the Core Handbook for more details.