Opened 7 days ago
Last modified 7 days ago
#66462 new defect (bug)
wp_read_image_metadata() uses a bare EXIF UserComment character code ("ASCII") as the title and caption
| Reported by: | lessbloat | Owned by: | |
|---|---|---|---|
| Priority: | normal | Milestone: | 7.2 |
| Component: | Media | Version: | 6.5 |
| Severity: | normal | Keywords: | has-patch has-unit-tests |
| Cc: | Focuses: |
Description
Some JPEGs carry an EXIF UserComment that holds only part of the character code and nothing else. Uploading one gives the attachment the title "ASCII" and the caption "ASCII". The caption then appears in the image block, for example when uploading from the WordPress/Jetpack mobile apps or the block editor.
We found this with photos exported from Picasa. Their UserComment tag is 5 bytes long:
Tag 0x9286 (5 bytes, undef[5]): 41 53 43 49 49 [ASCII]
The EXIF spec says UserComment starts with an 8-byte character code (ASCII\0\0\0, UNICODE\0, JIS\0\0\0\0\0, or eight null bytes), followed by the comment. This tag has a truncated code and no comment, so it should be treated as empty.
PHP's exif_read_data() strips the character code only when the value is at least 8 bytes long. For this file it returns the raw value:
$exif['COMPUTED']['UserComment'] === 'ASCII'
Before [57267], wp_read_image_metadata() only read UserComment when ImageDescription was also present, so these files produced no title or caption. Since 6.5 the new elseif branch uses UserComment on its own, so the bare code becomes both the caption and, being under 80 characters, the title. When ImageDescription is present, the code ends up as the caption (when the title came from the description) or is appended to it ("My description ASCII").
Steps to reproduce
- Generate a test image with this script (requires GD):
<?php // Writes bare-usercomment.jpg: a JPEG whose EXIF UserComment is the 5 bytes "ASCII". $image = imagecreatetruecolor( 8, 8 ); ob_start(); imagejpeg( $image ); $jpeg = ob_get_clean(); $ifd0 = pack( 'n', 1 ) . pack( 'nnNN', 0x8769, 4, 1, 26 ) . pack( 'N', 0 ); $exif_ifd = pack( 'n', 1 ) . pack( 'nnNN', 0x9286, 7, 5, 44 ) . pack( 'N', 0 ); $exif = "Exif\x00\x00MM\x00\x2a\x00\x00\x00\x08" . $ifd0 . $exif_ifd . 'ASCII'; file_put_contents( 'bare-usercomment.jpg', substr( $jpeg, 0, 2 ) . "\xff\xe1" . pack( 'n', strlen( $exif ) + 2 ) . $exif . substr( $jpeg, 2 ) );
- Upload
bare-usercomment.jpgin Media > Add New, or insert it with an Image block.
Expected: the attachment's title is the file name and the caption is empty.
Actual: the title is "ASCII" and the caption is "ASCII".
You can also check directly:
require_once ABSPATH . 'wp-admin/includes/image.php'; $meta = wp_read_image_metadata( 'bare-usercomment.jpg' ); // $meta['title'] === 'ASCII', $meta['caption'] === 'ASCII'
Proposed fix
In wp_read_image_metadata(), discard a UserComment that is only a character code:
if ( ! empty( $exif['COMPUTED']['UserComment'] ) ) {
$exif_usercomment = trim( $exif['COMPUTED']['UserComment'] );
/*
* PHP returns a UserComment shorter than its 8-byte character code
* as the bare code, such as "ASCII". It holds no comment.
*/
if ( in_array( $exif_usercomment, array( 'ASCII', 'UNICODE', 'JIS' ), true ) ) {
$exif_usercomment = '';
}
}
trim() already removes the null padding, so this also covers codes that are partially padded (for example ASCII\0\0). Valid UserComments are unaffected, because PHP strips the full 8-byte code from them.
Tests would go in tests/phpunit/tests/image/meta.php, with a fixture like the one above in tests/phpunit/data/images/. Cases to cover:
- bare code, no ImageDescription: title and caption are empty;
- bare code with a short ImageDescription: the title and caption are the description;
- bare code with an ImageDescription over 80 characters: the caption is the description, with no " ASCII" suffix;
- a valid
ASCII\0\0\0My comment: the title and caption are "My comment".
Related: [57267].
Attachments (1)
Change History (4)
This ticket was mentioned in PR #15434 on WordPress/wordpress-develop by @sarequl.
7 days ago
#1
- Keywords has-patch has-unit-tests added
#3
@
7 days ago
- Milestone Awaiting Review → 7.2
Can confirm using the example image from the PR.
The PR fixes it and seems good. Moving to next major.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)
Fixes a bare EXIF
UserCommentcharacter code being used as the image title and caption.See https://core.trac.wordpress.org/ticket/66462
What
A JPEG whose EXIF
UserCommentholds only a truncated character code — for example the five bytesASCII— makeswp_read_image_metadata()set both the title and the caption to"ASCII". The same happens when the bare code isUNICODEorJIS.Why
PHP's
exif_read_data()returns aUserCommentshorter than its eight-byte character code as the bare code itself. WordPress then treats that bare code as comment text, so a truncated header produces a meaningless title and caption on the attachment.How
After
trim(), theUserCommentis now discarded when it is exactly one of the character codesASCII,UNICODE, orJIS. A bare code holds no comment, so the metadata falls back toImageDescription(or to nothing). Valid comments, including ones that contain a code word as part of a longer string, are unchanged.Adds four regression tests and four JPEG fixtures covering the bare-code cases with and without a description, plus a valid
UserComment.Testing Instructions
tests/phpunit/data/images/bare-usercomment.jpg(EXIFUserComment=ASCII) to the Media Library. The attachment title and caption are empty, notASCII. On trunk both areASCII.valid-usercomment.jpg(EXIFUserComment=My comment). The title and caption areMy comment.bare-usercomment-short-description.jpg(bareASCIIcode plusImageDescription=My description). The title and caption come from the description.vendor/bin/phpunit tests/phpunit/tests/image/meta.php→OK (18 tests, 96 assertions). Revertingsrc/wp-admin/includes/image.phpto the base commit makes three of the new tests fail.vendor/bin/phpunit tests/phpunit/tests/image/{functions,dimensions,size,alttext,header,meta}.phpall pass.Note
The fix uses the heuristic proposed in the ticket. A *valid*
UserCommentwhose text is exactlyASCII,JIS, orUNICODEis also emptied, because PHP strips the code and the remaining text equals the bare code. This is inherent to the heuristic, and the probability of a real comment consisting solely of one of those words is negligible.