diff --git a/wp-admin/includes/class-wp-debug-data.php b/wp-admin/includes/class-wp-debug-data.php index 5c3034ce39..692fd0b559 100644 --- a/wp-admin/includes/class-wp-debug-data.php +++ b/wp-admin/includes/class-wp-debug-data.php @@ -581,6 +581,7 @@ class WP_Debug_Data { 'map' => ( defined( 'imagick::RESOURCETYPE_MAP' ) ? size_format( $imagick->getResourceLimit( imagick::RESOURCETYPE_MAP ) ) : $not_available ), 'memory' => ( defined( 'imagick::RESOURCETYPE_MEMORY' ) ? size_format( $imagick->getResourceLimit( imagick::RESOURCETYPE_MEMORY ) ) : $not_available ), 'thread' => ( defined( 'imagick::RESOURCETYPE_THREAD' ) ? $imagick->getResourceLimit( imagick::RESOURCETYPE_THREAD ) : $not_available ), + 'time' => ( defined( 'imagick::RESOURCETYPE_TIME' ) ? $imagick->getResourceLimit( imagick::RESOURCETYPE_TIME ) : $not_available ), ); $limits_debug = array( @@ -590,6 +591,7 @@ class WP_Debug_Data { 'imagick::RESOURCETYPE_MAP' => ( defined( 'imagick::RESOURCETYPE_MAP' ) ? size_format( $imagick->getResourceLimit( imagick::RESOURCETYPE_MAP ) ) : 'not available' ), 'imagick::RESOURCETYPE_MEMORY' => ( defined( 'imagick::RESOURCETYPE_MEMORY' ) ? size_format( $imagick->getResourceLimit( imagick::RESOURCETYPE_MEMORY ) ) : 'not available' ), 'imagick::RESOURCETYPE_THREAD' => ( defined( 'imagick::RESOURCETYPE_THREAD' ) ? $imagick->getResourceLimit( imagick::RESOURCETYPE_THREAD ) : 'not available' ), + 'imagick::RESOURCETYPE_TIME' => ( defined( 'imagick::RESOURCETYPE_TIME' ) ? $imagick->getResourceLimit( imagick::RESOURCETYPE_TIME ) : 'not available' ), ); $info['wp-media']['fields']['imagick_limits'] = array( diff --git a/wp-includes/class-wp-image-editor-imagick.php b/wp-includes/class-wp-image-editor-imagick.php index 40e3cbb823..69ab7b176c 100644 --- a/wp-includes/class-wp-image-editor-imagick.php +++ b/wp-includes/class-wp-image-editor-imagick.php @@ -253,6 +253,50 @@ class WP_Image_Editor_Imagick extends WP_Image_Editor { return parent::update_size( $width, $height ); } + /** + * Sets Imagick time limit. + * + * Depending on configuration, Imagick processing may take time. + * + * Multiple problems exist if PHP times out before ImageMagick completed: + * 1. Temporary files aren't cleaned by ImageMagick garbage collection. + * 2. No clear error is provided. + * 3. The cause of such timeout can be hard to pinpoint. + * + * This function, which is expected to be run before heavy image routines, resolves + * point 1 above by aligning Imagick's timeout with PHP's timeout, assuming it is set. + * + * Note: + * - Imagick resource exhaustion does not issue catchable exceptions (yet). + * See https://github.com/Imagick/imagick/issues/333. + * - The resource limit is not saved/restored. It applies to subsequent + * image operations within the time of the HTTP request. + * + * @since 6.2.0 + * + * @return int|null The new limit on success, null on failure. + */ + public static function set_imagick_time_limit() { + if ( ! defined( 'Imagick::RESOURCETYPE_TIME' ) ) { + return null; + } + + // Returns PHP_FLOAT_MAX if unset. + $imagick_timeout = Imagick::getResourceLimit( Imagick::RESOURCETYPE_TIME ); + + // Convert to an integer, keeping in mind that: 0 === (int) PHP_FLOAT_MAX. + $imagick_timeout = $imagick_timeout > PHP_INT_MAX ? PHP_INT_MAX : (int) $imagick_timeout; + + $php_timeout = (int) ini_get( 'max_execution_time' ); + + if ( $php_timeout > 1 && $php_timeout < $imagick_timeout ) { + $limit = (float) 0.8 * $php_timeout; + Imagick::setResourceLimit( Imagick::RESOURCETYPE_TIME, $limit ); + + return $limit; + } + } + /** * Resizes current image. * @@ -283,6 +327,8 @@ class WP_Image_Editor_Imagick extends WP_Image_Editor { return $this->crop( $src_x, $src_y, $src_w, $src_h, $dst_w, $dst_h ); } + self::set_imagick_time_limit(); + // Execute the resize. $thumb_result = $this->thumbnail_image( $dst_w, $dst_h ); if ( is_wp_error( $thumb_result ) ) { @@ -549,6 +595,8 @@ class WP_Image_Editor_Imagick extends WP_Image_Editor { $src_h -= $src_y; } + self::set_imagick_time_limit(); + try { $this->image->cropImage( $src_w, $src_h, $src_x, $src_y ); $this->image->setImagePage( $src_w, $src_h, 0, 0 ); diff --git a/wp-includes/version.php b/wp-includes/version.php index a8ee8af1bd..3aa8efcf29 100644 --- a/wp-includes/version.php +++ b/wp-includes/version.php @@ -16,7 +16,7 @@ * * @global string $wp_version */ -$wp_version = '6.2-beta3-55402'; +$wp_version = '6.2-beta3-55404'; /** * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.