Ticket #53668: 53668.4.diff
File 53668.4.diff, 14.0 KB (added by , 3 years ago) |
---|
-
src/wp-includes/class-wp-image-editor.php
591 591 * @return string|false 592 592 */ 593 593 protected static function get_extension( $mime_type = null ) { 594 $extensions = explode( '|', array_search( $mime_type, wp_get_mime_types(), true ) ); 595 596 if ( empty( $extensions[0] ) ) { 594 if ( empty( $mime_type ) ) { 597 595 return false; 598 596 } 599 597 600 return $extensions[0];598 return wp_get_default_extension_for_mime_type( $mime_type ); 601 599 } 602 600 } 603 601 -
src/wp-includes/functions.php
2486 2486 function wp_unique_filename( $dir, $filename, $unique_filename_callback = null ) { 2487 2487 // Sanitize the file name before we begin processing. 2488 2488 $filename = sanitize_file_name( $filename ); 2489 $ext2 = null;2490 2489 2491 2490 // Separate the filename into a name and extension. 2492 2491 $ext = pathinfo( $filename, PATHINFO_EXTENSION ); … … 2501 2500 $name = ''; 2502 2501 } 2503 2502 2503 // Reconstruct sanitized filename with lower case extension. 2504 $ext = strtolower( $ext ); 2505 $filename = pathinfo( $filename, PATHINFO_FILENAME ) . $ext; 2506 2504 2507 /* 2505 2508 * Increment the file number until we have a unique file to save in $dir. 2506 2509 * Use callback if supplied. … … 2511 2514 $number = ''; 2512 2515 $fname = pathinfo( $filename, PATHINFO_FILENAME ); 2513 2516 2517 // If filename already versioned, get version and un-versioned filename. 2518 if ( preg_match( '/-(\d)$/', $fname, $matches ) ) { 2519 $fname = preg_replace( '/' . $matches[0] . '$/', '', $fname ); 2520 $number = (int) $matches[1]; 2521 } 2522 2514 2523 // Always append a number to file names that can potentially match image sub-size file names. 2515 2524 if ( $fname && preg_match( '/-(?:\d+x\d+|scaled|rotated)$/', $fname ) ) { 2516 $number = 1;2525 $number = (int) $number + 1; 2517 2526 2518 2527 // At this point the file name may not be unique. This is tested below and the $number is incremented. 2519 2528 $filename = str_replace( "{$fname}{$ext}", "{$fname}-{$number}{$ext}", $filename ); 2520 2529 } 2521 2530 2522 // Change '.ext' to lower case. 2523 if ( $ext && strtolower( $ext ) != $ext ) { 2524 $ext2 = strtolower( $ext ); 2525 $filename2 = preg_replace( '|' . preg_quote( $ext ) . '$|', $ext2, $filename ); 2531 // Check for both lower and upper case extension or image sub-sizes may be overwritten. 2532 $uc_ext = strtoupper( $ext ); 2533 $uc_ext_filename = preg_replace( '|' . preg_quote( $ext ) . '$|', $uc_ext, $filename ); 2526 2534 2527 // Check for both lower and upper case extension or image sub-sizes may be overwritten. 2528 while ( file_exists( $dir . "/{$filename}" ) || file_exists( $dir . "/{$filename2}" ) ) { 2529 $new_number = (int) $number + 1; 2530 $filename = str_replace( array( "-{$number}{$ext}", "{$number}{$ext}" ), "-{$new_number}{$ext}", $filename ); 2531 $filename2 = str_replace( array( "-{$number}{$ext2}", "{$number}{$ext2}" ), "-{$new_number}{$ext2}", $filename2 ); 2532 $number = $new_number; 2533 } 2534 2535 $filename = $filename2; 2536 } else { 2537 while ( file_exists( $dir . "/{$filename}" ) ) { 2538 $new_number = (int) $number + 1; 2539 2540 if ( '' === "{$number}{$ext}" ) { 2541 $filename = "{$filename}-{$new_number}"; 2542 } else { 2543 $filename = str_replace( array( "-{$number}{$ext}", "{$number}{$ext}" ), "-{$new_number}{$ext}", $filename ); 2544 } 2545 2546 $number = $new_number; 2547 } 2535 while ( file_exists( $dir . "/{$filename}" ) || file_exists( $dir . "/{$uc_ext_filename}" ) ) { 2536 $new_number = (int) $number + 1; 2537 $filename = str_replace( array( "{$fname}-{$number}{$ext}", "{$fname}{$number}{$ext}" ), "{$fname}-{$new_number}{$ext}", $filename ); 2538 $uc_ext_filename = str_replace( array( "{$fname}-{$number}{$uc_ext}", "{$fname}{$number}{$uc_ext}" ), "{$fname}-{$new_number}{$uc_ext}", $uc_ext_filename ); 2539 $number = $new_number; 2548 2540 } 2549 2541 2550 2542 // Prevent collisions with existing file names that contain dimension-like strings … … 2579 2571 } 2580 2572 2581 2573 if ( ! empty( $files ) ) { 2582 // The extension case may have changed above.2583 $new_ext = ! empty( $ext2 ) ? $ext2 : $ext;2584 2585 2574 // Ensure this never goes into infinite loop 2586 2575 // as it uses pathinfo() and regex in the check, but string replacement for the changes. 2587 2576 $count = count( $files ); … … 2589 2578 2590 2579 while ( $i <= $count && _wp_check_existing_file_names( $filename, $files ) ) { 2591 2580 $new_number = (int) $number + 1; 2592 $filename = str_replace( array( " -{$number}{$new_ext}", "{$number}{$new_ext}" ), "-{$new_number}{$new_ext}", $filename );2581 $filename = str_replace( array( "{$fname}-{$number}{$ext}", "{$fname}{$number}{$ext}" ), "{$fname}-{$new_number}{$ext}", $filename ); 2593 2582 $number = $new_number; 2594 2583 $i++; 2595 2584 } 2596 2585 } 2597 2586 } 2587 2588 // If a different file type might be produced for an image, check filename uniqueness for that format. 2589 $filename = _wp_check_alternate_output_format_uniqueness( $filename, $ext, $dir ); 2598 2590 } 2599 2591 2600 2592 /** … … 2645 2637 } 2646 2638 2647 2639 /** 2640 * Helper function for wp_unique_filename to check potential alternate output formats for images. 2641 * 2642 * @since 5.8.1 2643 * @private 2644 * 2645 * @param string $filename 2646 * @param string $ext 2647 * @param string $dir 2648 * 2649 * @return string 2650 */ 2651 function _wp_check_alternate_output_format_uniqueness( $filename, $ext, $dir ) { 2652 static $checking_alternates; 2653 2654 if ( empty( $checking_alternates ) ) { 2655 $checking_alternates = true; 2656 $filename_changed = false; 2657 $file_type = wp_check_filetype_and_ext( trailingslashit( $dir ) . $filename, $filename ); 2658 $mime_type = $file_type['type']; 2659 2660 if ( ! empty( $mime_type ) && 0 === strpos( $mime_type, 'image/' ) ) { 2661 $output_formats = apply_filters( 'image_editor_output_format', array(), trailingslashit( $dir ) . $filename, $mime_type ); 2662 2663 if ( ! empty( $output_formats ) && is_array( $output_formats ) ) { 2664 // Temporarily add uploaded type to alts for simpler analysis. 2665 $alt_mime_types = array( $mime_type ); 2666 2667 // Alternate thumbnail format for uploaded file? 2668 if ( ! empty( $output_formats[ $mime_type ] ) ) { 2669 $alt_mime_types[] = $output_formats[ $mime_type ]; 2670 } 2671 2672 // Any other formats using uploaded or alternate format for thumbnails? 2673 $alt_mime_types = array_merge( $alt_mime_types, array_keys( array_intersect( $output_formats, $alt_mime_types ) ) ); 2674 2675 // Remove uploaded mime type as we've already tested that. 2676 $alt_mime_types = array_diff( $alt_mime_types, array( $mime_type ) ); 2677 } 2678 2679 if ( ! empty( $alt_mime_types ) ) { 2680 $alt_mime_types = array_unique( $alt_mime_types ); 2681 2682 foreach ( $alt_mime_types as $alt_mime_type ) { 2683 $alt_ext = wp_get_default_extension_for_mime_type( $alt_mime_type ); 2684 2685 if ( ! empty( $alt_ext ) && ".{$alt_ext}" !== $ext ) { 2686 $alt_filename = wp_basename( $filename, $ext ) . ".{$alt_ext}"; 2687 $alt_filename2 = wp_unique_filename( $dir, $alt_filename ); 2688 2689 // If a potential clash was found for alternate format, use its unique filename. 2690 if ( $alt_filename2 !== $alt_filename ) { 2691 $filename = wp_basename( $alt_filename2, ".{$alt_ext}" ) . $ext; 2692 $filename_changed = true; 2693 } 2694 } 2695 } 2696 } 2697 } 2698 $checking_alternates = false; 2699 2700 // Double check that incremented filename for original type or first tested alternate types do not clash. 2701 if ( $filename_changed ) { 2702 2703 return wp_unique_filename( $dir, $filename ); 2704 } 2705 } 2706 2707 return $filename; 2708 } 2709 2710 /** 2648 2711 * Create a file in the upload folder with given content. 2649 2712 * 2650 2713 * If there is an error, then the key 'error' will exist with the error message. … … 3042 3105 } 3043 3106 3044 3107 /** 3108 * Returns first matched extension from Mime-type, 3109 * as mapped from wp_get_mime_types() 3110 * 3111 * @since 5.8.1 3112 * 3113 * @param string $mime_type 3114 * 3115 * @return string|false 3116 * 3117 */ 3118 function wp_get_default_extension_for_mime_type( $mime_type ) { 3119 $extensions = explode( '|', array_search( $mime_type, wp_get_mime_types(), true ) ); 3120 3121 if ( empty( $extensions[0] ) ) { 3122 return false; 3123 } 3124 3125 return $extensions[0]; 3126 } 3127 3128 /** 3045 3129 * Returns the real mime type of an image file. 3046 3130 * 3047 3131 * This depends on exif_imagetype() or getimagesize() to determine real mime types. -
tests/phpunit/tests/functions.php
222 222 } 223 223 224 224 /** 225 * @ticket 53668 226 */ 227 function test__wp_check_alternate_output_format_uniqueness() { 228 $testdir = DIR_TESTDATA . '/images/'; 229 230 add_filter( 'upload_dir', array( $this, 'upload_dir_patch_basedir' ) ); 231 232 // Standard test that wp_unique_filename allows usage if file does not exist yet. 233 $this->assertSame( 'abcdef.png', wp_unique_filename( $testdir, 'abcdef.png' ), 'The abcdef.png image does not exist. The name does not need to be made unique.' ); 234 // Difference in extension does not affect wp_unique_filename by default (canola.jpg exists). 235 $this->assertSame( 'canola.png', wp_unique_filename( $testdir, 'canola.png' ), 'The canola.jpg image exists. Clashing base filename but not extension should not have name changed.' ); 236 // Run again with upper case extension. 237 $this->assertSame( 'canola.png', wp_unique_filename( $testdir, 'canola.PNG' ), 'The canola.jpg image exists. Clashing base filename but not extension should not have name changed.' ); 238 // Actual clash recognized. 239 $this->assertSame( 'canola-1.jpg', wp_unique_filename( $testdir, 'canola.jpg' ), 'The canola.jpg image exists. Uploading canola.jpg again should have unique name.' ); 240 // Future clash by regenerated thumbnails not applicable. 241 $this->assertSame( 'codeispoetry.jpg', wp_unique_filename( $testdir, 'codeispoetry.jpg' ), 'The codeispoetry.png image exists. Uploading codeispoetry.jpg does not need unique name.' ); 242 243 // When creating sub-sizes convert uploaded PNG images to JPG. 244 add_filter( 'image_editor_output_format', array( $this, 'image_editor_output_format_handler' ) ); 245 246 // Standard test that wp_unique_filename allows usage if file does not exist yet. 247 $this->assertSame( 'abcdef.png', wp_unique_filename( $testdir, 'abcdef.png' ), 'The abcdef.png image does not exist. Its name should not be changed.' ); 248 // Standard test that wp_unique_filename allows usage if file does not exist yet. 249 $this->assertSame( 'abcdef.bmp', wp_unique_filename( $testdir, 'abcdef.bmp' ), 'The abcdef.bmp and abcdef.pct images do not exist. When uploading abcdef.bmp its name should not be changed.' ); 250 // Difference in extension does affect wp_unique_filename when thumbnails use existing file's type. 251 $this->assertSame( 'canola-1.png', wp_unique_filename( $testdir, 'canola.png' ), 'The canola.jpg image exists. Uploading canola.png that will be converted to canola.jpg should produce unique file name.' ); 252 // Run again with upper case extension. 253 $this->assertSame( 'canola-1.png', wp_unique_filename( $testdir, 'canola.PNG' ), 'The canola.jpg image exists. Uploading canola.PNG that will be converted to canola.jpg should produce unique file name.' ); 254 // Actual clash recognized. 255 $this->assertSame( 'canola-1.jpg', wp_unique_filename( $testdir, 'canola.jpg' ), 'Existing file should have name changed.' ); 256 // Actual clash with images with different extensions. 257 $this->assertSame( 'test-image-3.png', wp_unique_filename( $testdir, 'test-image.png' ), 'The test-image.png, test-image-1-100x100.jpg, and test-image-2.gif images exist. All of them may be intersected when creating sub-sizes for the new image: test-image.png, so its filename should be unique.' ); 258 // Future clash by regenerated thumbnails recognized. 259 $this->assertSame( 'codeispoetry-1.jpg', wp_unique_filename( $testdir, 'codeispoetry.jpg' ), 'The codeispoetry.png image exists. When regenerating thumbnails for it they will be converted to JPG. The name of the newly uploaded codeispoetry.jpg should be made unique.' ); 260 261 remove_filter( 'image_editor_output_format', array( $this, 'image_editor_output_format_handler' ) ); 262 remove_filter( 'upload_dir', array( $this, 'upload_dir_patch_basedir' ) ); 263 } 264 265 /** 266 * Changes the output format when editing images. When uploading a PNG file 267 * it will be converted to JPG (if the image editor in PHP supports it). 268 * 269 * @param array $formats 270 * 271 * @return array 272 */ 273 public function image_editor_output_format_handler( $formats ) { 274 $formats['image/png'] = 'image/jpeg'; 275 $formats['image/gif'] = 'image/jpeg'; 276 $formats['image/pct'] = 'image/bmp'; 277 278 return $formats; 279 } 280 281 /** 225 282 * @dataProvider data_is_not_serialized 226 283 */ 227 284 function test_maybe_serialize( $value ) { … … 1946 2003 array( 'application/activity+json, application/nojson', true ), 1947 2004 ); 1948 2005 } 2006 2007 /** 2008 * @ticket 53668 2009 */ 2010 public function test_wp_get_default_extension_for_mime_type() { 2011 $this->assertEquals( 'jpg', wp_get_default_extension_for_mime_type( 'image/jpeg' ), 'jpg not returned as default extension for "image/jpeg"' ); 2012 $this->assertNotEquals( 'jpeg', wp_get_default_extension_for_mime_type( 'image/jpeg' ), 'jpeg should not be returned as default extension for "image/jpeg"' ); 2013 $this->assertEquals( 'png', wp_get_default_extension_for_mime_type( 'image/png' ), 'png not returned as default extension for "image/png"' ); 2014 $this->assertFalse( wp_get_default_extension_for_mime_type( 'wibble/wobble' ), 'false not returned for unrecognized mime type' ); 2015 $this->assertFalse( wp_get_default_extension_for_mime_type( '' ), 'false not returned when empty string as mime type supplied' ); 2016 $this->assertFalse( wp_get_default_extension_for_mime_type( ' ' ), 'false not returned when empty string as mime type supplied' ); 2017 $this->assertFalse( wp_get_default_extension_for_mime_type( 123 ), 'false not returned when int as mime type supplied' ); 2018 $this->assertFalse( wp_get_default_extension_for_mime_type( null ), 'false not returned when null as mime type supplied' ); 2019 } 1949 2020 }