WordPress.org

Make WordPress Core

Ticket #42437: 42437.2.diff

File 42437.2.diff, 5.1 KB (added by pbiron, 12 months ago)
  • src/wp-includes/functions.php

    From 6e9cc65df561edbe5eb1e16ea195d86f42e4478c Mon Sep 17 00:00:00 2001
    From: Paul Biron <paul@sparrowhawkcomputing.com>
    Date: Tue, 3 Dec 2019 13:36:27 -0700
    Subject: [PATCH] Avoid conflicts with dimension-like filenames.
    
    ---
     src/wp-includes/functions.php     | 70 ++++++++++++++++++++++---------
     tests/phpunit/tests/functions.php | 12 ++++++
     2 files changed, 62 insertions(+), 20 deletions(-)
    
    diff --git a/src/wp-includes/functions.php b/src/wp-includes/functions.php
    index 6102da94f2..6446488bb8 100644
    a b function wp_unique_filename( $dir, $filename, $unique_filename_callback = null ) 
    24252425        if ( $unique_filename_callback && is_callable( $unique_filename_callback ) ) {
    24262426                $filename = call_user_func( $unique_filename_callback, $dir, $name, $ext );
    24272427        } else {
     2428                // Always append a number to filenames that can potentially match subsize filenames.
     2429                $ext_esc = preg_quote( $ext );
     2430                $fname    = pathinfo( $filename, PATHINFO_FILENAME );
     2431                if ( preg_match( "/-\d+x\d+{$ext_esc}\$/", $filename ) ) {
     2432                        $number = 1;
     2433                        while ( file_exists( "{$dir}/{$fname}-{$number}{$ext}" ) ) {
     2434                                $number++;
     2435                        }
     2436
     2437                        $filename = "{$fname}-{$number}{$ext}";
     2438                }
     2439
    24282440                $number = '';
    24292441
    24302442                // Change '.ext' to lower case.
    function wp_unique_filename( $dir, $filename, $unique_filename_callback = null ) 
    24402452                                $number     = $new_number;
    24412453                        }
    24422454
    2443                         /**
    2444                          * Filters the result when generating a unique file name.
    2445                          *
    2446                          * @since 4.5.0
    2447                          *
    2448                          * @param string        $filename                 Unique file name.
    2449                          * @param string        $ext                      File extension, eg. ".png".
    2450                          * @param string        $dir                      Directory path.
    2451                          * @param callable|null $unique_filename_callback Callback function that generates the unique file name.
    2452                          */
    2453                         return apply_filters( 'wp_unique_filename', $filename2, $ext, $dir, $unique_filename_callback );
     2455                        $filename = $filename2;
    24542456                }
    2455 
    2456                 while ( file_exists( $dir . "/$filename" ) ) {
    2457                         $new_number = (int) $number + 1;
    2458                         if ( '' == "$number$ext" ) {
    2459                                 $filename = "$filename-" . $new_number;
    2460                         } else {
    2461                                 $filename = str_replace( array( "-$number$ext", "$number$ext" ), '-' . $new_number . $ext, $filename );
     2457                else {
     2458                        while ( file_exists( $dir . "/$filename" ) ) {
     2459                                $new_number = (int) $number + 1;
     2460                                if ( '' == "$number$ext" ) {
     2461                                        $filename = "$filename-" . $new_number;
     2462                                } else {
     2463                                        $filename = str_replace( array( "-$number$ext", "$number$ext" ), '-' . $new_number . $ext, $filename );
     2464                                }
     2465                                $number = $new_number;
    24622466                        }
    2463                         $number = $new_number;
     2467                }
     2468
     2469                // prevent collisions with existing filenames that contain dimension-like strings (whether they
     2470                // are subsizes or originals uploaded prior to patch #xxx
     2471                // the array_filter() calls are similar to glob() but with the full
     2472                // expressiveness of regular expressions.
     2473                $number = 0;
     2474                // get the fname again, in case $filename has been modified above.
     2475                $fname  = pathinfo( $filename, PATHINFO_FILENAME );
     2476                $regex = "/^{$fname}-\d+x\d+{$ext_esc}\$/";
     2477                $files = array_filter( scandir( $dir ), function( $file ) { return ! in_array( $file, array( '.', '..' ) ); } );
     2478                if ( array_filter( $files, function( $file ) use ( $regex ) { return 1 === preg_match( $regex, $file ); } ) ) {
     2479                        do {
     2480                                $number++;
     2481                                $regex = "/^{$fname}-{$number}-\d+x\d+{$ext_esc}\$/";
     2482                        } while ( array_filter( $files, function( $file ) use ( $regex ) { return 1 === preg_match( $regex, $file ); } ) );
     2483
     2484                        $filename = "{$fname}-{$number}{$ext}";
    24642485                }
    24652486        }
    24662487
    2467         /** This filter is documented in wp-includes/functions.php */
     2488        /**
     2489         * Filters the result when generating a unique file name.
     2490         *
     2491         * @since 4.5.0
     2492         *
     2493         * @param string        $filename                 Unique file name.
     2494         * @param string        $ext                      File extension, eg. ".png".
     2495         * @param string        $dir                      Directory path.
     2496         * @param callable|null $unique_filename_callback Callback function that generates the unique file name.
     2497         */
    24682498        return apply_filters( 'wp_unique_filename', $filename, $ext, $dir, $unique_filename_callback );
    24692499}
    24702500
  • tests/phpunit/tests/functions.php

    diff --git a/tests/phpunit/tests/functions.php b/tests/phpunit/tests/functions.php
    index dd29c779e5..fee99b0ed4 100644
    a b class Tests_Functions extends WP_UnitTestCase { 
    195195                $this->assertEquals( 'abcdefg.png', wp_unique_filename( $testdir, 'abcde\\\fg.png' ), 'Tripple slashed not removed' );
    196196        }
    197197
     198        /**
     199         * @group 42437
     200         */
     201        function test_unique_filename_with_dimension_like_filename() {
     202                $testdir = DIR_TESTDATA . '/images/';
     203
     204                // test collision with "dimension-like" original filename.
     205                $this->assertEquals( 'one-blue-pixel-100x100-1.png', wp_unique_filename( $testdir, 'one-blue-pixel-100x100.png' ) );
     206                // test collision with existing sub-size filename.
     207                $this->assertEquals( 'one-blue-pixel-1.png', wp_unique_filename( $testdir, 'one-blue-pixel.png' ) );
     208        }
     209
    198210        function test_is_serialized() {
    199211                $cases = array(
    200212                        serialize( null ),