<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[51706] branches/5.8: Media: Fix `wp_unique_filename()` to check for name collisions with all alternate file names when an image may be converted after uploading.</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { white-space: pre-line; overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta" style="font-size: 105%">
<dt style="float: left; width: 6em; font-weight: bold">Revision</dt> <dd><a style="font-weight: bold" href="https://core.trac.wordpress.org/changeset/51706">51706</a><script type="application/ld+json">{"@context":"http://schema.org","@type":"EmailMessage","description":"Review this Commit","action":{"@type":"ViewAction","url":"https://core.trac.wordpress.org/changeset/51706","name":"Review Commit"}}</script></dd>
<dt style="float: left; width: 6em; font-weight: bold">Author</dt> <dd>desrosj</dd>
<dt style="float: left; width: 6em; font-weight: bold">Date</dt> <dd>2021-08-31 23:56:11 +0000 (Tue, 31 Aug 2021)</dd>
</dl>

<pre style='padding-left: 1em; margin: 2em 0; border-left: 2px solid #ccc; line-height: 1.25; font-size: 105%; font-family: sans-serif'>Media: Fix `wp_unique_filename()` to check for name collisions with all alternate file names when an image may be converted after uploading. This includes possible collinions with pre-existing images whose sub-sizes/thumbnails are regenerated.

Props ianmjones, azaozz.
Merges <a href="https://core.trac.wordpress.org/changeset/51653">[51653]</a> to the 5.8 branch.
Fixes <a href="https://core.trac.wordpress.org/ticket/53668">#53668</a>.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#branches58srcwpincludesclasswpimageeditorphp">branches/5.8/src/wp-includes/class-wp-image-editor.php</a></li>
<li><a href="#branches58srcwpincludesfunctionsphp">branches/5.8/src/wp-includes/functions.php</a></li>
<li><a href="#branches58testsphpunittestsfunctionsphp">branches/5.8/tests/phpunit/tests/functions.php</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#branches58testsphpunitdataimagestestimage1100x100jpg">branches/5.8/tests/phpunit/data/images/test-image-1-100x100.jpg</a></li>
<li><a href="#branches58testsphpunitdataimagestestimage2gif">branches/5.8/tests/phpunit/data/images/test-image-2.gif</a></li>
<li><a href="#branches58testsphpunitdataimagestestimage3jpg">branches/5.8/tests/phpunit/data/images/test-image-3.jpg</a></li>
<li><a href="#branches58testsphpunitdataimagestestimage4png">branches/5.8/tests/phpunit/data/images/test-image-4.png</a></li>
</ul>

<h3>Property Changed</h3>
<ul>
<li><a href="#branches58">branches/5.8/</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<span class="cx" style="display: block; padding: 0 10px">Index: branches/5.8
</span><span class="cx" style="display: block; padding: 0 10px">===================================================================
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">--- branches/5.8 2021-08-31 19:57:20 UTC (rev 51705)
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+++ branches/5.8  2021-08-31 23:56:11 UTC (rev 51706)
</ins><a id="branches58"></a>
<div class="propset"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Property changes: branches/5.8</h4>
<pre class="diff"><span>
</span></pre></div>
<a id="svnmergeinfo"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: svn:mergeinfo</h4></div>
<span class="cx" style="display: block; padding: 0 10px"> /branches/4.9:43557,43622
</span><span class="cx" style="display: block; padding: 0 10px"> /branches/5.0:43681-43682,43684-43688,43719-43720,43723,43726-43727,43729-43731,43734-43744,43747,43751-43754,43758,43760-43765,43767-43770,43772,43774-43781,43783,43785,43790-43806,43808-43821,43825,43828,43830-43834,43836-43843,43846-43863,43867-43889,43891-43894,43897-43905,43908-43909,43911-43929,43931-43942,43946-43947,43949-43956,43959-43964,43967-43969,43988,43994,44014,44017,44047,44183,44185,44187-44206,44208-44213,44231-44232,44235,44248,44284,44287-44288
</span><span class="cx" style="display: block; padding: 0 10px"> /branches/5.5:49373-49379,49381
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-/trunk:51274,51277,51279-51284,51286-51289,51292-51294,51296,51304,51307,51309,51321-51324,51332,51343-51344,51348-51349,51351-51353,51355-51356,51359,51362,51369-51371,51375,51377,51380,51383,51387-51388,51390,51400,51402,51408-51410,51413-51414,51418,51421,51423,51426,51431-51432,51435,51440,51442-51443,51455,51459,51467-51469,51471-51474,51482-51483,51485-51486,51497-51498,51510,51525,51538-51540,51595,51611,51631-51632,51637,51649,51673-51674,51682-51683,51686,51688-51689
</del><span class="cx" style="display: block; padding: 0 10px">\ No newline at end of property
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+/trunk:51274,51277,51279-51284,51286-51289,51292-51294,51296,51304,51307,51309,51321-51324,51332,51343-51344,51348-51349,51351-51353,51355-51356,51359,51362,51369-51371,51375,51377,51380,51383,51387-51388,51390,51400,51402,51408-51410,51413-51414,51418,51421,51423,51426,51431-51432,51435,51440,51442-51443,51455,51459,51467-51469,51471-51474,51482-51483,51485-51486,51497-51498,51510,51525,51538-51540,51595,51611,51631-51632,51637,51649,51653,51673-51674,51682-51683,51686,51688-51689
</ins><span class="cx" style="display: block; padding: 0 10px">\ No newline at end of property
</span><a id="branches58srcwpincludesclasswpimageeditorphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: branches/5.8/src/wp-includes/class-wp-image-editor.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- branches/5.8/src/wp-includes/class-wp-image-editor.php    2021-08-31 19:57:20 UTC (rev 51705)
+++ branches/5.8/src/wp-includes/class-wp-image-editor.php      2021-08-31 23:56:11 UTC (rev 51706)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -591,13 +591,11 @@
</span><span class="cx" style="display: block; padding: 0 10px">         * @return string|false
</span><span class="cx" style="display: block; padding: 0 10px">         */
</span><span class="cx" style="display: block; padding: 0 10px">        protected static function get_extension( $mime_type = null ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $extensions = explode( '|', array_search( $mime_type, wp_get_mime_types(), true ) );
-
-               if ( empty( $extensions[0] ) ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         if ( empty( $mime_type ) ) {
</ins><span class="cx" style="display: block; padding: 0 10px">                         return false;
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                return $extensions[0];
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         return wp_get_default_extension_for_mime_type( $mime_type );
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span></span></pre></div>
<a id="branches58srcwpincludesfunctionsphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: branches/5.8/src/wp-includes/functions.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- branches/5.8/src/wp-includes/functions.php        2021-08-31 19:57:20 UTC (rev 51705)
+++ branches/5.8/src/wp-includes/functions.php  2021-08-31 23:56:11 UTC (rev 51706)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -2485,6 +2485,10 @@
</span><span class="cx" style="display: block; padding: 0 10px">        $filename = sanitize_file_name( $filename );
</span><span class="cx" style="display: block; padding: 0 10px">        $ext2     = null;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Initialize vars used in the wp_unique_filename filter.
+       $number        = '';
+       $alt_filenames = array();
+
</ins><span class="cx" style="display: block; padding: 0 10px">         // Separate the filename into a name and extension.
</span><span class="cx" style="display: block; padding: 0 10px">        $ext  = pathinfo( $filename, PATHINFO_EXTENSION );
</span><span class="cx" style="display: block; padding: 0 10px">        $name = pathinfo( $filename, PATHINFO_BASENAME );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -2505,8 +2509,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">        if ( $unique_filename_callback && is_callable( $unique_filename_callback ) ) {
</span><span class="cx" style="display: block; padding: 0 10px">                $filename = call_user_func( $unique_filename_callback, $dir, $name, $ext );
</span><span class="cx" style="display: block; padding: 0 10px">        } else {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $number = '';
-               $fname  = pathinfo( $filename, PATHINFO_FILENAME );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $fname = pathinfo( $filename, PATHINFO_FILENAME );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                // Always append a number to file names that can potentially match image sub-size file names.
</span><span class="cx" style="display: block; padding: 0 10px">                if ( $fname && preg_match( '/-(?:\d+x\d+|scaled|rotated)$/', $fname ) ) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -2516,38 +2519,55 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        $filename = str_replace( "{$fname}{$ext}", "{$fname}-{$number}{$ext}", $filename );
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                // Change '.ext' to lower case.
-               if ( $ext && strtolower( $ext ) != $ext ) {
-                       $ext2      = strtolower( $ext );
-                       $filename2 = preg_replace( '|' . preg_quote( $ext ) . '$|', $ext2, $filename );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         // Get the mime type. Uploaded files were already checked with wp_check_filetype_and_ext()
+               // in _wp_handle_upload(). Using wp_check_filetype() would be sufficient here.
+               $file_type = wp_check_filetype( $filename );
+               $mime_type = $file_type['type'];
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        // Check for both lower and upper case extension or image sub-sizes may be overwritten.
-                       while ( file_exists( $dir . "/{$filename}" ) || file_exists( $dir . "/{$filename2}" ) ) {
-                               $new_number = (int) $number + 1;
-                               $filename   = str_replace( array( "-{$number}{$ext}", "{$number}{$ext}" ), "-{$new_number}{$ext}", $filename );
-                               $filename2  = str_replace( array( "-{$number}{$ext2}", "{$number}{$ext2}" ), "-{$new_number}{$ext2}", $filename2 );
-                               $number     = $new_number;
-                       }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $is_image    = ( ! empty( $mime_type ) && 0 === strpos( $mime_type, 'image/' ) );
+               $upload_dir  = wp_get_upload_dir();
+               $lc_filename = null;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        $filename = $filename2;
-               } else {
-                       while ( file_exists( $dir . "/{$filename}" ) ) {
-                               $new_number = (int) $number + 1;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $lc_ext = strtolower( $ext );
+               $_dir   = trailingslashit( $dir );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                if ( '' === "{$number}{$ext}" ) {
-                                       $filename = "{$filename}-{$new_number}";
-                               } else {
-                                       $filename = str_replace( array( "-{$number}{$ext}", "{$number}{$ext}" ), "-{$new_number}{$ext}", $filename );
-                               }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         // If the extension is uppercase add an alternate file name with lowercase extension. Both need to be tested
+               // for uniqueness as the extension will be changed to lowercase for better compatibility with different filesystems.
+               // Fixes an inconsistency in WP < 2.9 where uppercase extensions were allowed but image sub-sizes were created with
+               // lowercase extensions.
+               if ( $ext && $lc_ext !== $ext ) {
+                       $lc_filename = preg_replace( '|' . preg_quote( $ext ) . '$|', $lc_ext, $filename );
+               }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                $number = $new_number;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         // Increment the number added to the file name if there are any files in $dir whose names match one of the
+               // possible name variations.
+               while ( file_exists( $_dir . $filename ) || ( $lc_filename && file_exists( $_dir . $lc_filename ) ) ) {
+                       $new_number = (int) $number + 1;
+
+                       if ( $lc_filename ) {
+                               $lc_filename = str_replace( array( "-{$number}{$lc_ext}", "{$number}{$lc_ext}" ), "-{$new_number}{$lc_ext}", $lc_filename );
</ins><span class="cx" style="display: block; padding: 0 10px">                         }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+                       if ( '' === "{$number}{$ext}" ) {
+                               $filename = "{$filename}-{$new_number}";
+                       } else {
+                               $filename = str_replace( array( "-{$number}{$ext}", "{$number}{$ext}" ), "-{$new_number}{$ext}", $filename );
+                       }
+
+                       $number = $new_number;
</ins><span class="cx" style="display: block; padding: 0 10px">                 }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                // Change the extension to lowercase if needed.
+               if ( $lc_filename ) {
+                       $filename = $lc_filename;
+               }
+
</ins><span class="cx" style="display: block; padding: 0 10px">                 // Prevent collisions with existing file names that contain dimension-like strings
</span><span class="cx" style="display: block; padding: 0 10px">                // (whether they are subsizes or originals uploaded prior to #42437).
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $upload_dir = wp_get_upload_dir();
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                $files = array();
+               $count = 10000;
+
</ins><span class="cx" style="display: block; padding: 0 10px">                 // The (resized) image files would have name and extension, and will be in the uploads dir.
</span><span class="cx" style="display: block; padding: 0 10px">                if ( $name && $ext && @is_dir( $dir ) && false !== strpos( $dir, $upload_dir['basedir'] ) ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        /**
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -2576,22 +2596,81 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                        if ( ! empty( $files ) ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                // The extension case may have changed above.
-                               $new_ext = ! empty( $ext2 ) ? $ext2 : $ext;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         $count = count( $files );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                                // Ensure this never goes into infinite loop
</span><span class="cx" style="display: block; padding: 0 10px">                                // as it uses pathinfo() and regex in the check, but string replacement for the changes.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                $count = count( $files );
-                               $i     = 0;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         $i = 0;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                                while ( $i <= $count && _wp_check_existing_file_names( $filename, $files ) ) {
</span><span class="cx" style="display: block; padding: 0 10px">                                        $new_number = (int) $number + 1;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                        $filename   = str_replace( array( "-{$number}{$new_ext}", "{$number}{$new_ext}" ), "-{$new_number}{$new_ext}", $filename );
-                                       $number     = $new_number;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+                                       // If $ext is uppercase it was replaced with the lowercase version after the previous loop.
+                                       $filename = str_replace( array( "-{$number}{$lc_ext}", "{$number}{$lc_ext}" ), "-{$new_number}{$lc_ext}", $filename );
+
+                                       $number = $new_number;
</ins><span class="cx" style="display: block; padding: 0 10px">                                         $i++;
</span><span class="cx" style="display: block; padding: 0 10px">                                }
</span><span class="cx" style="display: block; padding: 0 10px">                        }
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+               // Check if an image will be converted after uploading or some existing images sub-sizes file names may conflict
+               // when regenerated. If yes, ensure the new file name will be unique and will produce unique sub-sizes.
+               if ( $is_image ) {
+                       $output_formats = apply_filters( 'image_editor_output_format', array(), $_dir . $filename, $mime_type );
+                       $alt_types      = array();
+
+                       if ( ! empty( $output_formats[ $mime_type ] ) ) {
+                               // The image will be converted to this format/mime type.
+                               $alt_mime_type = $output_formats[ $mime_type ];
+
+                               // Other types of images whose names may conflict if their sub-sizes are regenerated.
+                               $alt_types = array_keys( array_intersect( $output_formats, array( $mime_type, $alt_mime_type ) ) );
+                               $alt_types[] = $alt_mime_type;
+                       } elseif ( ! empty( $output_formats ) ) {
+                               $alt_types = array_keys( array_intersect( $output_formats, array( $mime_type ) ) );
+                       }
+
+                       // Remove duplicates and the original mime type. It will be added later if needed.
+                       $alt_types = array_unique( array_diff( $alt_types, array( $mime_type ) ) );
+
+                       foreach ( $alt_types as $alt_type ) {
+                               $alt_ext = wp_get_default_extension_for_mime_type( $alt_type );
+
+                               if ( ! $alt_ext ) {
+                                       continue;
+                               }
+
+                               $alt_ext      = ".{$alt_ext}";
+                               $alt_filename = preg_replace( '|' . preg_quote( $lc_ext ) . '$|', $alt_ext, $filename );
+
+                               $alt_filenames[ $alt_ext ] = $alt_filename;
+                       }
+
+                       if ( ! empty( $alt_filenames ) ) {
+                               // Add the original filename. It needs to be checked again together with the alternate filenames
+                               // when $number is incremented.
+                               $alt_filenames[ $lc_ext ] = $filename;
+
+                               // Ensure no infinite loop.
+                               $i = 0;
+
+                               while ( $i <= $count && _wp_check_alternate_file_names( $alt_filenames, $_dir, $files ) ) {
+                                       $new_number = (int) $number + 1;
+
+                                       foreach ( $alt_filenames as $alt_ext => $alt_filename ) {
+                                               $alt_filenames[ $alt_ext ] = str_replace( array( "-{$number}{$alt_ext}", "{$number}{$alt_ext}" ), "-{$new_number}{$alt_ext}", $alt_filename );
+                                       }
+
+                                       // Also update the $number in (the output) $filename.
+                                       // If the extension was uppercase it was already replaced with the lowercase version.
+                                       $filename = str_replace( array( "-{$number}{$lc_ext}", "{$number}{$lc_ext}" ), "-{$new_number}{$lc_ext}", $filename );
+
+                                       $number = $new_number;
+                                       $i++;
+                               }
+                       }
+               }
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        /**
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -2598,16 +2677,45 @@
</span><span class="cx" style="display: block; padding: 0 10px">         * Filters the result when generating a unique file name.
</span><span class="cx" style="display: block; padding: 0 10px">         *
</span><span class="cx" style="display: block; padding: 0 10px">         * @since 4.5.0
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         * @since 5.8.1 The `$alt_filenames` and `$number` parameters were added.
</ins><span class="cx" style="display: block; padding: 0 10px">          *
</span><span class="cx" style="display: block; padding: 0 10px">         * @param string        $filename                 Unique file name.
</span><span class="cx" style="display: block; padding: 0 10px">         * @param string        $ext                      File extension, eg. ".png".
</span><span class="cx" style="display: block; padding: 0 10px">         * @param string        $dir                      Directory path.
</span><span class="cx" style="display: block; padding: 0 10px">         * @param callable|null $unique_filename_callback Callback function that generates the unique file name.
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         * @param string[]      $alt_filenames            Array of alternate file names that were checked for collisions.
+        * @param int|string    $number                   The highest number that was used to make the file name unique
+        *                                                or an empty string if unused.
</ins><span class="cx" style="display: block; padding: 0 10px">          */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        return apply_filters( 'wp_unique_filename', $filename, $ext, $dir, $unique_filename_callback );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ return apply_filters( 'wp_unique_filename', $filename, $ext, $dir, $unique_filename_callback, $alt_filenames, $number );
</ins><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * Helper function to test if each of an array of file names could conflict with existing files.
+ *
+ * @since 5.8.1
+ * @access private
+ *
+ * @param string[] $filenames Array of file names to check.
+ * @param string   $dir       The directory containing the files.
+ * @param array    $files     An array of existing files in the directory. May be empty.
+ * @return bool True if the tested file name could match an existing file, false otherwise.
+ */
+function _wp_check_alternate_file_names( $filenames, $dir, $files ) {
+       foreach ( $filenames as $filename ) {
+               if ( file_exists( $dir . $filename ) ) {
+                       return true;
+               }
+
+               if ( ! empty( $files ) && _wp_check_existing_file_names( $filename, $files ) ) {
+                       return true;
+               }
+       }
+
+       return false;
+}
+
+/**
</ins><span class="cx" style="display: block; padding: 0 10px">  * Helper function to check if a file name could match an existing image sub-size file name.
</span><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * @since 5.3.1
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -2791,6 +2899,26 @@
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * Returns first matched extension for the mime-type,
+ * as mapped from wp_get_mime_types().
+ *
+ * @since 5.8.1
+ *
+ * @param string $mime_type
+ *
+ * @return string|false
+ */
+function wp_get_default_extension_for_mime_type( $mime_type ) {
+       $extensions = explode( '|', array_search( $mime_type, wp_get_mime_types(), true ) );
+
+       if ( empty( $extensions[0] ) ) {
+               return false;
+       }
+
+       return $extensions[0];
+}
+
+/**
</ins><span class="cx" style="display: block; padding: 0 10px">  * Retrieve the file type from the file name.
</span><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * You can optionally define the mime array, if needed.
</span></span></pre></div>
<a id="branches58testsphpunitdataimagestestimage1100x100jpgfromrev51653trunktestsphpunitdataimagestestimage1100x100jpg"></a>
<div class="binary"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Copied: branches/5.8/tests/phpunit/data/images/test-image-1-100x100.jpg (from rev 51653, trunk/tests/phpunit/data/images/test-image-1-100x100.jpg)</h4>
<pre class="diff"><span>
<span class="cx">(Binary files differ)
</span></span></pre></div>
<a id="branches58testsphpunitdataimagestestimage2giffromrev51653trunktestsphpunitdataimagestestimage2gif"></a>
<div class="binary"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Copied: branches/5.8/tests/phpunit/data/images/test-image-2.gif (from rev 51653, trunk/tests/phpunit/data/images/test-image-2.gif)</h4>
<pre class="diff"><span>
<span class="cx">(Binary files differ)
</span></span></pre></div>
<a id="branches58testsphpunitdataimagestestimage3jpgfromrev51653trunktestsphpunitdataimagestestimage3jpg"></a>
<div class="copfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Copied: branches/5.8/tests/phpunit/data/images/test-image-3.jpg (from rev 51653, trunk/tests/phpunit/data/images/test-image-3.jpg)</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- branches/5.8/tests/phpunit/data/images/test-image-3.jpg                           (rev 0)
+++ branches/5.8/tests/phpunit/data/images/test-image-3.jpg     2021-08-31 23:56:11 UTC (rev 51706)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,22 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+\xFF\xD8\xFF\xE0JFIFHH\xFF\xE1\x80ExifMM*JR(\x87iZ9o9o\xA02\xA02\xFF\xDBC\xFF\xDBC\xFF\xC022\xFF\xC4 
+ \xFF\xC4\xB5}!1AQa"q2\x81\x91\xA1#B\xB1\xC1R\xD1\xF0$3br\x82      
+%&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz\x83\x84\x85\x86\x87\x88\x89\x8A\x92\x93\x94\x95\x96\x97\x98\x99\x9A\xA2\xA3\xA4\xA5\xA6\xA7\xA8\xA9\xAA\xB2\xB3\xB4\xB5\xB6\xB7\xB8\xB9\xBA\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xD2\xD3\xD4\xD5\xD6\xD7\xD8\xD9\xDA\xE1\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEA\xF1\xF2\xF3\xF4\xF5\xF6\xF7\xF8\xF9\xFA\xFF\xC4 
+ \xFF\xC4\xB5w!1AQaq"2\x81B\x91\xA1\xB1\xC1 #3R\xF0br\xD1
+$4\xE1%\xF1&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz\x82\x83\x84\x85\x86\x87\x88\x89\x8A\x92\x93\x94\x95\x96\x97\x98\x99\x9A\xA2\xA3\xA4\xA5\xA6\xA7\xA8\xA9\xAA\xB2\xB3\xB4\xB5\xB6\xB7\xB8\xB9\xBA\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xD2\xD3\xD4\xD5\xD6\xD7\xD8\xD9\xDA\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEA\xF2\xF3\xF4\xF5\xF6\xF7\xF8\xF9\xFA\xFF\xDA ?\xFE\xFE(\xA0\x80*X\xDF\xD8\xEAv\xC9{\xA6\xDE\xDAjr<\xD1\xC7wcs +ݴ\x92[O%\xB5\xC2$\xF0<\x913\xC1s \xD6\xF3(r\xD1O\x918Y\x94[\xA0\x80
+(\xA0\xCE\xF8+G\xED\x97{\xFB       ~\xC1>9\xF8Vu?\x8B\xF7z5\x9F\xC2\xCF\xD9\xE3\xC36v\xDF\xDA\xB7\x8A\xBFh/\x8B\xB1\xF8#\xE1V\x97\xA4\xE8\xE1^]r}7\xC4:\xB4~+\xD4t\x8Bu7\x9A\x86\xF5\x85\x8B\xA0\x80\xE6\xDB\xFE \xE1\xFF\x82\x80k_>|}\xFF\x82x|]\xD6\xF59\xBE%|\xF16\xB5\xF1\xA3፷\x89\xAE.\x9B\xC47_\xBC\xE2f\x87⿇\xE5\x86\xFD\xBEڳx\xE2\xF6\xA4\xBE!՞\xF4}\xB6]C\xE2\xE4\xB1ɑa \x8C\xFBh\xA0\x80
+(\xA0\xE7{\xF6\x84\x9B\xFE +\xFF\xC6\xFD\x9D?e\xBBC\xFD\xAF\xFB>\xC1'\xBC\xA7\xFEڟ\xB4+\xFB\xFDU\xFD\xAE>&\xD9K\xA3\xFE\xCA\xFE\xD5\xD0y\x8B\xBD\xF0\xFB\xC2\xF3_\xFCc\xD0'\xDBOmy\xAFi\xF7 d\x8A4\xA0\xE5\xAB\xFE
+Q\xA6\xEB?\xF0A_\xF88\xFF\xE1\xE7\xED\xAF\xE0\xAD6\xFBN\xFD\x9D\xBFho\xAF\xC7MkL\xD2-\xE5\xFB\xA5\xE0_\x8B\xF7~\xFD\xAC|\xB4!-/u\x8D_\xBD\xF1\xC4_ +h\xC9\xB4\xD0\xE6\xF1É#\x8Bͱ\x82P\xFE\x94\xBB\xA3x\xA7CѼM\xE1\xCDR\xC7[\xF0\x{1C8D1D};]\xD0u\xAD2\xE2;\xCD7Wѵ{8u +/T\xD3\xEE\xE1g\x86\xEA\xC7P\xB1\xB8\x82\xEE\xD2\xE2&h\xE7\x82X\xE5F*\xC0\x90 +j(\xA0\xFD\xA3~<x\xF6]\xF8\xF1\x8F\xF6\x8B\xF8\xA1}\xFD\x9F\xF0\xFF\xE0\x9FÏ|J\xF1T\xC8\xF1\xAD\xD4\xFA_\x84\xB4[\xBD^M3MYYV\xE7Y\xD6e\xB6\x8BH\xD1,T\x99\xB5 +^\xFA\xCA\xC6\xDD$\x9E\xE24`\xE4\x9B\xFE      I\xA9\xFF\xC1q\xBE\xFC*\xF8\xAD\xFBQ\xF87\xFE \xBF\xF0\xE3\x89\xFF\xE0\xA3_\xAF?m\xFCR\xF8\x93\xFB\\xE9 +\xBCa\xA8\xF8w\xE2~\x8B\xA7j_ \xBC\x9E \x93\xC3z\x95\xE7\x86\xFC\xE0        \xDD\xE1 + P\xBA7\x9Ae\xB6\xBD|\x92[ج\xA9aj\xF2\xF7\xFC7\xF0c\xFE
+\xEF\xFBr\xFE\xC5\xD1\xFCC\xFD\xA4\xBF\xE0\x9B\x9F>蟱ޣ\xE2\x8D\x93|V\xF8]\xFBVh\xBF\xFCk\xA1\xFC=\x9B@}7\xE2~\x88\x9E \xFF\x84oL\xB8\xD4<5yik\xE1\xDF\xF8\x8E{\xB4\xBBӢ\xF0\x9E\xA3\xB6[Kk\xC8e\xFD^\xFF\x83O\xBFo\xFF\xF8k\xCF\xF8&ޗ\xF0'\xC6:\xD7\xF6\x8F\xC5\xFF؋R\xD3~ +\xEA\xB1\xDD\yږ\xA3\xF0sS\xB5\xBC\xD4~k\xD2)c\xE5\xD9\xE9\xDA\x86\xB9\xF0\xC2\xCE5\x84 㹜\x97\xBDW\x90\xFA\x84\xA0\x80
+\xFE!?\xE0\xE4/\xF8+\xCF\xEC\x8B\xF1k\xC5?\xB3\x87\xFC\xD7\xC2?\xFC7\xAC\xFC.\xF8\x83\xFBS\xFC(_\xF8(\xC7\xC4\xEBk\xBE\xF8[\xF0S\xC1t |9\xD4u\xEF \xDB[\xEFY\xEB\xFA\x87\x8C\xFCe\xA4h\x97ZDŽf\xF8m\xA6h\xFA\x9C        \xAE\xCBc\xF6I\xF0G\xE2\x87\xC1/\x8C? <+\xE3\x9F\xD9\xD7\xE2\xC3O\x89\xDF\xAE\xECN\x95\xE0\xDF| \xF1G\x86\xFCa\xF0\xFEkJ\xFA\xBAV\x85\xADxJ\xF7Pж\xE8\xE8\xB7Zu\xAD\xC0}"\xEE\xC6m2\xE6 k\x8BY`\x8C;\xF6\x84\xF8\x87\xFB?\xFC3\xF8C\xE3]{\xF6\xA1\xF1\xF7\xC2χ\xF5-"\xEB\xC2^;\xF1\xC6oxk\xC1_n\xB4\xAF\xC1/\x87\xE6\xF0\xF8\xB3Q\xD2\xF4b<I\xFC\x9A4l\xB7b}V[\xB1ck\xF3̑\xB0\xF9H\xC1?ࡿ       \xFF\xE0\x93\xF0X\xEB?\xC4;\x8F~Þ9\xF8\x83\xF1G\xF6t\xF1\x8F\x8E\xED\xE2\xD4/l\xF5_\x81\xF3x\xF2\xF5>\xFCl\xFE͎\xBD\x9D\xBC9}\xA2\xF8K\xC67\xD3C\xA6\xDCk\x83\xC1\x9A\x8F\x8Ct\xCD2\xCD\xEF\xB5sm(\xFA\xCB|*\xF8\xB3\xF0\xBF\xE3\xA7\xC3\xEF \xFCX\xF8/\xF1\xC1\x9F\xBE\xF8\xCE\xCE{\xFF      \xF8\xFF\xE1\xF7\x894\x9FxC\xC46\x96\xB7\xD7Z]
 \xEC\xBAN\xBF\xA1\xDD\xDE鷦\xC3U\xB0\xBFҵ\xA1\xB8i\xB4\xFDV\xC2\xFBM\xBD\x8E \xEB;\x98"\xF4(\xA0\x80
+(\xA0\x80
+(\xA0\x80
+(\xA0\xFF\xD9
</ins><span class="cx" style="display: block; padding: 0 10px">\ No newline at end of file
</span></span></pre></div>
<a id="branches58testsphpunitdataimagestestimage4pngfromrev51653trunktestsphpunitdataimagestestimage4png"></a>
<div class="copfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Copied: branches/5.8/tests/phpunit/data/images/test-image-4.png (from rev 51653, trunk/tests/phpunit/data/images/test-image-4.png)</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- branches/5.8/tests/phpunit/data/images/test-image-4.png                           (rev 0)
+++ branches/5.8/tests/phpunit/data/images/test-image-4.png     2021-08-31 23:56:11 UTC (rev 51706)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,8 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+\x89PNG
+
+ +IHDR22?\x88\xB1 pHYs  \x9A\x9C\xA5IDATh\x81\xED\x99\xCF+tQƿsg4\xA6\xBB\xB0\x98\xB0\x94Hj\xD2\xCCbDJ\xFC&\xA5\xB0b6\xCA\xDAJI$)6fX\x88\x85Ո\xC8bJ\xD1\xD8X ,\xB8(+\x99[h(\xA6\x8B\x9A0f\x9Ew\xF5\xCE\xDB\xED\xF2\xCE\xFDqn\xEF\xF46O\xDD\xC5=\xF7\x9C\xF3|?\xF79\xD39ݱ\xFD\xE2\xFEu\xACT\xC97@\xF2M\xB5\x8A\xC5bt||l\xB6 +LVgg'\x9CN'\x92ɤ\xA9>\xA6\x82\x88\xA2\xAB\xD5
+"\xC2\xE2⢙V0ui-,,P:\x9D&"\xA2`0H0\xF3a\xD6J&\x93p:\x9D \xA2쵳\xB3c\x96\x9Dy\x89\xAC\xAE\xAE\xD2\xF3\xF3\xB3\xACmvv\xD6,;\xF3\xF1z\xBD\xB24\x88\x8BWWW\xA6\xF8\x99\x92\xC8\xC1\xC1  \x82@\x95\x95\x95\xC4q,P04\xC3ҜDzzz@D\x85B\xF0\xFB\xFD\xB2T\x9E\x9E\x9E\x98{2\xB9\xBF\xBF\x87\xCDf\xCF\xF3\x90$       \xD1hT\xB1Ħ\xA6\xA6X۲a``\x90\xC9dPWW'q\xB9\\xF8\xFC\xFCd\xEA\xCB\xE4\xE3\xE3\xE5\xE5\xE5 "\x9C\x9D\x9De\xDBC\xA1\x90"\x95\x95\x95\x96\xD6lA\xC2\xE10\x88---\xB2vI\x92\xC0\xF3\xBC \xA4\xB1\xB1\x91\xA55[\x90\xA6\xA6&\xC2\xE1\xB0\xE2\xD9\xE0\xE0\xA0"\x95\xFD\xFD}f\xDE\xCC@NNN@D(--\xC5\xFB\xFB\xBB\xE2\xF9\xE5\xE5\xA5\xA4\xAB\xAB\x8B\x95=;\x90\xBE\xBE>\x86\x87\x87\xEC\xD3\xD6\xD6&\xB1Z\xAD\x88\xC5bL\xFC\x99\x80<>>\xC2n\xB7\x83\xE38\x88\xA2\xF8c\xBF\x8D\x8D +E*CCC,J`299   "BGG\xC7_\xFB\xA5R)\xB8\.HII      \xDE\xDE\xDE \xD7`$\x95J\xA1\xA2\xA2D\x84\xED\xED\xED\x9C\xFD'&&\xA9\xCC\xCD\xCD-\xC38\xC8\xEF\x
 E5RSS\x83L&\x93\xB3<GQQ\x91 \xA4\xB6\xB6\xE9t\xDAP6\xA3g\xB5\xF9\xF9y""\xF2x<\xB4\xB9\xB9\xA9j\x8C\xDB\xED&A\xB2\xF7\xD7\xD7״\xB5\xB5E~\xBF_!F\xDE\xC2\xF9\xF9\xB9b\x99\xE8\xBD\xDA\xDB\xDB\xFF]"\xBF\xD3\xF0\xF9|\xD4\xD0Рil$\xA1D"\x91\xBD\xDF\xDB\xDB#A\xC8\xEB\xF5\xEA+F\xEFH$p8\x8As\x95Z\x8D\x8C\x8C(R\xE9\xEF\xEF\xD7[\x8E\xFE\xFB\xCČ\xA13\xD3\xDD\xDDl6\x9B \xC4n\xB7\xE3\xE1\xE1A\xD7|\xBA@\xBE\xBE\xBEPUUe\xF83Ooo\xAF"\x95\xB1\xB11]s\xE9Y__\x81\xE7y\xBC\xBE\xBE\xEA2\x80\xC3\xC3CHYYٷg\xB5\\xD2\xE2\xF3\xF9@Dz\x86\xCB\xE4\xF1x0\xCB\xCB˚\xE7\xD1 \xB2\xBB\xBB\x9B5T\xB3\x93\xE7\xD2\xF4\xF4\xB4\xA4\xBE\xBE^\xF3\xA9\xA4\xB9\xB99\xFBiG\x92$\xAD\xC3\xBA\xB8\xB8\xF8v_Y[[\xD34\x8F&\x90\xA5\xA5\xA5\xAC\xC7qL@DQ\xFC\xA4\xBA\xBA///\xAA\xE7Q\x8F\xC71>>\x8E\xE3df\xDD\xDDݸ\xB9\xB9\xD1 +q{{\x8B@ \xF0\xE3n\xDF\xDAڊ\xA3\xA3#U\xCB,'H4\x85\xC5b\xF9\xEB\xF1\x82\xE7y\x9C\x9E\x9E\xAA\x88D"(..V}|q\xBB\xDD9\xE7\xB4\x8
 5\xFF\xD9\xF3J\x90|S$\xDFT\xC97@\xF2M\xBF]\xC5\xC2\xDA\xC1\xBE\xD6\xC2IEND\xAEB`\x82
</ins><span class="cx" style="display: block; padding: 0 10px">\ No newline at end of file
</span></span></pre></div>
<a id="branches58testsphpunittestsfunctionsphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: branches/5.8/tests/phpunit/tests/functions.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- branches/5.8/tests/phpunit/tests/functions.php    2021-08-31 19:57:20 UTC (rev 51705)
+++ branches/5.8/tests/phpunit/tests/functions.php      2021-08-31 23:56:11 UTC (rev 51706)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -168,13 +168,21 @@
</span><span class="cx" style="display: block; padding: 0 10px">                $testdir = DIR_TESTDATA . '/images/';
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                // Sanity check.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $this->assertSame( 'abcdefg.png', wp_unique_filename( $testdir, 'abcdefg.png' ), 'Sanitiy check failed' );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $this->assertSame( 'abcdefg.png', wp_unique_filename( $testdir, 'abcdefg.png' ), 'Test non-existing file, file name should be unchanged.' );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                // Check number is appended for file already exists.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         // Ensure correct images exist.
</ins><span class="cx" style="display: block; padding: 0 10px">                 $this->assertFileExists( $testdir . 'test-image.png', 'Test image does not exist' );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $this->assertSame( 'test-image-1.png', wp_unique_filename( $testdir, 'test-image.png' ), 'Number not appended correctly' );
</del><span class="cx" style="display: block; padding: 0 10px">                 $this->assertFileNotExists( $testdir . 'test-image-1.png' );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                // Check number is appended if file already exists.
+               $this->assertSame( 'test-image-1.png', wp_unique_filename( $testdir, 'test-image.png' ), 'File name not unique, number not appended.' );
+
+               // Check file with uppercase extension.
+               $this->assertSame( 'test-image-1.png', wp_unique_filename( $testdir, 'test-image.PNG' ), 'File name with uppercase extension not unique, number not appended.' );
+
+               // Check file name with already added number.
+               $this->assertSame( 'test-image-2-1.gif', wp_unique_filename( $testdir, 'test-image-2.gif' ), 'File name not unique, number not appended correctly.' );
+
</ins><span class="cx" style="display: block; padding: 0 10px">                 // Check special chars.
</span><span class="cx" style="display: block; padding: 0 10px">                $this->assertSame( 'testtest-image.png', wp_unique_filename( $testdir, 'testtést-imagé.png' ), 'Filename with special chars failed' );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -222,6 +230,88 @@
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        /**
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         * @ticket 53668
+        */
+       function test_wp_unique_filename_with_additional_image_extension() {
+               $testdir = DIR_TESTDATA . '/images/';
+
+               add_filter( 'upload_dir', array( $this, 'upload_dir_patch_basedir' ) );
+
+               // Set conversions for uploaded images.
+               add_filter( 'image_editor_output_format', array( $this, 'image_editor_output_format_handler' ) );
+
+               // Ensure the test images exist.
+               $this->assertFileExists( $testdir . 'test-image-1-100x100.jpg', 'test-image-1-100x100.jpg does not exist' );
+               $this->assertFileExists( $testdir . 'test-image-2.gif', 'test-image-2.gif does not exist' );
+               $this->assertFileExists( $testdir . 'test-image-3.jpg', 'test-image-3.jpg does not exist' );
+               $this->assertFileExists( $testdir . 'test-image-4.png', 'test-image-4.png does not exist' );
+
+               // Standard test: file does not exist and there are no possible intersections with other files.
+               $this->assertSame(
+                       'abcdef.png',
+                       wp_unique_filename( $testdir, 'abcdef.png' ),
+                       'The abcdef.png, abcdef.gif, and abcdef.jpg images do not exist. The file name should not be changed.'
+               );
+
+               // Actual clash recognized.
+               $this->assertSame(
+                       'canola-1.jpg',
+                       wp_unique_filename( $testdir, 'canola.jpg' ),
+                       'The canola.jpg image exists. The file name should be unique.'
+               );
+
+               // Same name with different extension and the image will be converted.
+               $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.'
+               );
+
+               // Same name with different uppercase extension and the image will be converted.
+               $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.'
+               );
+
+               // Actual clash with several images with different extensions.
+               $this->assertSame(
+                       'test-image-5.png',
+                       wp_unique_filename( $testdir, 'test-image.png' ),
+                       'The test-image.png, test-image-1-100x100.jpg, test-image-2.gif, test-image-3.jpg, and test-image-4.png images exist.' .
+                       'All of them may clash when creating sub-sizes or regenerating thumbnails in the future. The filename should be unique.'
+               );
+
+               // Possible clash with regenerated thumbnails in the future.
+               $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.'
+               );
+
+               remove_filter( 'image_editor_output_format', array( $this, 'image_editor_output_format_handler' ) );
+               remove_filter( 'upload_dir', array( $this, 'upload_dir_patch_basedir' ) );
+       }
+
+       /**
+        * Changes the output format when editing images. When uploading a PNG file
+        * it will be converted to JPEG, GIF to JPEG, and PICT to BMP
+        * (if the image editor in PHP supports it).
+        *
+        * @param array $formats
+        *
+        * @return array
+        */
+       public function image_editor_output_format_handler( $formats ) {
+               $formats['image/png'] = 'image/jpeg';
+               $formats['image/gif'] = 'image/jpeg';
+               $formats['image/pct'] = 'image/bmp';
+
+               return $formats;
+       }
+
+       /**
</ins><span class="cx" style="display: block; padding: 0 10px">          * @dataProvider data_is_not_serialized
</span><span class="cx" style="display: block; padding: 0 10px">         */
</span><span class="cx" style="display: block; padding: 0 10px">        function test_maybe_serialize( $value ) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1921,4 +2011,18 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        array( 'application/activity+json, application/nojson', true ),
</span><span class="cx" style="display: block; padding: 0 10px">                );
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+       /**
+        * @ticket 53668
+        */
+       public function test_wp_get_default_extension_for_mime_type() {
+               $this->assertEquals( 'jpg', wp_get_default_extension_for_mime_type( 'image/jpeg' ), 'jpg not returned as default extension for "image/jpeg"' );
+               $this->assertNotEquals( 'jpeg', wp_get_default_extension_for_mime_type( 'image/jpeg' ), 'jpeg should not be returned as default extension for "image/jpeg"' );
+               $this->assertEquals( 'png', wp_get_default_extension_for_mime_type( 'image/png' ), 'png not returned as default extension for "image/png"' );
+               $this->assertFalse( wp_get_default_extension_for_mime_type( 'wibble/wobble' ), 'false not returned for unrecognized mime type' );
+               $this->assertFalse( wp_get_default_extension_for_mime_type( '' ), 'false not returned when empty string as mime type supplied' );
+               $this->assertFalse( wp_get_default_extension_for_mime_type( '   ' ), 'false not returned when empty string as mime type supplied' );
+               $this->assertFalse( wp_get_default_extension_for_mime_type( 123 ), 'false not returned when int as mime type supplied' );
+               $this->assertFalse( wp_get_default_extension_for_mime_type( null ), 'false not returned when null as mime type supplied' );
+       }
</ins><span class="cx" style="display: block; padding: 0 10px"> }
</span></span></pre>
</div>
</div>

</body>
</html>