diff --git a/src/wp-includes/fonts/class-wp-font-utils.php b/src/wp-includes/fonts/class-wp-font-utils.php index ee175f66aab6d..57385ff8084ed 100644 --- a/src/wp-includes/fonts/class-wp-font-utils.php +++ b/src/wp-includes/fonts/class-wp-font-utils.php @@ -236,11 +236,16 @@ private static function apply_sanitizer( $value, $sanitizer ) { /** * Returns the expected mime-type values for font files, depending on PHP version. * - * This is needed because font mime types vary by PHP version, so checking the PHP version - * is necessary until a list of valid mime-types for each file extension can be provided to - * the 'upload_mimes' filter. + * This is needed because the mime types detected for WOFF and WOFF2 files vary by PHP version, + * so checking the PHP version is necessary until a list of valid mime-types for each file + * extension can be provided to the 'upload_mimes' filter. + * + * TrueType fonts can be detected as either font/ttf or font/sfnt depending on the libmagic + * version, and both are accepted by wp_check_filetype_and_ext(). The canonical font/ttf + * is returned for them on all PHP versions. * * @since 6.5.0 + * @since 7.2.0 TrueType fonts now use the font/ttf mime type on all PHP versions. * * @access private * @@ -249,7 +254,7 @@ private static function apply_sanitizer( $value, $sanitizer ) { public static function get_allowed_font_mime_types() { return array( 'otf' => 'application/vnd.ms-opentype', - 'ttf' => 'font/sfnt', + 'ttf' => 'font/ttf', 'woff' => PHP_VERSION_ID >= 80112 ? 'font/woff' : 'application/font-woff', 'woff2' => PHP_VERSION_ID >= 80112 ? 'font/woff2' : 'application/font-woff2', ); diff --git a/src/wp-includes/functions.php b/src/wp-includes/functions.php index eac938b2c4d1a..f31c53aa7dd4f 100644 --- a/src/wp-includes/functions.php +++ b/src/wp-includes/functions.php @@ -3357,6 +3357,19 @@ function wp_check_filetype_and_ext( $file, $filename, $mimes = null ) { $type = false; $ext = false; } + } elseif ( in_array( $real_mime, array( 'font/ttf', 'font/sfnt' ), true ) ) { + /* + * libmagic 5.47 changed the type reported for TrueType fonts from font/sfnt to the + * canonical font/ttf. PHP 8.6 bundles a libmagic version with this change, but PHP + * builds that use the system libmagic can report either type, so both are accepted + * for TrueType fonts. + * + * @link https://github.com/file/file/commit/6481672a8eb64c2758bf6429d9a76ee5a22174e9 + */ + if ( ! in_array( $type, array( 'font/ttf', 'font/sfnt' ), true ) ) { + $type = false; + $ext = false; + } } else { if ( $type !== $real_mime ) { /* diff --git a/tests/phpunit/tests/fonts/font-library/wpFontUtils/getAllowedFontMimeTypes.php b/tests/phpunit/tests/fonts/font-library/wpFontUtils/getAllowedFontMimeTypes.php new file mode 100644 index 0000000000000..80c2de8a4e176 --- /dev/null +++ b/tests/phpunit/tests/fonts/font-library/wpFontUtils/getAllowedFontMimeTypes.php @@ -0,0 +1,52 @@ +markTestSkipped( 'This libmagic version cannot detect TrueType fonts. See https://github.com/php/php-src/issues/25051.' ); + } + + $mimes = WP_Font_Utils::get_allowed_font_mime_types(); + add_filter( 'upload_mimes', array( 'WP_Font_Utils', 'get_allowed_font_mime_types' ) ); + + $filetype = wp_check_filetype_and_ext( DIR_TESTDATA . '/fonts/OpenSans-Regular.' . $extension, 'OpenSans-Regular.' . $extension, $mimes ); + + $this->assertSame( $extension, $filetype['ext'], 'The font file extension should be accepted.' ); + $this->assertSame( $mimes[ $extension ], $filetype['type'], 'The font file mime type should match the allowed mime type.' ); + + remove_filter( 'upload_mimes', array( 'WP_Font_Utils', 'get_allowed_font_mime_types' ) ); + } + + /** + * Data provider. + * + * @return array[] + */ + public static function data_font_file_extensions() { + return array( + 'otf' => array( 'otf' ), + 'ttf' => array( 'ttf' ), + 'woff' => array( 'woff' ), + 'woff2' => array( 'woff2' ), + ); + } +} diff --git a/tests/phpunit/tests/fonts/font-library/wpRestFontFacesController.php b/tests/phpunit/tests/fonts/font-library/wpRestFontFacesController.php index 05af011f5cf0a..2a2026ccf2458 100644 --- a/tests/phpunit/tests/fonts/font-library/wpRestFontFacesController.php +++ b/tests/phpunit/tests/fonts/font-library/wpRestFontFacesController.php @@ -463,7 +463,20 @@ function ( $font_dir ) { */ public function test_create_item_with_multiple_font_files() { wp_set_current_user( self::$admin_id ); - $files = $this->setup_font_file_upload( array( 'ttf', 'otf', 'woff', 'woff2' ) ); + + $formats = array( 'ttf', 'otf', 'woff', 'woff2' ); + + /* + * Some libmagic versions cannot detect TrueType fonts and report them as + * application/octet-stream, which causes the upload to be rejected. + * + * @link https://github.com/php/php-src/issues/25051 + */ + if ( 'application/octet-stream' === finfo_file( finfo_open( FILEINFO_MIME_TYPE ), DIR_TESTDATA . '/fonts/OpenSans-Regular.ttf' ) ) { + $formats = array_diff( $formats, array( 'ttf' ) ); + } + + $files = $this->setup_font_file_upload( $formats ); $request = new WP_REST_Request( 'POST', '/wp/v2/font-families/' . self::$font_family_id . '/font-faces' ); $request->set_param( 'theme_json_version', WP_REST_Font_Faces_Controller::LATEST_THEME_JSON_VERSION_SUPPORTED ); @@ -488,7 +501,7 @@ public function test_create_item_with_multiple_font_files() { $this->check_file_meta( $data['id'], $data['font_face_settings']['src'] ); $settings = $data['font_face_settings']; - $this->assertCount( 4, $settings['src'], 'There should be 4 items in the font_face_settings::src data.' ); + $this->assertCount( count( $files ), $settings['src'], 'There should be one item in the font_face_settings::src data for each uploaded file.' ); } /** diff --git a/tests/phpunit/tests/functions.php b/tests/phpunit/tests/functions.php index 64d84458c334f..8ba133e930ad0 100644 --- a/tests/phpunit/tests/functions.php +++ b/tests/phpunit/tests/functions.php @@ -1861,6 +1861,91 @@ static function ( $mimes ) use ( $woff_mime_type ) { $this->assertSame( $expected, wp_check_filetype_and_ext( $file, $filename ) ); } + /** + * Tests that TrueType fonts are accepted whether font/ttf or font/sfnt is expected. + * + * libmagic 5.47 changed the type reported for TrueType fonts from font/sfnt to font/ttf. + * Expecting each type in turn ensures that whichever one libmagic reports, a file is also + * accepted when the other is expected. + * + * @ticket 66419 + * @group ms-excluded + * @requires extension fileinfo + * + * @dataProvider data_wp_check_filetype_and_ext_with_ttf_mime_types + * + * @covers ::wp_check_filetype_and_ext + * + * @param string $mime_type The mime type expected for TTF files. + */ + public function test_wp_check_filetype_and_ext_accepts_either_ttf_mime_type( $mime_type ) { + $file = DIR_TESTDATA . '/fonts/OpenSans-Regular.ttf'; + $filename = 'OpenSans-Regular.ttf'; + + $detected_type = finfo_file( finfo_open( FILEINFO_MIME_TYPE ), $file ); + if ( ! in_array( $detected_type, array( 'font/ttf', 'font/sfnt' ), true ) ) { + $this->markTestSkipped( "This version of libmagic detects TrueType fonts as {$detected_type}." ); + } + + $filter = static function ( $mimes ) use ( $mime_type ) { + $mimes['ttf'] = $mime_type; + return $mimes; + }; + add_filter( 'upload_mimes', $filter ); + + $expected = array( + 'ext' => 'ttf', + 'type' => $mime_type, + 'proper_filename' => false, + ); + + $this->assertSame( $expected, wp_check_filetype_and_ext( $file, $filename ) ); + + remove_filter( 'upload_mimes', $filter ); + } + + /** + * Data provider. + * + * @return array[] + */ + public static function data_wp_check_filetype_and_ext_with_ttf_mime_types() { + return array( + 'font/ttf' => array( 'font/ttf' ), + 'font/sfnt' => array( 'font/sfnt' ), + ); + } + + /** + * Tests that a font file of another format is rejected when named with a .ttf extension. + * + * @ticket 66419 + * @group ms-excluded + * @requires extension fileinfo + * + * @covers ::wp_check_filetype_and_ext + */ + public function test_wp_check_filetype_and_ext_rejects_other_font_formats_as_ttf() { + $file = DIR_TESTDATA . '/fonts/OpenSans-Regular.woff'; + $filename = 'OpenSans-Regular.ttf'; + + $filter = static function ( $mimes ) { + $mimes['ttf'] = 'font/ttf'; + return $mimes; + }; + add_filter( 'upload_mimes', $filter ); + + $expected = array( + 'ext' => false, + 'type' => false, + 'proper_filename' => false, + ); + + $this->assertSame( $expected, wp_check_filetype_and_ext( $file, $filename ) ); + + remove_filter( 'upload_mimes', $filter ); + } + /** * Test file path validation *