core/includes/bootstrap.inc | 63 +++++++--------------- core/includes/common.inc | 11 ++-- core/includes/file.inc | 9 +++- core/modules/color/color.module | 32 ++++++----- core/modules/simpletest/simpletest.install | 2 +- .../Drupal/system/Tests/Bootstrap/MiscUnitTest.php | 23 ++++---- .../{SizeUnitTest.php => ByteCountUnitTest.php} | 9 ++-- core/modules/system/system.install | 8 +-- 8 files changed, 76 insertions(+), 81 deletions(-) rename core/modules/system/lib/Drupal/system/Tests/Common/{SizeUnitTest.php => ByteCountUnitTest.php} (95%) diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc index db521b0..4a3bac2 100644 --- a/core/includes/bootstrap.inc +++ b/core/includes/bootstrap.inc @@ -18,6 +18,7 @@ use Symfony\Component\DependencyInjection\Exception\RuntimeException as DependencyInjectionRuntimeException; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\DataCollector\MemoryDataCollector; use Drupal\Core\Language\Language; use Drupal\Core\Lock\DatabaseLockBackend; use Drupal\Core\Lock\LockBackendInterface; @@ -3048,54 +3049,28 @@ function _drupal_shutdown_function() { } /** - * Returns the maximum amount of memory in bytes that Drupal is allowed to - * allocate. + * Compares a required PHP memory limit to the configured limit. * - * @return int|null - * The number of bytes, or NULL if there is no limit. - */ -function drupal_memory_limit() { - $memory_limit = ini_get('memory_limit'); - // If memory_limit is -1, there is no limit. - if ($memory_limit == -1) { - return NULL; - } - // Force parsing of PHP memory_limit as IEC, see - // http://php.net/manual/en/faq.using.php#faq.using.shorthandbytes - return parse_byte_count($memory_limit, TRUE); -} - -/** - * Compares the memory required for an operation to the available memory. - * - * @param int $required - * The memory required for the operation, expressed as a number of bytes with - * optional SI or IEC binary unit prefix (e.g. 2, 3 K, 5MB, 10 G, 6GiB, 8 - * bytes, 9mbytes). - * @param int $memory_limit - * (optional) The memory limit for the operation, expressed as a number of - * bytes with optional SI or IEC binary unit prefix. If no value is passed, - * the current PHP memory_limit will be used. + * @param string $required + * The required memory limit, expressed as a number of bytes with optional + * IEC unit. * * @return bool - * TRUE if there is sufficient memory to allow the operation, or FALSE - * otherwise. - */ -function drupal_check_memory_limit($required, $memory_limit = NULL) { - if (is_null($memory_limit)) { - // Get PHP's memory limit. - $memory_limit_bytes = drupal_memory_limit(); - // Is it unlimited? - if (is_null($memory_limit_bytes)) { - return TRUE; - } - } - else { - $memory_limit_bytes = parse_byte_count($memory_limit); + * TRUE if required limit is less than or equal to the configured limit, or + * FALSE otherwise. + * + * @see parse_byte_count() + */ +function drupal_check_memory_limit($required) { + // Get PHP's memory limit. + $data_collector = new MemoryDataCollector(); + $memory_limit_bytes = $data_collector->getMemoryLimit(); + // Is it unlimited? + if ($memory_limit_bytes == -1) { + return TRUE; } - // There is sufficient memory if the memory limit is greater than or equal to - // the memory required for the operation. - return $memory_limit_bytes >= parse_byte_count($required); + // Is the required limit less than or equal to the configured limit? + return parse_byte_count($required, TRUE) <= $memory_limit_bytes; } /** diff --git a/core/includes/common.inc b/core/includes/common.inc index ae96be1..199308d 100644 --- a/core/includes/common.inc +++ b/core/includes/common.inc @@ -995,9 +995,11 @@ function parse_byte_count($count, $force_iec = FALSE) { // Calculate byte count. if ($unit_length > 0) { // Determine if the unit is SI or IEC. The second letter of an abbreviated - // IEC unit is always 'i', e.g. Mi or MiB. The forth letter of an - // unabbreviated IEC unit is always 'i', e.g. mebibyte. - if ((($unit_length == 2 || $unit_length == 3) && $unit[1] == 'i') || ($unit_length >= 4 && $unit[3] == 'i') || $force_iec) { + // IEC unit is always 'i', for example MiB. The forth letter of an + // unabbreviated IEC unit is always 'i', for example mebibyte. + $short_iec = $unit_length == 3 && $unit[1] == 'i'; + $long_iec = $unit_length >= 4 && $unit[3] == 'i'; + if ($short_iec || $long_iec || $force_iec) { $base = DRUPAL_KIBIBYTE; } else { @@ -1005,8 +1007,7 @@ function parse_byte_count($count, $force_iec = FALSE) { } // Multiply the quantity by the quantity of the unit. The quantity of the // unit is calculated by determining its order of magnitude and raising the - // base of the unit to this power. If the unit is missing, strpos() returns - // FALSE which is cast to 0. This causes the unit to default to 'b'. + // base of the unit to this power. $quantity *= pow($base, (int) strpos('bkmgtpezy', $unit[0])); } // Make sure an integer is returned. Not cast to an integer type as this would diff --git a/core/includes/file.inc b/core/includes/file.inc index 2521138..4185b42 100644 --- a/core/includes/file.inc +++ b/core/includes/file.inc @@ -1189,20 +1189,25 @@ function file_scan_directory($dir, $mask, $options = array(), $depth = 0) { /** * Determines the maximum file upload size by querying the PHP settings. * + * Does not force parsing of PHP settings as IEC so they are unchanged when + * rendered as SI. + * * @return * A file size limit in bytes based on the PHP upload_max_filesize and * post_max_size + * + * @see parse_byte_count() */ function file_upload_max_size() { static $max_size = -1; if ($max_size < 0) { // Start with post_max_size. - $max_size = parse_byte_count(ini_get('post_max_size'), TRUE); + $max_size = parse_byte_count(ini_get('post_max_size')); // If upload_max_size is less, then reduce. Except if upload_max_size is // zero, which indicates no limit. - $upload_max = parse_byte_count(ini_get('upload_max_filesize'), TRUE); + $upload_max = parse_byte_count(ini_get('upload_max_filesize')); if ($upload_max > 0 && $upload_max < $max_size) { $max_size = $upload_max; } diff --git a/core/modules/color/color.module b/core/modules/color/color.module index bb97b89..9be046a 100644 --- a/core/modules/color/color.module +++ b/core/modules/color/color.module @@ -294,20 +294,24 @@ function color_scheme_form_submit($form, &$form_state) { $palette += $info['schemes']['default']['colors']; } - // Fetch source image dimensions. - $source = drupal_get_path('theme', $theme) . '/' . $info['base_image']; - list($width, $height) = getimagesize($source); - // We need at least a copy of the source and a target buffer of the same - // size (both at 32bpp). - $required = $width * $height * 8; - // We intend to prevent color scheme changes if there isn't enough memory - // available. memory_get_usage(TRUE) returns a more accurate number than - // memory_get_usage(), therefore we won't inadvertently reject a color - // scheme change based on a faulty memory calculation. - $required += memory_get_usage(TRUE); - if (!drupal_check_memory_limit($required)) { - drupal_set_message(t('There is not enough memory available to PHP to change this theme\'s color scheme. You need at least %size. Check the PHP documentation for more information.', array('%size' => format_byte_count($required, TRUE), '@url' => 'http://www.php.net/manual/ini.core.php#ini.sect.resource-limits')), 'error'); - return; + // Make sure enough memory is available, if PHP's memory limit is compiled in. + if (function_exists('memory_get_usage')) { + // Fetch source image dimensions. + $source = drupal_get_path('theme', $theme) . '/' . $info['base_image']; + list($width, $height) = getimagesize($source); + + // We need at least a copy of the source and a target buffer of the same + // size (both at 32bpp). + $required = $width * $height * 8; + // We intend to prevent color scheme changes if there isn't enough memory + // available. memory_get_usage(TRUE) returns a more accurate number than + // memory_get_usage(), therefore we won't inadvertently reject a color + // scheme change based on a faulty memory calculation. + $required += memory_get_usage(TRUE); + if (!drupal_check_memory_limit($required)) { + drupal_set_message(t('There is not enough memory available to PHP to change this theme\'s color scheme. You need at least %size. Check the PHP documentation for more information.', array('%size' => (int) ceil($required / (1024 * 1024)) . ' M', '@url' => 'http://www.php.net/manual/ini.core.php#ini.sect.resource-limits')), 'error'); + return; + } } // Delete old files. diff --git a/core/modules/simpletest/simpletest.install b/core/modules/simpletest/simpletest.install index 5aabde1..48d75b4 100644 --- a/core/modules/simpletest/simpletest.install +++ b/core/modules/simpletest/simpletest.install @@ -61,7 +61,7 @@ function simpletest_requirements($phase) { // Check the current memory limit. If it is set too low, SimpleTest will fail // to load all tests and throw a fatal error. - if (!drupal_check_memory_limit(parse_byte_count(SIMPLETEST_MINIMUM_PHP_MEMORY_LIMIT, TRUE))) { + if (!drupal_check_memory_limit(SIMPLETEST_MINIMUM_PHP_MEMORY_LIMIT)) { $requirements['php_memory_limit']['severity'] = REQUIREMENT_ERROR; $requirements['php_memory_limit']['description'] = t('The testing framework requires the PHP memory limit to be at least %memory_minimum_limit. The current value is %memory_limit. Follow these steps to continue.', array('%memory_limit' => $memory_limit, '%memory_minimum_limit' => SIMPLETEST_MINIMUM_PHP_MEMORY_LIMIT, '@url' => 'http://drupal.org/node/207036')); } diff --git a/core/modules/system/lib/Drupal/system/Tests/Bootstrap/MiscUnitTest.php b/core/modules/system/lib/Drupal/system/Tests/Bootstrap/MiscUnitTest.php index 3cd9f43..ef56385 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Bootstrap/MiscUnitTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Bootstrap/MiscUnitTest.php @@ -8,6 +8,7 @@ namespace Drupal\system\Tests\Bootstrap; use Drupal\simpletest\UnitTestBase; +use Symfony\Component\HttpKernel\DataCollector\MemoryDataCollector; /** * Tests miscellaneous functions in bootstrap.inc. @@ -26,14 +27,18 @@ public static function getInfo() { * Tests that the drupal_check_memory_limit() function works as expected. */ function testCheckMemoryLimit() { - // Test that a very reasonable amount of memory is available. - $this->assertTrue(drupal_check_memory_limit('30 MB'), '30 MB of memory tested available.'); - - // Test that even though we have 30MB of memory available - the function - // returns FALSE when given an upper limit for how much memory can be used. - $this->assertFalse(drupal_check_memory_limit('30 MB', '16 MB'), 'drupal_check_memory_limit() returns FALSE with a 16MB upper limit on a 30MB requirement.'); - - // Test that an equal amount of memory to the amount requested returns TRUE. - $this->assertTrue(drupal_check_memory_limit('30 MB', '30 MB'), 'drupal_check_memory_limit() returns TRUE when requesting 30MB on a 30MB requirement.'); + $data_collector = new MemoryDataCollector(); + $memory_limit = $data_collector->getMemoryLimit(); + // Is PHP's memory limit configured to be unlimited? + if ($memory_limit == -1) { + $this->assertTrue(drupal_check_memory_limit('1024M'), '1024 MiB of memory is available.'); + } + else { + $this->assertTrue(drupal_check_memory_limit($memory_limit), 'Current memory limit is available.'); + $this->assertTrue(drupal_check_memory_limit($memory_limit - 1), 'One byte less than current memory limit is available.'); + $this->assertFalse(drupal_check_memory_limit($memory_limit + 1), 'One byte more than current memory limit is not available.'); + $this->assertTrue(drupal_check_memory_limit((int) ($memory_limit / 2)), 'Half current memory limit is available.'); + $this->assertFalse(drupal_check_memory_limit($memory_limit * 2), 'Twice current memory limit is not available.'); + } } } diff --git a/core/modules/system/lib/Drupal/system/Tests/Common/SizeUnitTest.php b/core/modules/system/lib/Drupal/system/Tests/Common/ByteCountUnitTest.php similarity index 95% rename from core/modules/system/lib/Drupal/system/Tests/Common/SizeUnitTest.php rename to core/modules/system/lib/Drupal/system/Tests/Common/ByteCountUnitTest.php index d1a6b30..9db48e0 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Common/SizeUnitTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Common/ByteCountUnitTest.php @@ -2,7 +2,7 @@ /** * @file - * Definition of Drupal\system\Tests\Common\SizeUnitTest. + * Definition of Drupal\system\Tests\Common\ByteCountUnitTest. */ namespace Drupal\system\Tests\Common; @@ -14,6 +14,8 @@ */ class ByteCountUnitTest extends UnitTestBase { protected $exact_test_cases; + protected $exact_iec_test_cases; + protected $exact_force_iec_test_cases; protected $rounded_test_cases; public static function getInfo() { @@ -37,6 +39,7 @@ function setUp() { '1 YB' => pow(DRUPAL_KILOBYTE, 8), ); $this->exact_iec_test_cases = array( + '1 B' => 1, '1 KiB' => DRUPAL_KIBIBYTE, '1 MiB' => pow(DRUPAL_KIBIBYTE, 2), '1 GiB' => pow(DRUPAL_KIBIBYTE, 3), @@ -47,6 +50,7 @@ function setUp() { '1 YiB' => pow(DRUPAL_KIBIBYTE, 8), ); $this->exact_force_iec_test_cases = array( + '1 B' => 1, '1 kB' => DRUPAL_KIBIBYTE, '1 MB' => pow(DRUPAL_KIBIBYTE, 2), '1 GB' => pow(DRUPAL_KIBIBYTE, 3), @@ -73,7 +77,7 @@ function testCommonFormatByteCount() { foreach (array($this->exact_test_cases, $this->rounded_test_cases) as $test_cases) { foreach ($test_cases as $expected => $input) { $this->assertEqual( - ($result = format_byte_count($input, NULL)), + ($result = format_byte_count($input)), $expected, $expected . ' == ' . $result . ' (' . $input . ' bytes)' ); @@ -94,7 +98,6 @@ function testCommonParseByteCount() { ); } } - foreach ($this->exact_force_iec_test_cases as $string => $size) { $this->assertEqual( $parsed_size = parse_byte_count($string, TRUE), diff --git a/core/modules/system/system.install b/core/modules/system/system.install index 6a5ac17..4ad1261 100644 --- a/core/modules/system/system.install +++ b/core/modules/system/system.install @@ -9,6 +9,7 @@ use Drupal\Component\Uuid\Uuid; use Drupal\Core\Database\Database; use Drupal\Core\Language\Language; +use Symfony\Component\HttpKernel\DataCollector\MemoryDataCollector; /** * Test and report Drupal installation requirements. @@ -197,13 +198,14 @@ function system_requirements($phase) { } // Test PHP memory_limit. - $memory_limit = drupal_memory_limit(); + $data_collector = new MemoryDataCollector(); + $memory_limit = $data_collector->getMemoryLimit(); $requirements['php_memory_limit'] = array( 'title' => t('PHP memory limit'), - 'value' => $memory_limit ? format_byte_count($memory_limit, TRUE) : t("Unlimited"), + 'value' => ($memory_limit != -1) ? format_byte_count($memory_limit, TRUE) : t("Unlimited"), ); - if (!drupal_check_memory_limit(parse_byte_count(DRUPAL_MINIMUM_PHP_MEMORY_LIMIT, TRUE))) { + if (!drupal_check_memory_limit(DRUPAL_MINIMUM_PHP_MEMORY_LIMIT)) { $description = ''; if ($phase == 'install') { $description = t('Consider increasing your PHP memory limit to %memory_minimum_limit to help prevent errors in the installation process.', array('%memory_minimum_limit' => DRUPAL_MINIMUM_PHP_MEMORY_LIMIT));