Make WordPress Core

Changeset 49230


Ignore:
Timestamp:
10/20/2020 02:35:10 PM (6 years ago)
Author:
mikeschroder
Message:

Media: Support Stream Wrappers In WP_Image_Editor_Imagick

Since WP_Image_Editor's introduction, stream wrappers have functioned in WP_Image_Editor_GD, but haven't been properly supported in WP_Image_Editor_Imagick.

  • Detects stream wrappers and uses file_put_contents() along with Imagick::read/getImageBlob() for handling when necessary.
  • Introduces private method, WP_Image_Editor_Imagick::write_image to handle detection and proper saving.
  • Introduces WP_Test_Stream class for testing stream wrappers, along with new tests for Imagick's stream handling and a stream filename test.

Adds requirement for Imagick::readImageBlob(), available in Imagick >= 2.0.0, which aligns with the current requirement of Imagick >= 2.2.0.

Props p00ya, calin, joemcgill, pputzer, jimyaghi, mikeschroder.
Fixes #42663.

Location:
trunk
Files:
1 added
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/class-wp-image-editor-imagick.php

    r49174 r49230  
    7272                        'flopimage',
    7373                        'readimage',
     74                        'readimageblob',
    7475                );
    7576
     
    128129                }
    129130
    130                 if ( ! is_file( $this->file ) && ! preg_match( '|^https?://|', $this->file ) ) {
     131                if ( ! is_file( $this->file ) && ! wp_is_stream( $this->file ) ) {
    131132                        return new WP_Error( 'error_loading_image', __( 'File doesn’t exist?' ), $this->file );
    132133                }
     
    149150                                }
    150151                        } else {
    151                                 $this->image->readImage( $this->file );
     152                                if ( wp_is_stream( $this->file ) ) {
     153                                        // Due to reports of issues with streams with `Imagick::readImageFile()`, uses `Imagick::readImageBlob()` instead.
     154                                        $this->image->readImageBlob( file_get_contents( $this->file ), $this->file );
     155                                } else {
     156                                        $this->image->readImage( $this->file );
     157                                }
    152158                        }
    153159
     
    683689
    684690                        $this->image->setImageFormat( strtoupper( $this->get_extension( $mime_type ) ) );
    685                         $this->make_image( $filename, array( $image, 'writeImage' ), array( $filename ) );
    686 
     691                } catch ( Exception $e ) {
     692                        return new WP_Error( 'image_save_error', $e->getMessage(), $filename );
     693                }
     694
     695                $write_image_result = $this->write_image( $this->image, $filename );
     696                if ( is_wp_error( $write_image_result ) ) {
     697                        return $write_image_result;
     698                }
     699
     700                try {
    687701                        // Reset original format.
    688702                        $this->image->setImageFormat( $orig_format );
     
    704718                        'mime-type' => $mime_type,
    705719                );
     720        }
     721
     722        /**
     723         * Writes an image to a file or stream.
     724         *
     725         * @since 5.6
     726         *
     727         * @param Imagick $image
     728         * @param string  $filename The destination filename or stream URL.
     729         *
     730         * @return true|WP_Error
     731         */
     732        private function write_image( $image, $filename ) {
     733                if ( wp_is_stream( $filename ) ) {
     734                        /*
     735                         * Due to reports of issues with streams with `Imagick::writeImageFile()` and `Imagick::writeImage()`, copies the blob instead.
     736                         * Checks for exact type due to: https://www.php.net/manual/en/function.file-put-contents.php
     737                         */
     738                        if ( file_put_contents( $filename, $image->getImageBlob() ) === false ) {
     739                                /* translators: %s: PHP function name. */
     740                                return new WP_Error( 'image_save_error', sprintf( __( '%s failed while writing image to stream.' ), '<code>file_put_contents()</code>' ), $filename );
     741                        } else {
     742                                return true;
     743                        }
     744                } else {
     745                        try {
     746                                return $image->writeImage( $filename );
     747                        } catch ( Exception $e ) {
     748                                return new WP_Error( 'image_save_error', $e->getMessage(), $filename );
     749                        }
     750                }
    706751        }
    707752
  • trunk/src/wp-includes/class-wp-image-editor.php

    r48586 r49230  
    366366
    367367                if ( ! is_null( $dest_path ) ) {
    368                         $_dest_path = realpath( $dest_path );
    369                         if ( $_dest_path ) {
    370                                 $dir = $_dest_path;
     368                        if ( ! wp_is_stream( $dest_path ) ) {
     369                                $_dest_path = realpath( $dest_path );
     370                                if ( $_dest_path ) {
     371                                        $dir = $_dest_path;
     372                                }
     373                        } else {
     374                                $dir = $dest_path;
    371375                        }
    372376                }
  • trunk/tests/phpunit/tests/image/editor.php

    r48937 r49230  
    144144                // Combo!
    145145                $this->assertSame( trailingslashit( realpath( get_temp_dir() ) ) . 'canola-new.png', $editor->generate_filename( 'new', realpath( get_temp_dir() ), 'png' ) );
     146
     147                // Test with a stream destination.
     148                $this->assertSame( 'file://testing/path/canola-100x50.jpg', $editor->generate_filename( null, 'file://testing/path' ) );
    146149        }
    147150
  • trunk/tests/phpunit/tests/image/editorImagick.php

    r49108 r49230  
    1717                require_once ABSPATH . WPINC . '/class-wp-image-editor.php';
    1818                require_once ABSPATH . WPINC . '/class-wp-image-editor-imagick.php';
     19                require_once DIR_TESTROOT . '/includes/class-wp-test-stream.php';
    1920
    2021                parent::setUp();
     
    575576        }
    576577
     578        /**
     579         * Test that images can be loaded and written over streams
     580         */
     581        public function test_streams() {
     582                stream_wrapper_register( 'wptest', 'WP_Test_Stream' );
     583                WP_Test_Stream::$data = array(
     584                        'Tests_Image_Editor_Imagick' => array(
     585                                '/read.jpg' => file_get_contents( DIR_TESTDATA . '/images/waffles.jpg' ),
     586                        ),
     587                );
     588
     589                $file                 = 'wptest://Tests_Image_Editor_Imagick/read.jpg';
     590                $imagick_image_editor = new WP_Image_Editor_Imagick( $file );
     591
     592                $ret = $imagick_image_editor->load();
     593                $this->assertNotWPError( $ret );
     594
     595                $temp_file = 'wptest://Tests_Image_Editor_Imagick/write.jpg';
     596
     597                $ret = $imagick_image_editor->save( $temp_file );
     598                $this->assertNotWPError( $ret );
     599
     600                $this->assertSame( $temp_file, $ret['path'] );
     601
     602                if ( $temp_file !== $ret['path'] ) {
     603                        unlink( $ret['path'] );
     604                }
     605                unlink( $temp_file );
     606        }
    577607}
Note: See TracChangeset for help on using the changeset viewer.