Make WordPress Core

Changeset 55348


Ignore:
Timestamp:
02/15/2023 09:30:20 PM (2 years ago)
Author:
antpb
Message:

Media: Add setImagickTimeLimit() function to avoid timeout in Imagick operations.

Previously, Imagick operations could silently error by timeout and produce unexpected results. The new setImagickTimeLimit() function will better handle garbage collection in these cases as well as better align Imagick's timeout with PHP timeout, assuming it is set.

Props drzraf, audrasjb, costdev.
Fixes #52569.

Location:
branches/6.1/src
Files:
2 edited

Legend:

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

    r54239 r55348  
    581581                'memory' => ( defined( 'imagick::RESOURCETYPE_MEMORY' ) ? size_format( $imagick->getResourceLimit( imagick::RESOURCETYPE_MEMORY ) ) : $not_available ),
    582582                'thread' => ( defined( 'imagick::RESOURCETYPE_THREAD' ) ? $imagick->getResourceLimit( imagick::RESOURCETYPE_THREAD ) : $not_available ),
     583                'time'   => ( defined( 'imagick::RESOURCETYPE_TIME' ) ? $imagick->getResourceLimit( imagick::RESOURCETYPE_TIME ) : $not_available ),
    583584            );
    584585
     
    590591                'imagick::RESOURCETYPE_MEMORY' => ( defined( 'imagick::RESOURCETYPE_MEMORY' ) ? size_format( $imagick->getResourceLimit( imagick::RESOURCETYPE_MEMORY ) ) : 'not available' ),
    591592                'imagick::RESOURCETYPE_THREAD' => ( defined( 'imagick::RESOURCETYPE_THREAD' ) ? $imagick->getResourceLimit( imagick::RESOURCETYPE_THREAD ) : 'not available' ),
     593                'imagick::RESOURCETYPE_TIME'   => ( defined( 'imagick::RESOURCETYPE_TIME' ) ? $imagick->getResourceLimit( imagick::RESOURCETYPE_TIME ) : 'not available' ),
    592594            );
    593595
  • branches/6.1/src/wp-includes/class-wp-image-editor-imagick.php

    r54226 r55348  
    255255
    256256    /**
     257     * Depending on configuration, Imagick processing may take time.
     258     *
     259     * Multiple problems exist if PHP timeouts before ImageMagick completed:
     260     * 1. Temporary files aren't cleaned by ImageMagick garbage collection.
     261     * 2. No clear error is provided.
     262     * 3. The cause of such timeout can be hard to pinpoint.
     263     *
     264     * This function, which is expected to be run before heavy image routines, resolves
     265     * point 1 above by aligning Imagick's timeout with PHP's timeout, assuming it's set.
     266     *
     267     * Note: Imagick resource exhaustion does not issue catchable exceptions (yet)
     268     *       See https://github.com/Imagick/imagick/issues/333
     269     * Note: The resource limit isn't saved/restored. It applies to
     270     *       subsequent image operations within the time of the HTTP request.
     271     *
     272     * @since 6.2.0
     273     *
     274     * @return int|null Whether the new limit or null if none was set
     275     */
     276    public static function setImagickTimeLimit() {
     277        if ( ! defined( 'Imagick::RESOURCETYPE_TIME' ) ) {
     278            return null;
     279        }
     280
     281        // Returns PHP_FLOAT_MAX if unset.
     282        $imagick_timeout = Imagick::getResourceLimit( Imagick::RESOURCETYPE_TIME );
     283
     284        // Convert to an integer, keeping in mind that: 0 === (int) PHP_FLOAT_MAX.
     285        $imagick_timeout = $imagick_timeout > PHP_INT_MAX ? PHP_INT_MAX : (int) $imagick_timeout;
     286
     287        $php_timeout = intval( ini_get( 'max_execution_time' ) );
     288
     289        if ( $php_timeout > 1 && $php_timeout < $imagick_timeout ) {
     290            // $limit = $php_timeout - 1;
     291            $limit = floatval( 0.8 * $php_timeout );
     292            Imagick::setResourceLimit( Imagick::RESOURCETYPE_TIME, $limit );
     293
     294            return $limit;
     295        }
     296    }
     297
     298    /**
    257299     * Resizes current image.
    258300     *
     
    279321
    280322        list( $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h ) = $dims;
     323
     324        self::setImagickTimeLimit();
    281325
    282326        if ( $crop ) {
     
    546590        }
    547591
     592        self::setImagickTimeLimit();
     593
    548594        try {
    549595            $this->image->cropImage( $src_w, $src_h, $src_x, $src_y );
Note: See TracChangeset for help on using the changeset viewer.