Make WordPress Core


Ignore:
Timestamp:
04/02/2019 11:32:31 PM (6 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-includes/functions.php

    r45045 r45104  
    70077007    echo '</p>';
    70087008}
     7009
     7010/**
     7011 * Get the size of a directory.
     7012 *
     7013 * A helper function that is used primarily to check whether
     7014 * a blog has exceeded its allowed upload space.
     7015 *
     7016 * @since MU (3.0.0)
     7017 *
     7018 * @param string $directory Full path of a directory.
     7019 * @param int    $max_execution_time Maximum time to run before giving up. In seconds.
     7020 *                                   The timeout is global and is measured from the moment WordPress started to load.
     7021 * @return int|false|null Size in MB if a valid directory. False if not. Null if timeout.
     7022 */
     7023function get_dirsize( $directory, $max_execution_time = null ) {
     7024    $dirsize = get_transient( 'dirsize_cache' );
     7025
     7026    if ( is_array( $dirsize ) && isset( $dirsize[ $directory ]['size'] ) ) {
     7027        return $dirsize[ $directory ]['size'];
     7028    }
     7029
     7030    if ( ! is_array( $dirsize ) ) {
     7031        $dirsize = array();
     7032    }
     7033
     7034    // Exclude individual site directories from the total when checking the main site of a network
     7035    // as they are subdirectories and should not be counted.
     7036    if ( is_multisite() && is_main_site() ) {
     7037        $dirsize[ $directory ]['size'] = recurse_dirsize( $directory, $directory . '/sites', $max_execution_time );
     7038    } else {
     7039        $dirsize[ $directory ]['size'] = recurse_dirsize( $directory, null, $max_execution_time );
     7040    }
     7041
     7042    set_transient( 'dirsize_cache', $dirsize, HOUR_IN_SECONDS );
     7043    return $dirsize[ $directory ]['size'];
     7044}
     7045
     7046/**
     7047 * Get the size of a directory recursively.
     7048 *
     7049 * Used by get_dirsize() to get a directory's size when it contains
     7050 * other directories.
     7051 *
     7052 * @since MU (3.0.0)
     7053 * @since 4.3.0 $exclude parameter added.
     7054 *
     7055 * @param string $directory Full path of a directory.
     7056 * @param string $exclude   Optional. Full path of a subdirectory to exclude from the total.
     7057 * @param int    $max_execution_time Maximum time to run before giving up. In seconds.
     7058 *                                   The timeout is global and is measured from the moment WordPress started to load.
     7059 * @return int|false|null Size in MB if a valid directory. False if not. Null if timeout.
     7060 */
     7061function recurse_dirsize( $directory, $exclude = null, $max_execution_time = null ) {
     7062    $size = 0;
     7063
     7064    $directory = untrailingslashit( $directory );
     7065
     7066    if ( ! file_exists( $directory ) || ! is_dir( $directory ) || ! is_readable( $directory ) || $directory === $exclude ) {
     7067        return false;
     7068    }
     7069
     7070    if ( ! $max_execution_time ) {
     7071        // Keep the previous behavior but attempt to prevent fatal errors from timeout.
     7072        if ( function_exists( 'ini_get' ) ) {
     7073            $max_execution_time = ini_get( 'max_execution_time' );
     7074        } else {
     7075            // Use PHP default.
     7076            $max_execution_time = 30;
     7077        }
     7078
     7079        // Leave 1 second "buffer" for other operations if $max_execution_time has reasonable value.
     7080        if ( $max_execution_time > 10 ) {
     7081            $max_execution_time -= 1;
     7082        }
     7083    }
     7084
     7085    if ( $handle = opendir( $directory ) ) {
     7086        while ( ( $file = readdir( $handle ) ) !== false ) {
     7087            $path = $directory . '/' . $file;
     7088            if ( $file != '.' && $file != '..' ) {
     7089                if ( is_file( $path ) ) {
     7090                    $size += filesize( $path );
     7091                } elseif ( is_dir( $path ) ) {
     7092                    $handlesize = recurse_dirsize( $path, $exclude, $max_execution_time );
     7093                    if ( $handlesize > 0 ) {
     7094                        $size += $handlesize;
     7095                    }
     7096                }
     7097
     7098                if ( microtime( true ) - WP_START_TIMESTAMP > $max_execution_time ) {
     7099                    // Time exceeded. Give up instead of risking a fatal timeout.
     7100                    $size = null;
     7101                    break;
     7102                }
     7103            }
     7104        }
     7105        closedir( $handle );
     7106    }
     7107    return $size;
     7108}
Note: See TracChangeset for help on using the changeset viewer.