Skip to content
Closed
13 changes: 9 additions & 4 deletions src/wp-includes/fonts/class-wp-font-utils.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
*
Expand All @@ -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',
);
Expand Down
13 changes: 13 additions & 0 deletions src/wp-includes/functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -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 ) {
/*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?php
/**
* Test WP_Font_Utils::get_allowed_font_mime_types().
*
* @package WordPress
* @subpackage Font Library
*
* @group fonts
* @group font-library
*
* @covers WP_Font_Utils::get_allowed_font_mime_types
*/
class Tests_Fonts_WpFontUtils_GetAllowedFontMimeTypes extends WP_UnitTestCase {
/**
* @ticket 66419
*
* @requires extension fileinfo
*
* @dataProvider data_font_file_extensions
*
* @param string $extension Font file extension.
*/
public function test_should_match_the_mime_type_detected_for_a_font_file( $extension ) {
if ( 'ttf' === $extension && 'application/octet-stream' === finfo_file( finfo_open( FILEINFO_MIME_TYPE ), DIR_TESTDATA . '/fonts/OpenSans-Regular.ttf' ) ) {
$this->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();
Comment thread
desrosj marked this conversation as resolved.
Resolved
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' ) );
}
Comment thread
desrosj marked this conversation as resolved.
Resolved

/**
* 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' ),
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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 );
Expand All @@ -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.' );
}

/**
Expand Down
85 changes: 85 additions & 0 deletions tests/phpunit/tests/functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
*
Expand Down
Loading