@@ -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