Make WordPress Core

Opened 2 years ago

Last modified 4 hours ago

#60480 reviewing defect (bug)

preg_match() warning in wp_image_add_srcset_and_sizes() when image_meta['file'] is missing

Reported by: shanemac10's profile shanemac10 Owned by: westonruter's profile westonruter
Milestone: 7.0 Priority: normal
Severity: major Version: 4.4
Component: Import Keywords: has-patch
Focuses: performance Cc:

Description

When running Tools > Import > Run Importer, then selecting "Download and import file attachments" on the import options, the media (what appears to be a native Featured Image in my case) does not import, and displays this following message for each failed media import:

Warning: Undefined array key "file" in .../wp-includes/media.php on line 1723

When looking into the matter, it appears in wp_img_tag_add_srcset_and_sizes_attr on line 2154 and 2155 where wp_get_attachment_metadata is called, which may return false, then it's sent directly into wp_image_add_srcset_and_sizes, where it (on 1723) tests a preg_match on it without testing if $image_meta is an array or if key_exists, etc.

2154  $image_meta = wp_get_attachment_metadata( $attachment_id ); // <--- returns array|false
2155  return wp_image_add_srcset_and_sizes( $image, $image_meta, $attachment_id );
1723  if ( preg_match( '/-e[0-9]{13}/', $image_meta['file'], $img_edit_hash ) // <--- $image_meta may be false

Get blame says this code has been around for over 4 years.
https://github.com/WordPress/wordpress-develop/blame/6.4/src/wp-includes/media.php#L2138-L2159

My scenario is importing a custom post type (that is identical to generic post type) with only WYSIWYG content and a featured image, to a local dev site on my personal computer from a public site (w/ full DNS with SSL cert), so there should not be an issue with fetching the images I believe. Either way, this error is a bug, and needs a way to fail more gracefully if the issue is else where in the Import process.

Change History (14)

#1 @shanemac10
2 years ago

As an additional note: I made the following change to the code, and re-ran the import. The images did not import, and there were no errors printed either.

Added...

($image_meta['file'] ?? false) &&

Like so...

1723. if (($image_meta['file'] ?? false) && preg_match( '/-e[0-9]{13}/', $image_meta['file'], $img_edit_hash )

#2 @MadtownLems
16 months ago

I had similar errors logged, and I traced it down to when sites were using Images that were generated by uploaded PDFs. The metadata for those pdf thumbnails does not seem to contain the base 'file' attribute.

What I can't actually figure out is how our users even got the URLs to use those images on the front-end! 😅 .

This ticket was mentioned in PR #7691 on WordPress/wordpress-develop by @debarghyabanerjee.


15 months ago
#3

  • Keywords has-patch added

Trac Ticket: Core-60480

## Description

  • This pull request addresses a warning encountered during the media import process when using the "Download and import file attachments" option in the Tools > Import section of WordPress. A warning is triggered due to an attempt to access an undefined array key in the wp_image_add_srcset_and_sizes function.

## Proposed Changes

  • Added an isset() check before accessing the 'file' key of the $image_meta array to prevent the warning from occurring.
  • This adjustment ensures that the code handles cases where media metadata retrieval fails more gracefully, avoiding the warning message.
  • Additionally, this change is aimed at bringing consistency across all functions that interact with attachment metadata, ensuring that similar checks are uniformly applied throughout the codebase.

#4 @sabernhardt
8 months ago

#63394 was marked as a duplicate.

#5 follow-up: @sabernhardt
8 months ago

  • Summary changed from Warning: Undefined array key "file" in .../wp-includes/media.php on line 1723 to preg_match() warning in wp_image_add_srcset_and_sizes() when image_meta['file'] is missing

If the wp_image_add_srcset_and_sizes() checks for the 'file' array key, I think it could check at the same time as the 'sizes' array key. (Note: I have not tested this.)

Either

	// Ensure the image meta exists.
	if ( empty( $image_meta['sizes'] ) || empty( $image_meta['file'] ) ) {
		return $image;
	}

or

	// Ensure the image meta exists.
	if ( empty( $image_meta['sizes'] ) || ! isset( $image_meta['file'] ) ) {
		return $image;
	}

I copied @enravo's summary from #63394. Additional tickets that mention similar 'file' key messages include #48710, #55872, and #58535 (not necessarily using the same function).

#6 @enravo
8 months ago

Although this ticket (#60480) predates my report (#63394), I would like to note that my ticket provided the actual root-cause analysis and a concrete fix proposal.

Here is my original report: https://core.trac.wordpress.org/ticket/63394
And PR based on my analysis: https://github.com/Enravo/wordpress-develop/pull/1

I would greatly appreciate it if this contribution could be acknowledged in the props for [PR 8772](https://github.com/WordPress/wordpress-develop/pull/8772).
My patch directly addressed the warning caused by undefined array key "file" and deprecated preg_match() behavior, which is the same issue fixed in my PR.

GitHub: @Enravo

#7 @leedxw
6 months ago

This is just a note that may be of assistance to anyone investigating this.

We've started seeing this error on some sites (that have been running for many years).

The error comes from looking up PDFs... even though the PDFs aren't in <img> tags on the page.

On investigating I found instances of the page content looking like:

<figure class="wp-block-image alignleft is-resized">
<img src="https://www.example.com/wp-content/uploads/2019/09/logo.jpg" 
  alt=""
  class="wp-image-888"
  style="width:69px;height:104px"/>
</figure>

But attachment ID 888 is not the ID of the referenced image, but is the attachment ID of an unrelated PDF.

I don't know the cause of this mismatch, it could have happened at any time in the last 15 years, but it's why we've started seeing warnings from wp_image_add_srcset_and_sizes().

#8 @leedxw
5 months ago

Is there any movement on this ticket?

We've got plenty of examples where the preview image for a PDF has been added to a public page and class="wp-image- appears? Is this a bug?

Is it a bug that uploaded pdfs don't have a file property?

#9 @sabernhardt
11 hours ago

#64499 was marked as a duplicate.

#10 @sabernhardt
11 hours ago

On #64499, @djsuperfive reported the 'Undefined array key "file"' error with a WEBP image (using the Performance Lab plugin).

#11 @westonruter
11 hours ago

  • Focuses performance added
  • Milestone changed from Awaiting Review to 7.0

Tagging with performance since issue relates to Performance Lab, I'm assuming with the Modern Images Formats plugin.

#12 @djsuperfive
10 hours ago

Temporary patch to avoid fatal errors:

add_filter('wp_get_attachment_metadata',  function ($image_meta, $attachment_id) {
  if (!is_array($image_meta) || !isset($image_meta['file'])) {
    return false;
  }
  return $image_meta;
}, 10, 2);

This ticket was mentioned in Slack in #core-performance by westonruter. View the logs.


10 hours ago

#14 in reply to: ↑ 5 @westonruter
4 hours ago

  • Owner set to westonruter
  • Status changed from assigned to reviewing
  • Version changed from 6.4.3 to 4.4

Replying to sabernhardt:

If the wp_image_add_srcset_and_sizes() checks for the 'file' array key, I think it could check at the same time as the 'sizes' array key. (Note: I have not tested this.)

I'm not sure that's going to be equivalent. There is still logic that the function is supposed to do if $image_meta['file'] is not set. It's just supposed to use that file get to “Bail early if an image has been inserted and later edited.”

The code in question was introduced in [35412] for #34430. Cc @joemcgill in case he has anything to add.

Otherwise, the patch looks right to me. I don't see any test coverage for wp_image_add_srcset_and_sizes(). That would be nice to add, but this seems like a straightforward change. It just prevents passing null to preg_match() with the pattern /-e[0-9]{13}/. In versions of PHP prior to 8.1, the null would silently be treated the same as an empty string: https://3v4l.org/oY5nou#veol

Note: See TracTickets for help on using tickets.