Problem/Motivation
Executing something like this
<?php
$test = \Drupal::service('image.factory')->get(NULL, 'gd');
$test->createNew(20000, 20000);
?>
leads to a fatal error
PHP Fatal error: Allowed memory size of 268435456 bytes exhausted (tried to allocate 80000 bytes) in /[...]/core/modules/system/src/Plugin/ImageToolkit/Operation/gd/CreateNew.php on line 94
and WSOD.
This is because GD imagexxx functions do not return gracefully in case of memory allocation failures.
Proposed resolution
Take cues from the preliminary memory availability check done in the color module, and from this comment on PHP site, and introduce a memory checking method that can be called on load, create_new, and rotate operations before invoking imagexxx functions.
Remaining tasks
- review patch
User interface changes
None.
API changes
- introduce 2 public methods specific for GDToolkit,
::checkAvailableMemory()
and::getMemoryInfo()
. Used those methods in GDToolkit::load(), and in the 'gd_create_new' and 'gd_rotate' image toolkit operation. Added a PHP Unit test class to simulate insufficient memory. - added a
Bytes::toUnitAndSize()
method to return separately a unit of measurement and the size expressed in the unit of measurement, given a byte quantity. This is neeeded becauseformat_size()
returns a translatable object, which cannot be used in formatting messages for exceptions. Added unit test for that. Refactoredformat_size()
to useBytes::toUnitAndSize()
. Added test cases for formatting '0 bytes' and a quantity of bytes that in format_size was resulting improperly rounded. - added a
EnvironmentMemory
dynamic class that needs to be instantiated to check memory limit or memory available. Needed that to be able to provide PHP Unit test that stub the currently used memory. Added PHP unit test for that. - given the above, the static
Environment::checkMemoryLimit
is refactored to useEnvironmentMemory
. That method and entire class are duplicated - tentatively marked for deprecation.
Data model changes
None