<!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>[49745] branches/5.6: Multisite: Cache absolute `dirsize` paths to avoid PHP 8 fatal.</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/49745">49745</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/49745","name":"Review Commit"}}</script></dd>
<dt style="float: left; width: 6em; font-weight: bold">Author</dt> <dd>iandunn</dd>
<dt style="float: left; width: 6em; font-weight: bold">Date</dt> <dd>2020-12-03 20:43:53 +0000 (Thu, 03 Dec 2020)</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'>Multisite: Cache absolute `dirsize` paths to avoid PHP 8 fatal.

<a href="https://core.trac.wordpress.org/changeset/49212">r49212</a> greatly improved the performance of `get_dirsize()`, but also changed the structure of the data stored in the `dirsize_cache` transient. It stored relative paths instead of absolute ones, and also removed the unnecessary `size` array.

That difference in data structures led to a fatal error in the following environment:

* PHP 8
* Multisite
* A custom `WP_CONTENT_DIR` which is not a child of WP's `ABSPATH` folder (e.g., [https://roots.io/bedrock/ Bedrock])
* The `upload_space_check_disabled` option set to `0`

After upgrading to WP 5.6, the `dirsize_cache` transient still had data in the old format. When `wp-admin.php/index.php` was visited, `get_space_used()` received an `array` instead of an `int`, and tried to divide it by another `int`. PHP 7 would silently cast the arguments to match data types, but [https://wiki.php.net/rfc/arithmetic_operator_type_checks PHP 8 throws a fatal error]: 

`Uncaught TypeError: Unsupported operand types: array / int`

`recurse_dirsize()` was using `ABSPATH` to convert the absolute paths to relative ones, but some upload locations are not located under `ABSPATH`. In those cases, `$directory` and `$cache_path` were identical, and that triggered the early return of the old `array`, instead of the expected `int`. 

In order to avoid that, this commit restores the absolute paths, but without the `size` array. It also adds a type check when returning cached values. Using absolute paths without `size` has the result of overwriting the old data, so that it matches the new format. The type check and upgrade routine are additional safety measures.

Props peterwilsoncc, janthiel, helen, hellofromtonya, francina, pbiron.
Reviewed by SergeyBiryukov, iandunn.
Merges <a href="https://core.trac.wordpress.org/changeset/49744">[49744]</a> to the 5.6 branch.
Fixes <a href="https://core.trac.wordpress.org/ticket/51913">#51913</a>. See <a href="https://core.trac.wordpress.org/ticket/19879">#19879</a>.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#branches56srcwpadminincludesupgradephp">branches/5.6/src/wp-admin/includes/upgrade.php</a></li>
<li><a href="#branches56srcwpincludesfunctionsphp">branches/5.6/src/wp-includes/functions.php</a></li>
<li><a href="#branches56srcwpincludesversionphp">branches/5.6/src/wp-includes/version.php</a></li>
<li><a href="#branches56testsphpunittestsmultisitecleanDirsizeCachephp">branches/5.6/tests/phpunit/tests/multisite/cleanDirsizeCache.php</a></li>
</ul>

<h3>Property Changed</h3>
<ul>
<li><a href="#branches56">branches/5.6/</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<span class="cx" style="display: block; padding: 0 10px">Index: branches/5.6
</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.6 2020-12-03 20:37:43 UTC (rev 49744)
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+++ branches/5.6  2020-12-03 20:43:53 UTC (rev 49745)
</ins><a id="branches56"></a>
<div class="propset"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Property changes: branches/5.6</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:49645,49649-49651,49668,49673-49674,49677,49681,49685,49691,49702-49705,49708-49710,49713,49716,49718,49720,49722,49725-49726,49731,49736-49737,49739,49741
</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:49645,49649-49651,49668,49673-49674,49677,49681,49685,49691,49702-49705,49708-49710,49713,49716,49718,49720,49722,49725-49726,49731,49736-49737,49739,49741,49744
</ins><span class="cx" style="display: block; padding: 0 10px">\ No newline at end of property
</span><a id="branches56srcwpadminincludesupgradephp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: branches/5.6/src/wp-admin/includes/upgrade.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- branches/5.6/src/wp-admin/includes/upgrade.php    2020-12-03 20:37:43 UTC (rev 49744)
+++ branches/5.6/src/wp-admin/includes/upgrade.php      2020-12-03 20:43:53 UTC (rev 49745)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -874,7 +874,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                upgrade_550();
</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">-        if ( $wp_current_db_version < 49632 ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ if ( $wp_current_db_version < 49735 ) {
</ins><span class="cx" style="display: block; padding: 0 10px">                 upgrade_560();
</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">@@ -2274,6 +2274,10 @@
</span><span class="cx" style="display: block; padding: 0 10px">                 */
</span><span class="cx" style="display: block; padding: 0 10px">                save_mod_rewrite_rules();
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+       if ( $wp_current_db_version < 49735 ) {
+               delete_transient( 'dirsize_cache' );
+       }
</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="branches56srcwpincludesfunctionsphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: branches/5.6/src/wp-includes/functions.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- branches/5.6/src/wp-includes/functions.php        2020-12-03 20:37:43 UTC (rev 49744)
+++ branches/5.6/src/wp-includes/functions.php  2020-12-03 20:43:53 UTC (rev 49745)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -7626,8 +7626,6 @@
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> function recurse_dirsize( $directory, $exclude = null, $max_execution_time = null, &$directory_cache = null ) {
</span><span class="cx" style="display: block; padding: 0 10px">        $directory  = untrailingslashit( $directory );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        $cache_path = untrailingslashit( str_replace( ABSPATH, '', $directory ) );
-
</del><span class="cx" style="display: block; padding: 0 10px">         $save_cache = false;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        if ( ! isset( $directory_cache ) ) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -7635,8 +7633,8 @@
</span><span class="cx" style="display: block; padding: 0 10px">                $save_cache      = true;
</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">-        if ( isset( $directory_cache[ $cache_path ] ) ) {
-               return $directory_cache[ $cache_path ];
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ if ( isset( $directory_cache[ $directory ] ) && is_int( $directory_cache[ $directory ] ) ) {
+               return $directory_cache[ $directory ];
</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">        if ( ! file_exists( $directory ) || ! is_dir( $directory ) || ! is_readable( $directory ) ) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -7705,7 +7703,7 @@
</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><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        $directory_cache[ $cache_path ] = $size;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $directory_cache[ $directory ] = $size;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        // Only write the transient on the top level call and not on recursive calls.
</span><span class="cx" style="display: block; padding: 0 10px">        if ( $save_cache ) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -7731,12 +7729,12 @@
</span><span class="cx" style="display: block; padding: 0 10px">                return;
</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">-        $cache_path = untrailingslashit( str_replace( ABSPATH, '', $path ) );
-       unset( $directory_cache[ $cache_path ] );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $path = untrailingslashit( $path );
+       unset( $directory_cache[ $path ] );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        while ( DIRECTORY_SEPARATOR !== $cache_path && '.' !== $cache_path && '..' !== $cache_path ) {
-               $cache_path = dirname( $cache_path );
-               unset( $directory_cache[ $cache_path ] );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ while ( DIRECTORY_SEPARATOR !== $path && '.' !== $path && '..' !== $path ) {
+               $path = dirname( $path );
+               unset( $directory_cache[ $path ] );
</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">        set_transient( 'dirsize_cache', $directory_cache );
</span></span></pre></div>
<a id="branches56srcwpincludesversionphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: branches/5.6/src/wp-includes/version.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- branches/5.6/src/wp-includes/version.php  2020-12-03 20:37:43 UTC (rev 49744)
+++ branches/5.6/src/wp-includes/version.php    2020-12-03 20:43:53 UTC (rev 49745)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -20,7 +20,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * @global int $wp_db_version
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-$wp_db_version = 49632;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+$wp_db_version = 49735;
</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">  * Holds the TinyMCE version.
</span></span></pre></div>
<a id="branches56testsphpunittestsmultisitecleanDirsizeCachephp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: branches/5.6/tests/phpunit/tests/multisite/cleanDirsizeCache.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- branches/5.6/tests/phpunit/tests/multisite/cleanDirsizeCache.php  2020-12-03 20:37:43 UTC (rev 49744)
+++ branches/5.6/tests/phpunit/tests/multisite/cleanDirsizeCache.php    2020-12-03 20:43:53 UTC (rev 49745)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -93,7 +93,7 @@
</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">                        $upload_dir       = wp_upload_dir();
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        $cache_key_prefix = untrailingslashit( str_replace( ABSPATH, '', $upload_dir['basedir'] ) );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 $cache_key_prefix = untrailingslashit( $upload_dir['basedir'] );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                        // Clear the dirsize cache.
</span><span class="cx" style="display: block; padding: 0 10px">                        delete_transient( 'dirsize_cache' );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -141,7 +141,7 @@
</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">                        $upload_dir       = wp_upload_dir();
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        $cache_key_prefix = untrailingslashit( str_replace( ABSPATH, '', $upload_dir['basedir'] ) );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 $cache_key_prefix = untrailingslashit( $upload_dir['basedir'] );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                        // Clear the dirsize cache.
</span><span class="cx" style="display: block; padding: 0 10px">                        delete_transient( 'dirsize_cache' );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -205,7 +205,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        $this->assertSame( $size, $calc_size );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                        // `dirsize_cache` should now be filled after upload and recurse_dirsize() call.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        $cache_path = untrailingslashit( str_replace( ABSPATH, '', $upload_dir['path'] ) );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 $cache_path = untrailingslashit( $upload_dir['path'] );
</ins><span class="cx" style="display: block; padding: 0 10px">                         $this->assertSame( true, is_array( get_transient( 'dirsize_cache' ) ) );
</span><span class="cx" style="display: block; padding: 0 10px">                        $this->assertSame( $size, get_transient( 'dirsize_cache' )[ $cache_path ] );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -233,17 +233,100 @@
</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">                function _get_mock_dirsize_cache_for_site( $site_id ) {
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                        $prefix = wp_upload_dir()['basedir'];
+
</ins><span class="cx" style="display: block; padding: 0 10px">                         return array(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                "wp-content/uploads/sites/$site_id/2/2" => 22,
-                               "wp-content/uploads/sites/$site_id/2/1" => 21,
-                               "wp-content/uploads/sites/$site_id/2"   => 2,
-                               "wp-content/uploads/sites/$site_id/1/3" => 13,
-                               "wp-content/uploads/sites/$site_id/1/2" => 12,
-                               "wp-content/uploads/sites/$site_id/1/1" => 11,
-                               "wp-content/uploads/sites/$site_id/1"   => 1,
-                               "wp-content/uploads/sites/$site_id/custom_directory" => 42,
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         "$prefix/2/2"              => 22,
+                               "$prefix/2/1"              => 21,
+                               "$prefix/2"                => 2,
+                               "$prefix/1/3"              => 13,
+                               "$prefix/1/2"              => 12,
+                               "$prefix/1/1"              => 11,
+                               "$prefix/1"                => 1,
+                               "$prefix/custom_directory" => 42,
</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">+
+               /*
+                * Test that 5.6+ gracefully handles the old 5.5 transient structure.
+                *
+                * @ticket 51913
+                */
+               function test_5_5_transient_structure_compat() {
+                       $blog_id = self::factory()->blog->create();
+                       switch_to_blog( $blog_id );
+
+                       /*
+                        * Our comparison of space relies on an initial value of 0. If a previous test has failed
+                        * or if the `src` directory already contains a directory with site content, then the initial
+                        * expectation will be polluted. We create sites until an empty one is available.
+                        */
+                       while ( 0 !== get_space_used() ) {
+                               restore_current_blog();
+                               $blog_id = self::factory()->blog->create();
+                               switch_to_blog( $blog_id );
+                       }
+
+                       // Clear the dirsize cache.
+                       delete_transient( 'dirsize_cache' );
+
+                       // Set the dirsize cache to our mock.
+                       set_transient( 'dirsize_cache', $this->_get_mock_5_5_dirsize_cache( $blog_id ) );
+
+                       $upload_dir = wp_upload_dir();
+
+                       /*
+                        * The cached size should be ignored, because it's in the old format. The function
+                        * will try to fetch a live value, but in this case the folder doesn't actually
+                        * exist on disk, so the function should fail.
+                        */
+                       $this->assertSame( false, recurse_dirsize( $upload_dir['basedir'] . '/2/1' ) );
+
+                       /*
+                        * Now that it's confirmed that old cached values aren't being returned, create the
+                        * folder on disk, so that the the rest of the function can be tested.
+                        */
+                       wp_mkdir_p( $upload_dir['basedir'] . '/2/1' );
+                       $filename = $upload_dir['basedir'] . '/2/1/this-needs-to-exist.txt';
+                       file_put_contents( $filename, 'this file is 21 bytes' );
+
+                       // Clear the dirsize cache.
+                       delete_transient( 'dirsize_cache' );
+
+                       // Set the dirsize cache to our mock.
+                       set_transient( 'dirsize_cache', $this->_get_mock_5_5_dirsize_cache( $blog_id ) );
+
+                       /*
+                        * Now that the folder exists, the old cached value should be overwritten
+                        * with the size, using the current format.
+                        */
+                       $this->assertSame( 21, recurse_dirsize( $upload_dir['basedir'] . '/2/1' ) );
+                       $this->assertSame( 21, get_transient( 'dirsize_cache' )[ $upload_dir['basedir'] . '/2/1' ] );
+
+                       // No cache match on non existing directory should return false.
+                       $this->assertSame( false, recurse_dirsize( $upload_dir['basedir'] . '/does_not_exist' ) );
+
+                       // Cleanup.
+                       $this->remove_added_uploads();
+                       rmdir( $upload_dir['basedir'] . '/2/1' );
+
+                       restore_current_blog();
+               }
+
+               function _get_mock_5_5_dirsize_cache( $site_id ) {
+                       $prefix = untrailingslashit( wp_upload_dir()['basedir'] );
+
+                       return array(
+                               "$prefix/2/2"              => array( 'size' => 22 ),
+                               "$prefix/2/1"              => array( 'size' => 21 ),
+                               "$prefix/2"                => array( 'size' => 2 ),
+                               "$prefix/1/3"              => array( 'size' => 13 ),
+                               "$prefix/1/2"              => array( 'size' => 12 ),
+                               "$prefix/1/1"              => array( 'size' => 11 ),
+                               "$prefix/1"                => array( 'size' => 1 ),
+                               "$prefix/custom_directory" => array( 'size' => 42 ),
+                       );
+               }
</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"> endif;
</span></span></pre>
</div>
</div>

</body>
</html>