WordPress.org

Make WordPress Core

Changeset 40134


Ignore:
Timestamp:
02/27/17 19:27:58 (3 months ago)
Author:
joemcgill
Message:

Media: Reduce failing uploads following 4.7.1.

[39831] introduced more strict MIME type checking for uploads, which
resulted in unintetionally blocking several filetypes that were
previously valid. This change uses a more targeted approach to MIME
validation to restore previous behavior for most types.

Props blobfolio, iandunn, ipstenu, markoheijnen, xknown, joemcgill.
Merges [40124] and [40125] to the 4.7 branch.
Fixes #39550, #39552.

Location:
branches/4.7
Files:
3 edited
1 copied

Legend:

Unmodified
Added
Removed
  • branches/4.7

  • branches/4.7/src/wp-includes/functions.php

    r40085 r40134  
    22692269    } 
    22702270 
     2271    $real_mime = false; 
     2272 
    22712273    // Validate image types. 
    22722274    if ( $type && 0 === strpos( $type, 'image/' ) ) { 
     
    22752277        $real_mime = wp_get_image_mime( $file ); 
    22762278 
    2277         if ( ! $real_mime ) { 
    2278             $type = $ext = false; 
    2279         } elseif ( $real_mime != $type ) { 
     2279        if ( $real_mime && $real_mime != $type ) { 
    22802280            /** 
    22812281             * Filters the list mapping image mime types to their respective extensions. 
     
    23082308                $type = $wp_filetype['type']; 
    23092309            } else { 
    2310                 $type = $ext = false; 
     2310                // Reset $real_mime and try validating again. 
     2311                $real_mime = false; 
    23112312            } 
    23122313        } 
    2313     } elseif ( function_exists( 'finfo_file' ) ) { 
    2314         // Use finfo_file if available to validate non-image files. 
     2314    } 
     2315 
     2316    // Validate files that didn't get validated during previous checks. 
     2317    if ( $type && ! $real_mime && extension_loaded( 'fileinfo' ) ) { 
    23152318        $finfo = finfo_open( FILEINFO_MIME_TYPE ); 
    23162319        $real_mime = finfo_file( $finfo, $file ); 
    23172320        finfo_close( $finfo ); 
    23182321 
    2319         // If the extension does not match the file's real type, return false. 
    2320         if ( $real_mime !== $type ) { 
    2321             $type = $ext = false; 
     2322        /* 
     2323         * If $real_mime doesn't match what we're expecting, we need to do some extra 
     2324         * vetting of application mime types to make sure this type of file is allowed. 
     2325         * Other mime types are assumed to be safe, but should be considered unverified. 
     2326         */ 
     2327        if ( $real_mime && ( $real_mime !== $type ) && ( 0 === strpos( $real_mime, 'application' ) ) ) { 
     2328            $allowed = get_allowed_mime_types(); 
     2329 
     2330            if ( ! in_array( $real_mime, $allowed ) ) { 
     2331                $type = $ext = false; 
     2332            } 
    23222333        } 
    23232334    } 
  • branches/4.7/tests/phpunit/tests/functions.php

    r38810 r40134  
    899899        $this->assertEquals( $uuids, $unique_uuids ); 
    900900    } 
     901 
     902    /** 
     903     * @ticket 39550 
     904     * @dataProvider _wp_check_filetype_and_ext_data 
     905     */ 
     906    function test_wp_check_filetype_and_ext( $file, $filename, $expected ) { 
     907        if ( ! extension_loaded( 'fileinfo' ) ) { 
     908            $this->markTestSkipped( 'The fileinfo PHP extension is not loaded.' ); 
     909        } 
     910 
     911        $this->assertEquals( $expected, wp_check_filetype_and_ext( $file, $filename ) ); 
     912    } 
     913 
     914    /** 
     915     * @ticket 39550 
     916     */ 
     917    function test_wp_check_filetype_and_ext_with_filtered_svg() { 
     918        if ( ! extension_loaded( 'fileinfo' ) ) { 
     919            $this->markTestSkipped( 'The fileinfo PHP extension is not loaded.' ); 
     920        } 
     921 
     922        if ( is_multisite() ) { 
     923            $this->markTestSkipped( 'Test does not run in multisite' ); 
     924        } 
     925 
     926        $file = DIR_TESTDATA . '/uploads/video-play.svg'; 
     927        $filename = 'video-play.svg'; 
     928 
     929        $expected = array( 
     930            'ext' => 'svg', 
     931            'type' => 'image/svg+xml', 
     932            'proper_filename' => false, 
     933        ); 
     934 
     935        add_filter( 'upload_mimes', array( $this, '_filter_mime_types_svg' ) ); 
     936        $this->assertEquals( $expected, wp_check_filetype_and_ext( $file, $filename ) ); 
     937 
     938        // Cleanup. 
     939        remove_filter( 'upload_mimes', array( $this, '_test_add_mime_types_svg' ) ); 
     940    } 
     941 
     942    /** 
     943     * @ticket 39550 
     944     */ 
     945    function test_wp_check_filetype_and_ext_with_filtered_woff() { 
     946        if ( ! extension_loaded( 'fileinfo' ) ) { 
     947            $this->markTestSkipped( 'The fileinfo PHP extension is not loaded.' ); 
     948        } 
     949 
     950        if ( is_multisite() ) { 
     951            $this->markTestSkipped( 'Test does not run in multisite' ); 
     952        } 
     953 
     954        $file = DIR_TESTDATA . '/uploads/dashicons.woff'; 
     955        $filename = 'dashicons.woff'; 
     956 
     957        $expected = array( 
     958            'ext' => 'woff', 
     959            'type' => 'application/font-woff', 
     960            'proper_filename' => false, 
     961        ); 
     962 
     963        add_filter( 'upload_mimes', array( $this, '_filter_mime_types_woff' ) ); 
     964        $this->assertEquals( $expected, wp_check_filetype_and_ext( $file, $filename ) ); 
     965 
     966        // Cleanup. 
     967        remove_filter( 'upload_mimes', array( $this, '_test_add_mime_types_woff' ) ); 
     968    } 
     969 
     970    public function _filter_mime_types_svg( $mimes ) { 
     971        $mimes['svg'] = 'image/svg+xml'; 
     972        return $mimes; 
     973    } 
     974 
     975    public function _filter_mime_types_woff( $mimes ) { 
     976        $mimes['woff'] = 'application/font-woff'; 
     977        return $mimes; 
     978    } 
     979 
     980    public function _wp_check_filetype_and_ext_data() { 
     981        $data = array( 
     982            // Standard image. 
     983            array( 
     984                DIR_TESTDATA . '/images/canola.jpg', 
     985                'canola.jpg', 
     986                array( 
     987                    'ext' => 'jpg', 
     988                    'type' => 'image/jpeg', 
     989                    'proper_filename' => false, 
     990                ), 
     991            ), 
     992            // Image with wrong extension. 
     993            array( 
     994                DIR_TESTDATA . '/images/test-image-mime-jpg.png', 
     995                'test-image-mime-jpg.png', 
     996                array( 
     997                    'ext' => 'jpg', 
     998                    'type' => 'image/jpeg', 
     999                    'proper_filename' => 'test-image-mime-jpg.jpg', 
     1000                ), 
     1001            ), 
     1002            // Image without extension. 
     1003            array( 
     1004                DIR_TESTDATA . '/images/test-image-no-extension', 
     1005                'test-image-no-extension', 
     1006                array( 
     1007                    'ext' => false, 
     1008                    'type' => false, 
     1009                    'proper_filename' => false, 
     1010                ), 
     1011            ), 
     1012            // Valid non-image file with an image extension. 
     1013            array( 
     1014                DIR_TESTDATA . '/formatting/big5.txt', 
     1015                'big5.jpg', 
     1016                array( 
     1017                    'ext' => 'jpg', 
     1018                    'type' => 'image/jpeg', 
     1019                    'proper_filename' => false, 
     1020                ), 
     1021            ), 
     1022            // Non-image file not allowed. 
     1023            array( 
     1024                DIR_TESTDATA . '/export/crazy-cdata.xml', 
     1025                'crazy-cdata.xml', 
     1026                array( 
     1027                    'ext' => false, 
     1028                    'type' => false, 
     1029                    'proper_filename' => false, 
     1030                ), 
     1031            ), 
     1032        ); 
     1033 
     1034        // Test a few additional file types on single sites. 
     1035        if ( ! is_multisite() ) { 
     1036            $data = array_merge( $data, array( 
     1037                // Standard non-image file. 
     1038                array( 
     1039                    DIR_TESTDATA . '/formatting/big5.txt', 
     1040                    'big5.txt', 
     1041                    array( 
     1042                        'ext' => 'txt', 
     1043                        'type' => 'text/plain', 
     1044                        'proper_filename' => false, 
     1045                    ), 
     1046                ), 
     1047                // Non-image file with wrong sub-type. 
     1048                array( 
     1049                    DIR_TESTDATA . '/uploads/pages-to-word.docx', 
     1050                    'pages-to-word.docx', 
     1051                    array( 
     1052                        'ext' => 'docx', 
     1053                        'type' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 
     1054                        'proper_filename' => false, 
     1055                    ), 
     1056                ), 
     1057            ) ); 
     1058        } 
     1059 
     1060        return $data; 
     1061    } 
    9011062} 
Note: See TracChangeset for help on using the changeset viewer.