Ticket #32075: 32075-improved-patch-v9.patch
File 32075-improved-patch-v9.patch, 17.0 KB (added by , 9 years ago) |
---|
-
src/wp-admin/admin.php
From 5542ed0101fd4f2f8c86e3c946109a27bd593480 Mon Sep 17 00:00:00 2001 From: jrfnl <github_nospam@adviesenzo.nl> Date: Sun, 26 Jun 2016 12:54:05 +0200 Subject: [PATCH] Prevent WP setting the memory limit to a value lower than it currently is. Also fixes a bug in how the memory limits were tested in the first place. Includes unit tests for the newly added functions in load.php. --- src/wp-admin/admin.php | 16 +--- src/wp-admin/includes/file.php | 3 +- src/wp-admin/includes/image-edit.php | 3 +- src/wp-includes/class-wp-image-editor-gd.php | 12 +-- src/wp-includes/class-wp-image-editor-imagick.php | 5 +- src/wp-includes/default-constants.php | 43 +++++----- src/wp-includes/deprecated.php | 5 +- src/wp-includes/functions.php | 95 +++++++++++++++++++++++ src/wp-includes/load.php | 58 ++++++++++++++ tests/phpunit/tests/functions.php | 14 ++++ tests/phpunit/tests/load.php | 72 +++++++++++++++++ 11 files changed, 268 insertions(+), 58 deletions(-) create mode 100644 tests/phpunit/tests/load.php diff --git a/src/wp-admin/admin.php b/src/wp-admin/admin.php index 6e9af5e..b35f073 100644
a b else 138 138 require(ABSPATH . 'wp-admin/menu.php'); 139 139 140 140 if ( current_user_can( 'manage_options' ) ) { 141 /** 142 * Filters the maximum memory limit available for administration screens. 143 * 144 * This only applies to administrators, who may require more memory for tasks like updates. 145 * Memory limits when processing images (uploaded or edited by users of any role) are 146 * handled separately. 147 * 148 * The WP_MAX_MEMORY_LIMIT constant specifically defines the maximum memory limit available 149 * when in the administration back end. The default is 256M, or 256 megabytes of memory. 150 * 151 * @since 3.0.0 152 * 153 * @param string 'WP_MAX_MEMORY_LIMIT' The maximum WordPress memory limit. Default 256M. 154 */ 155 @ini_set( 'memory_limit', apply_filters( 'admin_memory_limit', WP_MAX_MEMORY_LIMIT ) ); 141 wp_raise_memory_limit( 'admin' ); 156 142 } 157 143 158 144 /** -
src/wp-admin/includes/file.php
diff --git a/src/wp-admin/includes/file.php b/src/wp-admin/includes/file.php index 3b754df..f65b55c 100644
a b function unzip_file($file, $to) { 570 570 return new WP_Error('fs_unavailable', __('Could not access filesystem.')); 571 571 572 572 // Unzip can use a lot of memory, but not this much hopefully 573 /** This filter is documented in wp-admin/admin.php */ 574 @ini_set( 'memory_limit', apply_filters( 'admin_memory_limit', WP_MAX_MEMORY_LIMIT ) ); 573 wp_raise_memory_limit( 'admin' ); 575 574 576 575 $needed_dirs = array(); 577 576 $to = trailingslashit($to); -
src/wp-admin/includes/image-edit.php
diff --git a/src/wp-admin/includes/image-edit.php b/src/wp-admin/includes/image-edit.php index 99e1c40..8b12a4e 100644
a b function image_edit_apply_changes( $image, $changes ) { 586 586 function stream_preview_image( $post_id ) { 587 587 $post = get_post( $post_id ); 588 588 589 /** This filter is documented in wp-admin/admin.php */ 590 @ini_set( 'memory_limit', apply_filters( 'admin_memory_limit', WP_MAX_MEMORY_LIMIT ) ); 589 wp_raise_memory_limit( 'admin' ); 591 590 592 591 $img = wp_get_image_editor( _load_image_to_edit_path( $post_id ) ); 593 592 -
src/wp-includes/class-wp-image-editor-gd.php
diff --git a/src/wp-includes/class-wp-image-editor-gd.php b/src/wp-includes/class-wp-image-editor-gd.php index 96e7bf1..d7823eb 100644
a b class WP_Image_Editor_GD extends WP_Image_Editor { 96 96 if ( ! is_file( $this->file ) && ! preg_match( '|^https?://|', $this->file ) ) 97 97 return new WP_Error( 'error_loading_image', __('File doesn’t exist?'), $this->file ); 98 98 99 /**100 * Filters the memory limit allocated for image manipulation.101 *102 * @since 3.5.0103 *104 * @param int|string $limit Maximum memory limit to allocate for images. Default WP_MAX_MEMORY_LIMIT.105 * Accepts an integer (bytes), or a shorthand string notation, such as '256M'.106 */107 $image_memory_limit = apply_filters( 'image_memory_limit', WP_MAX_MEMORY_LIMIT );108 109 99 // Set artificially high because GD uses uncompressed images in memory. 110 @ini_set( 'memory_limit', $image_memory_limit);100 wp_raise_memory_limit( 'image' ); 111 101 112 102 $this->image = @imagecreatefromstring( file_get_contents( $this->file ) ); 113 103 -
src/wp-includes/class-wp-image-editor-imagick.php
diff --git a/src/wp-includes/class-wp-image-editor-imagick.php b/src/wp-includes/class-wp-image-editor-imagick.php index 3d92d39..82b872d 100644
a b class WP_Image_Editor_Imagick extends WP_Image_Editor { 137 137 if ( ! is_file( $this->file ) && ! preg_match( '|^https?://|', $this->file ) ) 138 138 return new WP_Error( 'error_loading_image', __('File doesn’t exist?'), $this->file ); 139 139 140 /** This filter is documented in wp-includes/class-wp-image-editor-gd.php */141 $image_memory_limit = apply_filters( 'image_memory_limit', WP_MAX_MEMORY_LIMIT );142 143 140 /* 144 141 * Even though Imagick uses less PHP memory than GD, set higher limit 145 142 * for users that have low PHP.ini limits. 146 143 */ 147 @ini_set( 'memory_limit', $image_memory_limit);144 wp_raise_memory_limit( 'image' ); 148 145 149 146 try { 150 147 $this->image = new Imagick( $this->file ); -
src/wp-includes/default-constants.php
diff --git a/src/wp-includes/default-constants.php b/src/wp-includes/default-constants.php index fe96e34..7a8ff57 100644
a b 17 17 function wp_initial_constants() { 18 18 global $blog_id; 19 19 20 // set memory limits 21 if ( !defined('WP_MEMORY_LIMIT') ) { 22 if ( is_multisite() ) { 23 define('WP_MEMORY_LIMIT', '64M'); 20 $current_limit = @ini_get( 'memory_limit' ); 21 $current_limit_int = wp_php_ini_bytes_to_int( $current_limit ); 22 23 // Define memory limits. 24 if ( ! defined( 'WP_MEMORY_LIMIT' ) ) { 25 if ( false === wp_is_ini_value_changable( 'memory_limit' ) ) { 26 define( 'WP_MEMORY_LIMIT', $current_limit ); 27 } elseif ( is_multisite() ) { 28 define( 'WP_MEMORY_LIMIT', '64M' ); 24 29 } else { 25 define( 'WP_MEMORY_LIMIT', '40M');30 define( 'WP_MEMORY_LIMIT', '40M' ); 26 31 } 27 32 } 28 33 29 34 if ( ! defined( 'WP_MAX_MEMORY_LIMIT' ) ) { 30 define( 'WP_MAX_MEMORY_LIMIT', '256M' ); 35 if ( false === wp_is_ini_value_changable( 'memory_limit' ) ) { 36 define( 'WP_MAX_MEMORY_LIMIT', $current_limit ); 37 } elseif ( -1 === $current_limit_int || $current_limit_int > 268435456 ) { 38 define( 'WP_MAX_MEMORY_LIMIT', $current_limit ); 39 } else { 40 define( 'WP_MAX_MEMORY_LIMIT', '256M' ); 41 } 31 42 } 32 43 44 // Set memory limits. 45 $wp_limit_int = wp_php_ini_bytes_to_int( WP_MEMORY_LIMIT ); 46 if ( -1 !== $current_limit_int && ( -1 === $wp_limit_int || $wp_limit_int > $current_limit_int ) ) { 47 @ini_set( 'memory_limit', WP_MEMORY_LIMIT ); 48 } 49 33 50 if ( ! isset($blog_id) ) 34 51 $blog_id = 1; 35 52 36 // set memory limits.37 if ( function_exists( 'memory_get_usage' ) ) {38 $current_limit = @ini_get( 'memory_limit' );39 $current_limit_int = intval( $current_limit );40 if ( false !== strpos( $current_limit, 'G' ) )41 $current_limit_int *= 1024;42 $wp_limit_int = intval( WP_MEMORY_LIMIT );43 if ( false !== strpos( WP_MEMORY_LIMIT, 'G' ) )44 $wp_limit_int *= 1024;45 46 if ( -1 != $current_limit && ( -1 == WP_MEMORY_LIMIT || $current_limit_int < $wp_limit_int ) )47 @ini_set( 'memory_limit', WP_MEMORY_LIMIT );48 }49 50 53 if ( !defined('WP_CONTENT_DIR') ) 51 54 define( 'WP_CONTENT_DIR', ABSPATH . 'wp-content' ); // no trailing slash, full paths only - WP_CONTENT_URL is defined further down 52 55 -
src/wp-includes/deprecated.php
diff --git a/src/wp-includes/deprecated.php b/src/wp-includes/deprecated.php index 0949f0b..8471a9b 100644
a b function wp_load_image( $file ) { 3175 3175 if ( ! function_exists('imagecreatefromstring') ) 3176 3176 return __('The GD image library is not installed.'); 3177 3177 3178 /** This filter is documented in wp-includes/class-wp-image-editor-gd.php */3179 $image_memory_limit = apply_filters( 'image_memory_limit', WP_MAX_MEMORY_LIMIT );3180 3181 3178 // Set artificially high because GD uses uncompressed images in memory. 3182 @ini_set( 'memory_limit', $image_memory_limit);3179 wp_raise_memory_limit( 'image' ); 3183 3180 3184 3181 $image = imagecreatefromstring( file_get_contents( $file ) ); 3185 3182 -
src/wp-includes/functions.php
diff --git a/src/wp-includes/functions.php b/src/wp-includes/functions.php index 690e271..16de2e6 100644
a b function mysql_to_rfc3339( $date_string ) { 5350 5350 // Strip timezone information 5351 5351 return preg_replace( '/(?:Z|[+-]\d{2}(?::\d{2})?)$/', '', $formatted ); 5352 5352 } 5353 5354 /** 5355 * Attempts to raise the PHP memory limit for memory intensive processes. 5356 * 5357 * Allows only to raise the existing limit and prevents lowering it. 5358 * 5359 * @since 4.6.0 5360 * 5361 * @param string $context Context in which the function is called. 5362 * Either 'admin' or 'image'. Defaults to 'admin'. 5363 */ 5364 function wp_raise_memory_limit( $context = 'admin' ) { 5365 // Exit early if the limit cannot be changed. 5366 if ( false === wp_is_ini_value_changable( 'memory_limit' ) ) { 5367 return; 5368 } 5369 5370 $current_limit = @ini_get( 'memory_limit' ); 5371 $current_limit_int = wp_php_ini_bytes_to_int( $current_limit ); 5372 5373 if ( -1 === $current_limit_int ) { 5374 return; 5375 } 5376 5377 $wp_max_limit = WP_MAX_MEMORY_LIMIT; 5378 $wp_max_limit_int = wp_php_ini_bytes_to_int( $wp_max_limit ); 5379 $filtered_limit = $wp_max_limit; 5380 5381 switch ( $context ) { 5382 case 'admin': 5383 /** 5384 * Filters the memory limit available for administration screens. 5385 * 5386 * This only applies to administrators, who may require more memory for tasks like updates. 5387 * Memory limits when processing images (uploaded or edited by users of any role) are 5388 * handled separately. 5389 * 5390 * The WP_MAX_MEMORY_LIMIT constant specifically defines the maximum memory limit available 5391 * when in the administration back end. The default is 256M (256 megabytes 5392 * of memory) or the original `memory_limit` php.ini value if this is higher. 5393 * 5394 * @since 3.0.0 5395 * @since 4.6.0 The default takes the original `memory_limit` into account. 5396 * 5397 * @param int|string $filtered_limit The maximum WordPress memory limit. 5398 * Accepts an integer (bytes), or a shorthand string 5399 * notation, such as '256M'. 5400 */ 5401 $filtered_limit = apply_filters( 'admin_memory_limit', $filtered_limit ); 5402 break; 5403 5404 case 'image': 5405 /** 5406 * Filters the memory limit allocated for image manipulation. 5407 * 5408 * @since 3.5.0 5409 * @since 4.6.0 The default takes the original `memory_limit` into account. 5410 * 5411 * @param int|string $filtered_limit Maximum memory limit to allocate for images. 5412 * Default 256M or the original php.ini memory_limit, 5413 * whichever is higher. 5414 * Accepts an integer (bytes), or a shorthand string 5415 * notation, such as '256M'. 5416 */ 5417 $filtered_limit = apply_filters( 'image_memory_limit', $filtered_limit ); 5418 break; 5419 5420 default: 5421 /** 5422 * Filters the memory limit allocated for arbitrary contexts. 5423 * 5424 * The dynamic portion of the hook name, `$context`, refers to an arbitrary 5425 * context passed on calling the function. This allows for plugins to define 5426 * their own contexts for raising the memory limit. 5427 * 5428 * @since 4.6.0 5429 * 5430 * @param int|string $filtered_limit Maximum memory limit to allocate for images. 5431 * Default 256M or the original php.ini memory_limit, 5432 * whichever is higher. 5433 * Accepts an integer (bytes), or a shorthand string 5434 * notation, such as '256M'. 5435 */ 5436 $filtered_limit = apply_filters( "{$context}_memory_limit", $filtered_limit ); 5437 break; 5438 } 5439 5440 $filtered_limit_int = wp_php_ini_bytes_to_int( $filtered_limit ); 5441 5442 if ( -1 === $filtered_limit_int || ( $filtered_limit_int > $wp_max_limit_int && $filtered_limit_int > $current_limit_int ) ) { 5443 @ini_set( 'memory_limit', $filtered_limit ); 5444 } elseif ( -1 === $wp_max_limit_int || $wp_max_limit_int > $current_limit_int ) { 5445 @ini_set( 'memory_limit', $wp_max_limit ); 5446 } 5447 } -
src/wp-includes/load.php
diff --git a/src/wp-includes/load.php b/src/wp-includes/load.php index 80654f1..66d3fca 100644
a b function is_ssl() { 974 974 } 975 975 return false; 976 976 } 977 978 /** 979 * Converts a PHP ini shorthand byte value to an integer byte value. 980 * 981 * @since 4.6.0 982 * 983 * @see http://php.net/manual/en/function.ini-get.php 984 * @see http://php.net/manual/en/faq.using.php#faq.using.shorthandbytes 985 * 986 * @param string $value An PHP ini byte value, either shorthand or ordinary. 987 * @return int Value in bytes. 988 */ 989 function wp_php_ini_bytes_to_int( $value ) { 990 $value = trim( $value ); 991 $last = strtolower( $value[ strlen( $value ) - 1 ] ); 992 993 switch( $last ) { 994 // Note: the `break` statement is left out on purpose! 995 case 'g': 996 $value *= 1024; 997 case 'm': 998 $value *= 1024; 999 case 'k': 1000 $value *= 1024; 1001 default: 1002 // Left empty on purpose. 1003 break; 1004 } 1005 1006 // Deal with large (float) values which run into the maximum integer size. 1007 if ( PHP_INT_MAX < $value ) { 1008 $value = PHP_INT_MAX; 1009 } 1010 return (int) $value; 1011 } 1012 1013 /** 1014 * Determines whether a PHP ini value is changable at runtime. 1015 * 1016 * @since 4.6.0 1017 * 1018 * @see http://php.net/manual/en/function.ini-get-all.php 1019 * 1020 * @param string $setting The name of the ini setting to check. 1021 * @return bool True if the value is changable at runtime. False otherwise. 1022 */ 1023 function wp_is_ini_value_changable( $setting ) { 1024 static $ini_all; 1025 1026 if ( ! isset( $ini_all ) ) { 1027 $ini_all = ini_get_all(); 1028 } 1029 1030 if ( isset( $ini_all[ $setting ]['access'] ) && ( INI_ALL === $ini_all[ $setting ]['access'] || INI_USER === $ini_all[ $setting ]['access'] ) ) { 1031 return true; 1032 } 1033 return false; 1034 } -
tests/phpunit/tests/functions.php
diff --git a/tests/phpunit/tests/functions.php b/tests/phpunit/tests/functions.php index e28e65f..6b5c8c9 100644
a b class Tests_Functions extends WP_UnitTestCase { 887 887 888 888 $this->assertNull( wp_ext2type( 'unknown_format' ) ); 889 889 } 890 891 /** 892 * Test raising the memory limit. 893 * 894 * {@internal Unfortunately as the default for 'WP_MAX_MEMORY_LIMIT' in the 895 * test suite is -1, we can not test the memory limit negotiations.}} 896 * 897 * @ticket 32075 898 */ 899 function test_wp_raise_memory_limit() { 900 ini_set( 'memory_limit', '40M' ); 901 wp_raise_memory_limit(); 902 $this->assertEquals( '-1', ini_get( 'memory_limit' ) ); 903 } 890 904 } -
new file tests/phpunit/tests/load.php
diff --git a/tests/phpunit/tests/load.php b/tests/phpunit/tests/load.php new file mode 100644 index 0000000..84133ff
- + 1 <?php 2 3 /** 4 * @group load.php 5 */ 6 class Tests_Load extends WP_UnitTestCase { 7 8 /** 9 * Test converting PHP ini byte values to integer byte values. 10 * 11 * @dataProvider data_wp_php_ini_bytes_to_int 12 */ 13 function test_wp_php_ini_bytes_to_int( $value, $expected ) { 14 $this->assertSame( $expected, wp_php_ini_bytes_to_int( $value ) ); 15 } 16 17 function data_wp_php_ini_bytes_to_int() { 18 $array = array( 19 // Integer input 20 array( -1, -1 ), // = no memory limit 21 array( 8388608, 8388608 ), // 8M 22 23 // String input (memory limit shorthand values) 24 array( '32k', 32768 ), 25 array( '64K', 65536 ), 26 array( '128m', 134217728 ), 27 array( '256M', 268435456 ), 28 array( '1g', 1073741824 ), 29 array( '1024', 1024 ), // No letter will be interpreted as integer value. 30 31 // Edge cases 32 array( 'g', 0 ), 33 array( 'null', 0 ), 34 array( 'off', 0 ), 35 ); 36 37 // Test while running into maximum integer size limit on 32bit systems. 38 if ( 2147483647 === PHP_INT_MAX ) { 39 $array[] = array( '2G', 2147483647 ); 40 $array[] = array( '4G', 2147483647 ); 41 } else { 42 $array[] = array( '2G', 2147483648 ); 43 $array[] = array( '4G', 4294967296 ); 44 } 45 46 return $array; 47 } 48 49 /** 50 * Test the determining of the changability of a PHP ini value. 51 * 52 * @dataProvider data_wp_is_ini_value_changable 53 */ 54 function test_wp_is_ini_value_changable( $setting, $expected ) { 55 $this->assertSame( $expected, wp_is_ini_value_changable( $setting ) ); 56 } 57 58 function data_wp_is_ini_value_changable() { 59 $array = array( 60 array( 'memory_limit', true ), // PHP_INI_ALL 61 array( 'log_errors', true ), // PHP_INI_ALL 62 array( 'upload_max_filesize', false ), // PHP_INI_PERDIR 63 array( 'upload_tmp_dir', false ), // PHP_INI_SYSTEM 64 ); 65 66 if ( extension_loaded( 'Tidy' ) && version_compare( PHP_VERSION, '7.0.0', '>' ) ) { 67 $array[] = array( 'tidy.clean_output', true ); // PHP_INI_USER 68 } 69 70 return $array; 71 } 72 }