-
Notifications
You must be signed in to change notification settings - Fork 819
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
API: Prevent large images from repeatedly crashing PHP on resize #2753
Conversation
Hi, thanks for keeping up with this. I actually developed a slightly different solution the last time I played with it, but never got around to creating a pull: jakr@5913ad0 I used a slightly different method for cleaning up. Since we are not really deleting the ImageBackend, I thought we did not have to introduce onBeforeDelete and could just directly pass the filename information to the backend, see cleanupBeforeDelete. Feel free to mix and match the approaches. |
Hi @jakr, Our solutions are quite similar, I was simply matching the existing naming convention (for Thanks for the work on the memory calculations, I copied that from your original PR :) |
looks very good. I know, you wrote it's a quick fix, but may I still make 1 feature request: |
@Zauberfisch For that example it wouldn’t resample the image, so it wouldn’t display it at all - rather than showing the full size image, it simply won’t show one. A message of some kind in the CMS is the eventual goal, I might look at addressing that in a separate pull request if I get time. I’ve been trying to think of how best to achieve it without coupling stuff to GD. There are a few different places this will need to be addressed, off the top of my head these include:
I don’t know how we can manage to display a useful error message (i.e. “Image is too large to be resized, please try a smaller image” instead of “Image unavailable”). Just running ideas from the top of my head here, but perhaps something like:
public static function diagnose_failure($filename) {
if ( ! $this->checkAvailableMemory($filename)) {
return "Image is too large to be resampled. Please try a smaller image";
} else if($this->failedResample($filename)) {
return "Image failed to resample - it may be corrupt or too large";
} else {
return "Image failed to resample - an unknown error occurred";
}
} |
Updated to avoid problems with image manipulations causing fatal errors after the image has been loaded into memory. I’ve adjusted the ‘lock file’ logic to use a destructor to remove the file: if all is well In some situations, the image would pass memory checks and be loaded into Thanks to @Zauberfisch for discovering and helping with this. |
Hi Loz, Thanks for working on this. Maybe you already thought of this but may be good to include a Dev task "Remove all image lock files". One case where this could be useful is if the memory limit has been increased so it may be worth having a second attempt at resampling any files which failed on the previous memory limit. |
Hi @jonom, No I’ve not looked at that yet, I was thinking of perhaps integrating it with the One thing I’ve thought of is that the lock file names aren’t “modification-specific” - if Perhaps we could pass the cache file name returned by |
Modification-specific lock files would certainly be handy for tracing the source of any crashes - especially if there was a report that listed all the lock files to be found in the assets folder. But if it's a lot of work I wonder if it would be worth it. Whenever I've had a GD memory crash in SilverStripe, the cause was always a too-high resolution image that should have been down-sampled before uploading. So I would say the core of the problem is identifying those problematic images so that they can be replaced or removed. In that case a single lock file and a simple "This image may cause problems" indicator in the CMS should get the job done most of the time. |
Please don't create any special logic for crashes on images that are just slightly too large and only crash in a single resolution.
I hope that no site will have hundreds of lockfiles lying about, so I think that even the admin task will be overkill, but if you want to write it, go ahead. |
Is there a reason to use lock files rather than the caching functionality? You wouldn't really want lock files to get transferred around with your assets. |
@jakr I disagree, I have a site that went live last week that had exactly that problem. the image itself did not crash. 1 re size did not crash it either, but performing a 2nd operation on that image resulted in a crash for about 3 out of 100 images. |
@ajshort This was just the functionality discussed on the Google Group, but I’d welcome other suggestions 😃. Can I ask what “caching functionality” refers to? Do you mean using @jakr / @Zauberfisch I agree that hundreds of lock files left over would suck (perhaps less so if they’re stored in the |
Check out |
@ajshort Ah I see, that’s a neat idea. Just to make sure I’m understanding fully, we’d have something like:
I guess we could also clear the cache on flush then as well. |
I wouldn't clear it on flush, I'd like a separated task better. You often have to flush (new files, changed statics, ...), but I might not always want to clear the image locks |
Yep - I'd be tempted to hash together the file's name, mtime, and any arguments and just use it as a simple lookup table. |
I've had very little time to look at this lately, so I've pushed up what little work I've done on this for comments on the implementation. On my todo list:
|
Okay, reworked to use
Hopefully, if I/someone ever gets round to it, that’ll allow the method/arguments to be extracted from the cache to provide devs/CMS users with info as to why the image failed to resample. |
Add unit tests, fix incorrect class instanciation Prevent image manipulation methods from causing repeat GD failures Use destructor to handle lock file removal Remove attempts to call parent destructor - there isn't one First draft of using SS_Cache API Updated unit tests, minor fixes/tweaks Updated onBeforeDelete logic and unit tests Add dev task for clearing cache of image manipulations Store manipulation method/arguments in more accessible way in cache API: Prevent large images from repeatedly crashing PHP on resize
Re-opened against master as I feel this is too big a change for 3.1: #2859. |
@@ -97,6 +97,16 @@ public function hasImageResource() { | |||
} | |||
|
|||
/** | |||
* @todo Implement memory checking/lock file for Imagick? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In my experience, Imagick doesn't seems to have the same memory limitations for resizing.
Shouldn't the |
Hey @jedateach, This behaviour was merged into master instead in #2859. I did miss out |
This is a (late) follow up to the discussion here about GD crashing when attempting to open large or high DPI images.
The Google Group discussion involved ideas around “image unavailable” icons in the CMS, this setup (by storing which manipulation failed) will hopefully pave the way for that functionality to be added later, while addressing the immediate issue of completely crashing entire sections of websites.
Implements the same method for checking available memory as #2569, though it’s different to the method Ingo suggested. I’m not really sure which is more robust, the method in the php.net comments doesn’t take into account that bits and channels aren’t always present in the image info.
Marked as an API change as I’ve added a few methods to the
Image_Backend
interface. Have only tested the basic functionality so far, unit tests etc are still todo. Perhaps this would be better opened against master and delayed until 3.2?Doesn’t cause any issues with the CMS, the images just don’t appear for now:
All comments welcome.