prepareErrorHandler(); $result = parent::create(); $this->restoreErrorHandler(); if(!file_exists($this->destination->root)) { $message = str::template('Thumbnail creation for "{file}" failed. Please ensure, that the thumbs directory is writable and your driver configuration is correct.', [ 'file' => static::$_errorData['file'], ]); static::sendErrorResponse($message); exit; } return $result; } private function prepareErrorHandler() { // Reserve one additional megabyte of memory to make // catching of out-of-memory errors more reliable. // The variable’s content is deleted in the shutdown // function to have more available memory to prepare an // error. static::$_reservedMemory = str_repeat('#', 1024 * 1024); $dimensions = $this->source->dimensions(); $filename = str_replace(kirby()->roots()->index() . DS, '', $this->source->root()); $asset = new ProxyAsset($this->destination->root); $asset->options($this->options); $asset->original($this->source); $targetDimensions = $asset->dimensions(); static::$_errorData = [ 'file' => $filename, 'width' => $dimensions->width, 'height' => $dimensions->height, 'size' => $this->source->size(), 'targetWidth' => $targetDimensions->width, 'targetHeight' => $targetDimensions->height, ]; static::$_displayErrors = ini_get('display_errors'); static::$_errorReporting = error_reporting(); error_reporting(E_ALL); ini_set('display_errors', 0); if (!static::$_errorListening) { // As of PHP 7.0 there is not way of de-registering a // shutdown callback. So we only register it once at // the first time, this method is called. static::$_errorListening = true; register_shutdown_function([__CLASS__, 'shutdownCallback']); } static::$_creating = true; } private function restoreErrorHandler() { // Delete the reserved memory, because if thumbnail // creation succeeded, it is not needed any more. static::$_reservedMemory = null; ini_set('display_errors', static::$_displayErrors); error_reporting(static::$_errorReporting); static::$_creating = false; } public static function shutdownCallback() { // Delete the reserved memory to have more memory for // preparing an error message. static::$_reservedMemory = null; $error = error_get_last(); if(!$error) return; if($error['type'] == E_ERROR || $error['type'] === E_WARNING) { if(str::contains($error['message'], 'Allowed Memory Size')) { $message = str::template('Thumbnail creation for "{file}" failed, because source image is probably too large ({width} × {height} pixels / {size}) To fix this issue, increase the memory limit of PHP or upload a smaller version of this image.', [ 'file' => static::$_errorData['file'], 'width' => number_format(static::$_errorData['width']), 'height' => number_format(static::$_errorData['height']), 'size' => number_format(static::$_errorData['size'] / (1024 * 1024), 2) . " MB", ]); static::sendErrorResponse($message); } else { static::sendErrorResponse($error['message']); } } } public static function sendErrorResponse($message = '') { // Make sure, that the error message is non-cachable header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0"); header("Cache-Control: post-check=0, pre-check=0", false); header("Pragma: no-cache"); if(static::$_errorFormat === 'image') { // The returned error image is an SVG file, because it // can be created just by joined a couple of XML tags // together and is supported by every modern browser, // starting with IE 9 (which is of course not // modern any more …). header('Content-Type: image/svg+xml'); // Although this is technically not correct, we have // to send status code 200, otherwise the image does // not show up in Firefox and Safari, although it // works with code 500 in Chrome and Edge. Also tested // in IE 10, IE 11 http_response_code(200); $width = static::$_errorData['targetWidth']; $height = static::$_errorData['targetHeight']; // Return an SVG File with the thumb’s dimensions // Icon Credit: fontawesome.io ?>

'', 'code' => 500, 'message' => $message, 'data' => [ 'file' => static::$_errorData, ], ]); } exit; } }