Skip to content

Commit 4b83198

Browse files
authored
Merge branch 'WordPress:trunk' into trunk
2 parents cf5cbec + 128db3c commit 4b83198

2 files changed

Lines changed: 112 additions & 3 deletions

File tree

src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1707,7 +1707,7 @@ public function get_item_schema() {
17071707

17081708
$schema['properties']['filesize'] = array(
17091709
'description' => __( 'Attachment file size in bytes.' ),
1710-
'type' => 'integer',
1710+
'type' => array( 'integer', 'null' ),
17111711
'context' => array( 'view', 'edit' ),
17121712
'readonly' => true,
17131713
);
@@ -2359,12 +2359,13 @@ protected function get_attachment_filename( int $attachment_id ): ?string {
23592359
*
23602360
* @param int $attachment_id Attachment ID.
23612361
* @return int|null Attachment file size in bytes, or null if not available.
2362+
* @phpstan-return non-negative-int|null
23622363
*/
23632364
protected function get_attachment_filesize( int $attachment_id ): ?int {
23642365
$meta = wp_get_attachment_metadata( $attachment_id );
23652366

2366-
if ( isset( $meta['filesize'] ) ) {
2367-
return $meta['filesize'];
2367+
if ( isset( $meta['filesize'] ) && is_numeric( $meta['filesize'] ) && $meta['filesize'] > 0 ) {
2368+
return (int) $meta['filesize'];
23682369
}
23692370

23702371
$original_path = wp_get_original_image_path( $attachment_id );

tests/phpunit/tests/rest-api/rest-attachments-controller.php

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1005,6 +1005,114 @@ public function test_get_item() {
10051005
$this->assertSame( 'image/jpeg', $data['mime_type'] );
10061006
}
10071007

1008+
/**
1009+
* Ensures int-castable `filesize` values in attachment metadata are normalized
1010+
* to an integer in the response.
1011+
*
1012+
* Attachment metadata is untyped, so plugins that populate `filesize` from
1013+
* a remote storage API may store it as a string.
1014+
*
1015+
* @ticket 65670
1016+
*
1017+
* @dataProvider data_valid_filesize_meta
1018+
*
1019+
* @param mixed $stored_filesize Valid `filesize` metadata value.
1020+
* @param int $expected_filesize Expected `filesize` value in the REST response after normalization.
1021+
*/
1022+
public function test_get_item_normalizes_int_castable_filesize_meta( $stored_filesize, int $expected_filesize ) {
1023+
$attachment_id = self::factory()->attachment->create_object(
1024+
array(
1025+
'file' => self::$test_file,
1026+
'post_mime_type' => 'image/jpeg',
1027+
)
1028+
);
1029+
$this->assertIsInt( $attachment_id );
1030+
1031+
$meta = wp_get_attachment_metadata( $attachment_id );
1032+
$meta = is_array( $meta ) ? $meta : array();
1033+
$meta['filesize'] = $stored_filesize;
1034+
$this->assertNotFalse( wp_update_attachment_metadata( $attachment_id, $meta ) );
1035+
1036+
$request = new WP_REST_Request( 'GET', '/wp/v2/media/' . $attachment_id );
1037+
$response = rest_get_server()->dispatch( $request );
1038+
$data = $response->get_data();
1039+
1040+
$this->assertIsArray( $data );
1041+
$this->assertSame( 200, $response->get_status() );
1042+
$this->assertSame( $expected_filesize, $data['filesize'] );
1043+
}
1044+
1045+
/**
1046+
* Data provider.
1047+
*
1048+
* @return array<string, array{ 0: mixed, 1: int }>
1049+
*/
1050+
public function data_valid_filesize_meta(): array {
1051+
return array(
1052+
'integer string' => array( '123456', 123456 ),
1053+
'float string' => array( '123.4', 123 ),
1054+
'scientific notation' => array( '1e3', 1000 ),
1055+
'float' => array( 123.0, 123 ),
1056+
);
1057+
}
1058+
1059+
/**
1060+
* Ensures a `filesize` metadata value that is not a positive number does not
1061+
* cause a fatal TypeError or a bogus size cast from a non-numeric value,
1062+
* falling back to the actual file size instead.
1063+
*
1064+
* Numeric values are trusted and cast to an integer instead, per
1065+
* {@see self::test_get_item_normalizes_int_castable_filesize_meta()}.
1066+
*
1067+
* @ticket 65670
1068+
*
1069+
* @dataProvider data_invalid_filesize_meta
1070+
*
1071+
* @param mixed $filesize Invalid `filesize` metadata value.
1072+
*/
1073+
public function test_get_item_recovers_from_invalid_filesize_meta( $filesize ) {
1074+
$attachment_id = self::factory()->attachment->create_object(
1075+
array(
1076+
'file' => self::$test_file,
1077+
'post_mime_type' => 'image/jpeg',
1078+
)
1079+
);
1080+
$this->assertIsInt( $attachment_id );
1081+
1082+
$meta = wp_get_attachment_metadata( $attachment_id );
1083+
$meta = is_array( $meta ) ? $meta : array();
1084+
$meta['filesize'] = $filesize;
1085+
$this->assertNotFalse( wp_update_attachment_metadata( $attachment_id, $meta ) );
1086+
1087+
$request = new WP_REST_Request( 'GET', '/wp/v2/media/' . $attachment_id );
1088+
$response = rest_get_server()->dispatch( $request );
1089+
$data = $response->get_data();
1090+
1091+
$this->assertIsArray( $data );
1092+
$this->assertSame( 200, $response->get_status() );
1093+
$this->assertIsInt( $data['filesize'] );
1094+
$attached_file = wp_get_original_image_path( $attachment_id );
1095+
$attached_file = $attached_file ? $attached_file : get_attached_file( $attachment_id );
1096+
$this->assertIsString( $attached_file );
1097+
$this->assertSame( filesize( $attached_file ), $data['filesize'] );
1098+
}
1099+
1100+
/**
1101+
* Data provider.
1102+
*
1103+
* @return array<string, array{ 0: mixed }>
1104+
*/
1105+
public function data_invalid_filesize_meta(): array {
1106+
return array(
1107+
'non-numeric string' => array( 'corrupt' ),
1108+
'boolean' => array( true ),
1109+
'zero' => array( 0 ),
1110+
'zero string' => array( '0' ),
1111+
'negative integer' => array( -5 ),
1112+
'negative integer string' => array( '-5' ),
1113+
);
1114+
}
1115+
10081116
/**
10091117
* @requires function imagejpeg
10101118
*/

0 commit comments

Comments
 (0)