WordPress.org

Make WordPress Core

Ticket #46645: 46645.2.diff

File 46645.2.diff, 13.7 KB (added by azaozz, 6 months ago)

Uh, disabled caching in get_dirsize() to better test it and forgot to enable it in 46645.1.diff. Disregard that diff, this is the proper one to test :)

  • src/wp-admin/includes/class-wp-debug-data.php

     
    312312                        );
    313313                }
    314314
     315                $size_db = WP_Debug_Data::get_database_size();
     316
    315317                // Go through the various installation directories and calculate their sizes.
    316318                $uploads_dir = wp_upload_dir();
    317                 $inaccurate  = false;
    318319
    319320                /*
    320321                 * We will be using the PHP max execution time to prevent the size calculations
    321                  * from causing a timeout. We provide a default value of 30 seconds, as some
     322                 * from causing a timeout. The default value is 30 seconds, and some
    322323                 * hosts do not allow you to read configuration values.
    323324                 */
    324                 $max_execution_time   = 30;
    325                 $start_execution_time = microtime( true );
     325                $max_execution_time = 0;
     326
    326327                if ( function_exists( 'ini_get' ) ) {
    327328                        $max_execution_time = ini_get( 'max_execution_time' );
    328329                }
    329330
     331                // Here 20 seconds is a "sensible default" for how long to make the user wait for the directory size calculation.
     332                // When testing 20 seconds seem enough in nearly all cases. The remaining edge cases are likely testing or development sites
     333                // that have very large number of files, for example `node_modules` in plugins or themes, etc.
     334                if ( ! $max_execution_time || $max_execution_time > 20  ) {
     335                        $max_execution_time = 20;
     336                } else {
     337                        // If the max_execution_time is set to lower than 20 seconds, reduce it a bit to prevent
     338                        // edge-case timeouts that may happen after the size loop has finished running.
     339                        $max_execution_time -= 1;
     340                }
     341
    330342                $size_directories = array(
    331343                        'wordpress' => array(
    332344                                'path' => ABSPATH,
     
    346358                        ),
    347359                );
    348360
     361                $timeout = __( 'The directory size calculation has timed out. Usually caused by a very large number of sub-directories and files.' );
     362                $inaccessible = __( 'The size cannot be calculated. The directory is not accessible. Usually caused by invalid permissions.' );
     363                $size_total = 0;
     364
    349365                // Loop over all the directories we want to gather the sizes for.
    350366                foreach ( $size_directories as $size => $attributes ) {
    351                         /*
    352                          * We run a helper function with a RecursiveIterator, which
    353                          * may throw an exception if it can't access directories.
    354                          *
    355                          * If a failure is detected we mark the result as inaccurate.
    356                          */
    357                         try {
    358                                 $calculated_size = WP_Debug_data::get_directory_size( $attributes['path'], $max_execution_time, $start_execution_time );
     367                        $dir_size = null; // Default to timeout.
     368                        $current_runtime = microtime( true ) - WP_START_TIMESTAMP;
    359369
    360                                 $size_directories[ $size ]['size'] = $calculated_size;
     370                        if ( $max_execution_time > $current_runtime ) {
     371                                $dir_size = get_dirsize( $attributes['path'], $max_execution_time - $current_runtime );
     372                        }
    361373
    362                                 /*
    363                                  * If the size returned is -1, this means execution has
    364                                  * exceeded the maximum execution time, also denoting an
    365                                  * inaccurate value in the end.
    366                                  */
    367                                 if ( -1 === $calculated_size ) {
    368                                         $inaccurate = true;
     374                        if ( $dir_size === false ) {
     375                                // Error reading
     376                                $dir_size = $inaccessible;
     377                                $size_total = null;
     378                        } elseif ( $dir_size === null ) {
     379                                // Timeout
     380                                $dir_size = $timeout;
     381                                $size_total = null;
     382                        } else {
     383                                if ( $size_total !== null ) {
     384                                        $size_total += $dir_size;
    369385                                }
    370                         } catch ( Exception $e ) {
    371                                 $inaccurate = true;
     386
     387                                $dir_size = size_format( $dir_size, 2 );
    372388                        }
     389
     390                        $size_directories[ $size ]['size'] = $dir_size;
    373391                }
    374392
    375                 $size_db = WP_Debug_Data::get_database_size();
     393                if ( $size_total !== null && $size_db > 0 ) {
     394                        $size_total = size_format( $size_total + $size_db, 2 );
     395                } else {
     396                        $size_total = __( 'Total size is not available. Some errors were encountered when determining the size of your installation.' );
     397                }
    376398
    377                 $size_total = $size_directories['wordpress']['size'] + $size_db;
    378 
    379399                $info['wp-paths-sizes']['fields'] = array(
    380400                        array(
    381401                                'label' => __( 'Uploads Directory Location' ),
     
    383403                        ),
    384404                        array(
    385405                                'label' => __( 'Uploads Directory Size' ),
    386                                 'value' => ( -1 === $size_directories['uploads']['size'] ? __( 'Unable to determine the size of this directory' ) : size_format( $size_directories['uploads']['size'], 2 ) ),
     406                                'value' => $size_directories['uploads']['size'],
    387407                        ),
    388408                        array(
    389409                                'label' => __( 'Themes Directory Location' ),
     
    395415                        ),
    396416                        array(
    397417                                'label' => __( 'Themes Directory Size' ),
    398                                 'value' => ( -1 === $size_directories['themes']['size'] ? __( 'Unable to determine the size of this directory' ) : size_format( $size_directories['themes']['size'], 2 ) ),
     418                                'value' => $size_directories['themes']['size'],
    399419                        ),
    400420                        array(
    401421                                'label' => __( 'Plugins Directory Location' ),
     
    403423                        ),
    404424                        array(
    405425                                'label' => __( 'Plugins Directory Size' ),
    406                                 'value' => ( -1 === $size_directories['plugins']['size'] ? __( 'Unable to determine the size of this directory' ) : size_format( $size_directories['plugins']['size'], 2 ) ),
     426                                'value' => $size_directories['plugins']['size'],
    407427                        ),
    408428                        array(
    409429                                'label' => __( 'WordPress Directory Location' ),
     
    411431                        ),
    412432                        array(
    413433                                'label' => __( 'WordPress Directory Size' ),
    414                                 'value' => size_format( $size_directories['wordpress']['size'], 2 ),
     434                                'value' => $size_directories['wordpress']['size'],
    415435                        ),
    416436                        array(
    417437                                'label' => __( 'Database size' ),
     
    419439                        ),
    420440                        array(
    421441                                'label' => __( 'Total installation size' ),
    422                                 'value' => sprintf(
    423                                         '%s%s',
    424                                         size_format( $size_total, 2 ),
    425                                         ( false === $inaccurate ? '' : __( '- Some errors, likely caused by invalid permissions, were encountered when determining the size of your installation. This means the values represented may be inaccurate.' ) )
    426                                 ),
     442                                'value' => $size_total,
    427443                        ),
    428444                );
    429445
     
    933949        }
    934950
    935951        /**
    936          * Return the size of a directory, including all subdirectories.
    937          *
    938          * @since 5.2.0
    939          *
    940          * @param string     $path                 The directory to check.
    941          * @param string|int $max_execution_time   How long a PHP script can run on this host.
    942          * @param float      $start_execution_time When we started executing this section of the script.
    943          *
    944          * @return int The directory size, in bytes.
    945          */
    946         public static function get_directory_size( $path, $max_execution_time, $start_execution_time ) {
    947                 $size = 0;
    948 
    949                 foreach ( new RecursiveIteratorIterator( new RecursiveDirectoryIterator( $path ) ) as $file ) {
    950                         // Check if the maximum execution time is a value considered "infinite".
    951                         if ( 0 !== $max_execution_time && -1 !== $max_execution_time ) {
    952                                 $runtime = ( microtime( true ) - $start_execution_time );
    953 
    954                                 // If the script has been running as long, or longer, as it is allowed, return a failure message.
    955                                 if ( $runtime >= $max_execution_time ) {
    956                                         return -1;
    957                                 }
    958                         }
    959                         $size += $file->getSize();
    960                 }
    961 
    962                 return $size;
    963         }
    964 
    965         /**
    966952         * Fetch the total size of all the database tables for the active database user.
    967953         *
    968954         * @since 5.2.0
     
    980966                        }
    981967                }
    982968
    983                 return $size;
     969                return (int) $size;
    984970        }
    985971}
  • src/wp-includes/default-constants.php

     
    2929        define( 'TB_IN_BYTES', 1024 * GB_IN_BYTES );
    3030        /**#@-*/
    3131
     32        // Start of run timestamp.
     33        if ( ! defined( 'WP_START_TIMESTAMP' ) ) {
     34                define( 'WP_START_TIMESTAMP', microtime( true ) );
     35        }
     36
    3237        $current_limit     = @ini_get( 'memory_limit' );
    3338        $current_limit_int = wp_convert_hr_to_bytes( $current_limit );
    3439
  • src/wp-includes/functions.php

     
    68976897        );
    68986898        echo '</p>';
    68996899}
     6900
     6901/**
     6902 * Get the size of a directory.
     6903 *
     6904 * A helper function that is used primarily to check whether
     6905 * a blog has exceeded its allowed upload space.
     6906 *
     6907 * @since MU (3.0.0)
     6908 *
     6909 * @param string $directory Full path of a directory.
     6910 * @param int    $max_execution_time Maximum time to run before giving up. In seconds.
     6911 * @return int|false|null Size in MB if a valid directory. False if not. Null if timeout.
     6912 */
     6913function get_dirsize( $directory, $max_execution_time = null ) {
     6914        $dirsize = get_transient( 'dirsize_cache' );
     6915        if ( is_array( $dirsize ) && isset( $dirsize[ $directory ]['size'] ) ) {
     6916                return $dirsize[ $directory ]['size'];
     6917        }
     6918
     6919        if ( ! is_array( $dirsize ) ) {
     6920                $dirsize = array();
     6921        }
     6922
     6923        // Exclude individual site directories from the total when checking the main site,
     6924        // as they are subdirectories and should not be counted.
     6925        if ( is_main_site() ) {
     6926                $dirsize[ $directory ]['size'] = recurse_dirsize( $directory, $directory . '/sites', $max_execution_time );
     6927        } else {
     6928                $dirsize[ $directory ]['size'] = recurse_dirsize( $directory, null, $max_execution_time );
     6929        }
     6930
     6931        set_transient( 'dirsize_cache', $dirsize, HOUR_IN_SECONDS );
     6932        return $dirsize[ $directory ]['size'];
     6933}
     6934
     6935/**
     6936 * Get the size of a directory recursively.
     6937 *
     6938 * Used by get_dirsize() to get a directory's size when it contains
     6939 * other directories.
     6940 *
     6941 * @since MU (3.0.0)
     6942 * @since 4.3.0 $exclude parameter added.
     6943 *
     6944 * @param string $directory Full path of a directory.
     6945 * @param string $exclude   Optional. Full path of a subdirectory to exclude from the total.
     6946 * @param int    $max_execution_time Maximum time to run before giving up. In seconds.
     6947 * @return int|false|null Size in MB if a valid directory. False if not. Null if timeout.
     6948 */
     6949function recurse_dirsize( $directory, $exclude = null, $max_execution_time = null ) {
     6950        $size = 0;
     6951
     6952        $directory = untrailingslashit( $directory );
     6953
     6954        if ( ! file_exists( $directory ) || ! is_dir( $directory ) || ! is_readable( $directory ) || $directory === $exclude ) {
     6955                return false;
     6956        }
     6957
     6958        if ( ! $max_execution_time ) {
     6959                // Keep the previous behavior but attempt to prevent fatal errors from timeouts.
     6960                if ( function_exists( 'ini_get' ) ) {
     6961                        $max_execution_time = ini_get( 'max_execution_time' );
     6962                } else {
     6963                        // Use PHP default.
     6964                        $max_execution_time = 30;
     6965                }
     6966
     6967                // Leave 1 second for other operations if $max_execution_time has "reasonable" value.
     6968                if ( $max_execution_time > 10 ) {
     6969                        $max_execution_time -= 1;
     6970                }
     6971        }
     6972
     6973        if ( $handle = opendir( $directory ) ) {
     6974                $timestamp = microtime( true );
     6975
     6976                while ( ( $file = readdir( $handle ) ) !== false ) {
     6977                        $path = $directory . '/' . $file;
     6978                        if ( $file != '.' && $file != '..' ) {
     6979                                if ( is_file( $path ) ) {
     6980                                        $size += filesize( $path );
     6981                                } elseif ( is_dir( $path ) ) {
     6982                                        $passed_time = microtime( true ) - $timestamp;
     6983                                        $handlesize = recurse_dirsize( $path, $exclude, $max_execution_time - $passed_time );
     6984                                        if ( $handlesize > 0 ) {
     6985                                                $size += $handlesize;
     6986                                        }
     6987                                }
     6988
     6989                                if ( microtime( true ) - $timestamp > $max_execution_time ) {
     6990                                        // Time exceeded. Give up instead of risking a fatal timeout.
     6991                                        $size = null;
     6992                                        break;
     6993                                }
     6994                        }
     6995                }
     6996                closedir( $handle );
     6997        }
     6998        return $size;
     6999}
  • src/wp-includes/ms-functions.php

     
    17781778// Misc functions
    17791779
    17801780/**
    1781  * Get the size of a directory.
    1782  *
    1783  * A helper function that is used primarily to check whether
    1784  * a blog has exceeded its allowed upload space.
    1785  *
    1786  * @since MU (3.0.0)
    1787  *
    1788  * @param string $directory Full path of a directory.
    1789  * @return int Size of the directory in MB.
    1790  */
    1791 function get_dirsize( $directory ) {
    1792         $dirsize = get_transient( 'dirsize_cache' );
    1793         if ( is_array( $dirsize ) && isset( $dirsize[ $directory ]['size'] ) ) {
    1794                 return $dirsize[ $directory ]['size'];
    1795         }
    1796 
    1797         if ( ! is_array( $dirsize ) ) {
    1798                 $dirsize = array();
    1799         }
    1800 
    1801         // Exclude individual site directories from the total when checking the main site,
    1802         // as they are subdirectories and should not be counted.
    1803         if ( is_main_site() ) {
    1804                 $dirsize[ $directory ]['size'] = recurse_dirsize( $directory, $directory . '/sites' );
    1805         } else {
    1806                 $dirsize[ $directory ]['size'] = recurse_dirsize( $directory );
    1807         }
    1808 
    1809         set_transient( 'dirsize_cache', $dirsize, HOUR_IN_SECONDS );
    1810         return $dirsize[ $directory ]['size'];
    1811 }
    1812 
    1813 /**
    1814  * Get the size of a directory recursively.
    1815  *
    1816  * Used by get_dirsize() to get a directory's size when it contains
    1817  * other directories.
    1818  *
    1819  * @since MU (3.0.0)
    1820  * @since 4.3.0 $exclude parameter added.
    1821  *
    1822  * @param string $directory Full path of a directory.
    1823  * @param string $exclude   Optional. Full path of a subdirectory to exclude from the total.
    1824  * @return int|false Size in MB if a valid directory. False if not.
    1825  */
    1826 function recurse_dirsize( $directory, $exclude = null ) {
    1827         $size = 0;
    1828 
    1829         $directory = untrailingslashit( $directory );
    1830 
    1831         if ( ! file_exists( $directory ) || ! is_dir( $directory ) || ! is_readable( $directory ) || $directory === $exclude ) {
    1832                 return false;
    1833         }
    1834 
    1835         if ( $handle = opendir( $directory ) ) {
    1836                 while ( ( $file = readdir( $handle ) ) !== false ) {
    1837                         $path = $directory . '/' . $file;
    1838                         if ( $file != '.' && $file != '..' ) {
    1839                                 if ( is_file( $path ) ) {
    1840                                         $size += filesize( $path );
    1841                                 } elseif ( is_dir( $path ) ) {
    1842                                         $handlesize = recurse_dirsize( $path, $exclude );
    1843                                         if ( $handlesize > 0 ) {
    1844                                                 $size += $handlesize;
    1845                                         }
    1846                                 }
    1847                         }
    1848                 }
    1849                 closedir( $handle );
    1850         }
    1851         return $size;
    1852 }
    1853 
    1854 /**
    18551781 * Check an array of MIME types against a whitelist.
    18561782 *
    18571783 * WordPress ships with a set of allowed upload filetypes,