7

Is there a way to prevent the PHP GD image library from running out of memory? If too large an image is uploaded, GD tends to run out of memory, terminating the script. I'd like it to throw a catchable exception or something to that extend, but alas it doesn't.

Right now I'm using a cobbled-together script that first issues an ini_set('memory_limit', '128M'), if that works I'm usually all set. Depending on the server configuration though that may not be possible, so I'm falling back on an algorithm that tries to estimate the amount of memory needed (taking resolution, color depth, channels and a fudge factor into account), then compares it to memory_get_usage() if the function exists, otherwise does a rough estimate.

The whole thing works so far, but it's far from elegant and will fail in some edge cases, I'm sure. Is there any better way to do this, i.e. have GD fail gracefully if it has to, instead of grinding everything to a halt?

deceze
  • 510,633
  • 85
  • 743
  • 889
  • 1
    Large JPEG images (not-PNG or other types) can be resized whilst loading, see this answer for further details: http://stackoverflow.com/questions/12661/efficient-jpeg-image-resizing-in-php/4613341#4613341 – Steve-o Jan 06 '11 at 09:43
  • This would depend on how much ram you have. If you have 512mb of ram and you are trying to resize about a 10k pixel png image. You will hit 1.5GB in ram usage almost immediately. My suggestion is A) get more ram B) use functions for the building of your images destroying them and use a memory usage function to view it each processed image. Use flush functions to dump and clear the buffer... – JSG Nov 15 '19 at 15:28

6 Answers6

3

Buy more memory! :-P

Seriously though, it is impossible to handle being out of memory because any action you take would require more memory.

Your best bet is to limit the size of image being uploaded based on the current memory settings.

Nick Presta
  • 28,134
  • 6
  • 57
  • 76
  • 2
    LOL, buy me a host with more memory. ;-) Well, I'd at least like GD to estimate its own memory usage, instead of me having to do the error-prone guesswork and then hold my breath. I can't just limit the image by file size. A small file with a highly-compressed, high-resolution JPG may take up more memory than a large file with a low-resolution PNG. That's why I have to fall back on my above mentioned calculation. – deceze Jul 13 '09 at 03:08
2

After you create an image.

imagepng($image);
imagedestroy($image);

will remove the memory problem

Kemal Fadillah
  • 9,760
  • 3
  • 45
  • 63
  • This should be marked as the answer, it worked like a charm for me. – Vic Dec 23 '15 at 19:17
  • 2
    This should **not** be marked as the answer. Destroying an image saves memory usage, but in no way makes GD behave more gracefully. – Glutexo Mar 01 '16 at 13:28
  • 2
    Downvote. This is not a solution, but a standard procedure to avoid memory leaks. It won't stop GD from causing a memory overflow if one image alone is already big enough to hit the memory limit. – StrikeAgainst Nov 20 '19 at 21:44
1

There is another way to do it, but it can be time consuming, as certain parts of the image editing process would be repeated a number of times, but you can set the memory limit to your estimated value, then try to process the image, if it fails catch the exception, increase the memory limit, then process the image again - repeating this until you succeed or reach a certain memory limit - at which point you'd throw an error message to the user explaining that their image is too big to be used.

Edit: To catch the out-of-memory error, you could use this solution: http://au2.php.net/set_error_handler#35622

jsnfwlr
  • 3,638
  • 2
  • 23
  • 25
  • Read again, AFAIK there's nothing catchable being thrown. It's a one-shot works-or-it-doesn't operation. Unless you can tell me how to catch an out-of-memory error, which is what I'm asking for. :) – deceze Jul 14 '09 at 02:02
  • I'll have to see if this actually helps, as noted by Nick, I'd have to use more memory to deal with the error after it occurred. – deceze Jul 26 '09 at 05:38
1

Do some tests to check how much memory each gd function need.

  • imagecreatetruecolor seems to need width*height*5 bytes.

  • imagepng seems to need width*height*4 bytes.

Littm
  • 4,923
  • 4
  • 30
  • 38
sebbu
  • 126
  • 1
  • 6
  • Why would `imagecreatetruecolor` need 5 bytes per pixel? Sounds like an odd number. – Luke Jun 12 '14 at 07:46
  • because alpha support was added a long time after imagecreate, and a lots of functions probably had assumptions than the 4th byte was always 0, so it couldn't be used... or they thought/saw it was too complex to use it and created a new one. – sebbu Jul 17 '14 at 19:01
  • Have you any experience also when loading existing images on top of it? e.g. for jpg or png? I use x * y * ~5 for jpg, ~8 for png, on top of the current mem usage. if that exceed mem limit i set an exception. But: Setting 64M as limit and having a 2MB uploaded jpg can sometimes break the operation. Jpg seems to use sometimes more memory. Compression? Any other exif data? where i can improve the calculation? – f b Jun 16 '17 at 07:55
  • all calls to imagepng, imagejpeg, imagegif, imagebmp, imagewbmp, imagexbm, imagewebp, imagegd, imagegd2 will use width * height * some coef bytes, in addition to the current ressources existing (from all the imagecreate, imagecreatetruecolor and imagecreatefrom*) (and maybe some temporary memory for compression, format & all). imageloadfont & imagepsloadfont will use also some memory. old resource must be destroyed with imdestroy to avoid leakages. – sebbu Jul 09 '17 at 00:31
1

To catch PHP's fatal errors, like "Out of memory" or "PHP Fatal error: Allowed memory size of 8388608 bytes exhausted (tried to allocate … bytes) in", see here : http://php.net/manual/en/function.set-error-handler.php#88401

  • 1
    Once a PHP script is out of memory, it can't call the shutdown function because that would require the allocation of more memory. – scotts Feb 12 '10 at 19:26
0

Your best bet is to stop trying to figure out how much ram it will need, and just max it out at the outset - if you have 4 GB available, tell the image script to use between 2 and 4 GB or so, and when the script ends, have it go back to normal, that will cover off all potentially fatal situations. That's the only "Fail-safe" way I can think of anyway ...

jsnfwlr
  • 3,638
  • 2
  • 23
  • 25
  • That's what I'm trying to do, but that's rarely possible on shared hosts. For those cases I'm doing the best-guess calculations to prevent hang-ups. – deceze Jul 13 '09 at 07:31
  • 1
    Setting the PHP memory limit equal to the total amount of RAM the system has, or anywhere remotely near it, will allow users to DOS you via your image script. Figuring out how much RAM is needed beforehand is the only way I can think of that will prevent this type of DOS. – Ted Phillips Aug 13 '17 at 19:23