Make WordPress Core


Ignore:
Timestamp:
04/02/2019 11:32:31 PM (8 years ago)
Author:
azaozz
Message:

Site health:

  • Prevent fatal errors from timeouts on the Tools => Site Health => Info tab.
  • Use the get_dirsize() and recurse_dirsize() functions to calculate directory sizes. The results are cached.
  • Introduce "timeout protection" in recurse_dirsize().

Props pento, Clorith, xkon, afercia, jeremyfelt, azaozz.
Fixes #46645.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-admin/includes/class-wp-debug-data.php

    r45102 r45104  
    3333        static function debug_data( $locale = null ) {
    3434                global $wpdb;
    35 
    3635                if ( ! empty( $locale ) ) {
    3736                        // Change the language used for translations
    … …  
    313312                }
    314313
     314                $size_db = WP_Debug_Data::get_database_size();
     315
    315316                // Go through the various installation directories and calculate their sizes.
    316317                $uploads_dir = wp_upload_dir();
    317                 $inaccurate  = false;
    318318
    319319                /*
    320320                 * 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
     321                 * from causing a timeout. The default value is 30 seconds, and some
    322322                 * hosts do not allow you to read configuration values.
    323323                 */
    324                 $max_execution_time   = 30;
    325                 $start_execution_time = microtime( true );
     324                $max_execution_time = 30;
     325
    326326                if ( function_exists( 'ini_get' ) ) {
    327327                        $max_execution_time = ini_get( 'max_execution_time' );
     328                }
     329
     330                // Here 20 seconds is a "sensible default" for how long to make the user wait for the directory size calculation.
     331                // When testing 20 seconds seem enough in nearly all cases. The remaining edge cases are likely testing or development sites
     332                // that have very large number of files, for example `node_modules` in plugins or themes, etc.
     333                if ( $max_execution_time > 20  ) {
     334                        $max_execution_time = 20;
     335                } elseif ( $max_execution_time > 2 ) {
     336                        // If the max_execution_time is set to lower than 20 seconds, reduce it a bit to prevent
     337                        // edge-case timeouts that may happen after the size loop has finished running.
     338                        $max_execution_time -= 1;
    328339                }
    329340
    … …  
    347358                );
    348359
     360                $timeout = __( 'The directory size calculation has timed out. Usually caused by a very large number of sub-directories and files.' );
     361                $inaccessible = __( 'The size cannot be calculated. The directory is not accessible. Usually caused by invalid permissions.' );
     362                $size_total = 0;
     363
    349364                // Loop over all the directories we want to gather the sizes for.
    350365                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 );
    359 
    360                                 $size_directories[ $size ]['size'] = $calculated_size;
    361 
    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;
     366                        $dir_size = null; // Default to timeout.
     367
     368                        if ( microtime( true ) - WP_START_TIMESTAMP < $max_execution_time ) {
     369                                $dir_size = get_dirsize( $attributes['path'], $max_execution_time );
     370                        }
     371
     372                        if ( $dir_size === false ) {
     373                                // Error reading
     374                                $dir_size = $inaccessible;
     375                                $size_total = null;
     376                        } elseif ( $dir_size === null ) {
     377                                // Timeout
     378                                $dir_size = $timeout;
     379                                $size_total = null;
     380                        } else {
     381                                $is_subdir = ( strpos( $size_directories[ $size ]['path'], ABSPATH ) === 0 );
     382
     383                                if ( $size_total !== null && ( $size === 'wordpress' || ! $is_subdir ) ) {
     384                                        $size_total += $dir_size;
    369385                                }
    370                         } catch ( Exception $e ) {
    371                                 $inaccurate = true;
    372                         }
    373                 }
    374 
    375                 $size_db = WP_Debug_Data::get_database_size();
    376 
    377                 $size_total = $size_directories['wordpress']['size'] + $size_db;
     386
     387                                $dir_size = size_format( $dir_size, 2 );
     388                        }
     389
     390                        $size_directories[ $size ]['size'] = $dir_size;
     391                }
     392
     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                }
    378398
    379399                $info['wp-paths-sizes']['fields'] = array(
    … …  
    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(
    … …  
    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(
    … …  
    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(
    … …  
    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(
    … …  
    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                );
    … …  
    936952
    937953        /**
    938          * Return the size of a directory, including all subdirectories.
    939          *
    940          * @since 5.2.0
    941          *
    942          * @param string     $path                 The directory to check.
    943          * @param string|int $max_execution_time   How long a PHP script can run on this host.
    944          * @param float      $start_execution_time When we started executing this section of the script.
    945          *
    946          * @return int The directory size, in bytes.
    947          */
    948         public static function get_directory_size( $path, $max_execution_time, $start_execution_time ) {
    949                 $size = 0;
    950 
    951                 foreach ( new RecursiveIteratorIterator( new RecursiveDirectoryIterator( $path ) ) as $file ) {
    952                         // Check if the maximum execution time is a value considered "infinite".
    953                         if ( 0 !== $max_execution_time && -1 !== $max_execution_time ) {
    954                                 $runtime = ( microtime( true ) - $start_execution_time );
    955 
    956                                 // If the script has been running as long, or longer, as it is allowed, return a failure message.
    957                                 if ( $runtime >= $max_execution_time ) {
    958                                         return -1;
    959                                 }
    960                         }
    961                         $size += $file->getSize();
    962                 }
    963 
    964                 return $size;
    965         }
    966 
    967         /**
    968954         * Fetch the total size of all the database tables for the active database user.
    969955         *
    … …  
    983969                }
    984970
    985                 return $size;
     971                return (int) $size;
    986972        }
    987973}
Note: See TracChangeset for help on using the changeset viewer.