: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
return $this->setError(elFinder::ERROR_RM, $this->path($stat['hash']));
if ($this->convEncOut(!$this->_unlink($this->convEncIn($path)))) {
return $this->setError(elFinder::ERROR_RM, $this->path($stat['hash']));
$this->removed[] = $stat;
/************************* thumbnails **************************/
* Return thumbnail file name for required file
* @param array $stat file stat
* @author Dmitry (dio) Levashov
protected function tmbname($stat)
$name = $stat['hash'] . (isset($stat['ts']) ? $stat['ts'] : '') . '.png';
if (strlen($name) > 255) {
$name = $this->id . md5($stat['hash']) . $stat['ts'] . '.png';
* Return thumnbnail name if exists
* @param string $path file path
* @param array $stat file stat
* @author Dmitry (dio) Levashov
protected function gettmb($path, $stat)
if ($this->tmbURL && $this->tmbPath) {
// file itself thumnbnail
if (strpos($path, $this->tmbPath) === 0) {
$name = $this->tmbname($stat);
$tmb = $this->tmbPath . DIRECTORY_SEPARATOR . $name;
if ($this->options['tmbGcMaxlifeHour'] && $this->options['tmbGcPercentage'] > 0) {
* Return true if thumnbnail for required file can be created
* @param string $path thumnbnail path
* @param array $stat file stat
* @param bool $checkTmbPath
* @author Dmitry (dio) Levashov
protected function canCreateTmb($path, $stat, $checkTmbPath = true)
$_mimes = array('image/jpeg', 'image/png', 'image/gif', 'image/x-ms-bmp');
if (function_exists('imagecreatefromwebp')) {
$_mimes[] = 'image/webp';
$gdMimes = array_flip($_mimes);
$imgmgPS = array_flip(array('application/postscript', 'application/pdf'));
if ((!$checkTmbPath || $this->tmbPathWritable)
&& (!$this->tmbPath || strpos($path, $this->tmbPath) === false) // do not create thumnbnail for thumnbnail
$mime = strtolower($stat['mime']);
list($type) = explode('/', $mime);
if (!empty($this->imgConverter)) {
if (isset($this->imgConverter[$mime])) {
if (isset($this->imgConverter[$type])) {
($type === 'image' && ($this->imgLib === 'gd' ? isset($gdMimes[$stat['mime']]) : true))
(ELFINDER_IMAGEMAGICK_PS && isset($imgmgPS[$stat['mime']]) && $this->imgLib !== 'gd')
* Return true if required file can be resized.
* By default - the same as canCreateTmb
* @param string $path thumnbnail path
* @param array $stat file stat
* @author Dmitry (dio) Levashov
protected function canResize($path, $stat)
return $this->canCreateTmb($path, $stat, false);
* Create thumnbnail and return it's URL on success
* @param string $path file path
* @internal param string $mime file mime type
* @throws elFinderAbortException
* @throws ImagickException
* @author Dmitry (dio) Levashov
protected function createTmb($path, $stat)
if (!$stat || !$this->canCreateTmb($path, $stat)) {
$name = $this->tmbname($stat);
$tmb = $this->tmbPath . DIRECTORY_SEPARATOR . $name;
$mime = strtolower($stat['mime']);
list($type) = explode('/', $mime);
if (isset($this->imgConverter[$mime])) {
$imgConverter = $this->imgConverter[$mime]['func'];
if (!empty($this->imgConverter[$mime]['maxlen'])) {
$maxlength = intval($this->imgConverter[$mime]['maxlen']);
} else if (isset($this->imgConverter[$type])) {
$imgConverter = $this->imgConverter[$type]['func'];
if (!empty($this->imgConverter[$type]['maxlen'])) {
$maxlength = intval($this->imgConverter[$type]['maxlen']);
if ($imgConverter && !is_callable($imgConverter)) {
// copy image into tmbPath so some drivers does not store files on local fs
if (($src = $this->fopenCE($path, 'rb')) == false) {
if (($trg = fopen($tmb, 'wb')) == false) {
$this->fcloseCE($src, $path);
stream_copy_to_stream($src, $trg, $maxlength);
$this->fcloseCE($src, $path);
if (!call_user_func_array($imgConverter, array($tmb, $stat, $this))) {
file_exists($tmb) && unlink($tmb);
$tmbSize = $this->tmbSize;
if ($this->imgLib === 'imagick') {
$imagickTest = new imagick($tmb . '[0]');
if (($this->imgLib === 'imagick' && !$imagickTest) || ($s = getimagesize($tmb)) === false) {
if ($this->imgLib === 'imagick') {
$bgcolor = $this->options['tmbBgColor'];
if ($bgcolor === 'transparent') {
$bgcolor = 'rgba(255, 255, 255, 0.0)';
$imagick = new imagick();
$imagick->setBackgroundColor(new ImagickPixel($bgcolor));
$imagick->readImage($this->getExtentionByMime($stat['mime'], ':') . $tmb . '[0]');
$imagick->setImageFormat('png');
$imagick->writeImage($tmb);
if (($s = getimagesize($tmb)) !== false) {
} else if ($this->imgLib === 'convert') {
$convParams = $this->imageMagickConvertPrepare($tmb, 'png', 100, array(), $stat['mime']);
$cmd = sprintf('%s -colorspace sRGB -trim -- %s %s', ELFINDER_CONVERT_PATH, $convParams['quotedPath'], $convParams['quotedDstPath']);
if ($this->procExec($cmd) === 0) {
if (($s = getimagesize($tmb)) !== false) {
if (function_exists('gd_info') && ($s = getimagesize($tmb))) {
file_exists($tmb) && unlink($tmb);
/* If image smaller or equal thumbnail size - just fitting to thumbnail square */
if ($s[0] <= $tmbSize && $s[1] <= $tmbSize) {
$result = $this->imgSquareFit($tmb, $tmbSize, $tmbSize, 'center', 'middle', $this->options['tmbBgColor'], 'png');
if ($this->options['tmbCrop']) {
/* Resize and crop if image bigger than thumbnail */
if (!(($s[0] > $tmbSize && $s[1] <= $tmbSize) || ($s[0] <= $tmbSize && $s[1] > $tmbSize)) || ($s[0] > $tmbSize && $s[1] > $tmbSize)) {
$result = $this->imgResize($tmb, $tmbSize, $tmbSize, true, false, 'png');
if ($result && ($s = getimagesize($tmb)) != false) {
$x = $s[0] > $tmbSize ? intval(($s[0] - $tmbSize) / 2) : 0;
$y = $s[1] > $tmbSize ? intval(($s[1] - $tmbSize) / 2) : 0;
$result = $this->imgCrop($result, $tmbSize, $tmbSize, $x, $y, 'png');
$result = $this->imgResize($tmb, $tmbSize, $tmbSize, true, true, 'png');
if ($s = getimagesize($tmb)) {
if ($s[0] !== $tmbSize || $s[1] !== $tmbSize) {
$result = $this->imgSquareFit($result, $tmbSize, $tmbSize, 'center', 'middle', $this->options['tmbBgColor'], 'png');
* @param string $path image file
* @param int $width new width
* @param int $height new height
* @param bool $keepProportions crop image
* @param bool $resizeByBiggerSide resize image based on bigger side if true
* @param string $destformat image destination format
* @param int $jpgQuality JEPG quality (1-100)
* @param array $options Other extra options
* @throws elFinderAbortException
* @author Dmitry (dio) Levashov
* @author Alexey Sukhotin
protected function imgResize($path, $width, $height, $keepProportions = false, $resizeByBiggerSide = true, $destformat = null, $jpgQuality = null, $options = array())
if (($s = getimagesize($path)) == false) {
$jpgQuality = $this->options['jpgQuality'];
list($orig_w, $orig_h) = array($s[0], $s[1]);
list($size_w, $size_h) = array($width, $height);
if (empty($options['unenlarge']) || $orig_w > $size_w || $orig_h > $size_h) {
if ($keepProportions == true) {
/* Resizing by biggest side */
if ($resizeByBiggerSide) {
$size_h = round($orig_h * $width / $orig_w);
$size_w = round($orig_w * $height / $orig_h);
$size_w = round($orig_w * $height / $orig_h);
$size_h = round($orig_h * $width / $orig_w);
elFinder::extendTimeLimit(300);
$img = new imagick($path);
// Imagick::FILTER_BOX faster than FILTER_LANCZOS so use for createTmb
// resize bench: http://app-mgng.rhcloud.com/9
// resize sample: http://www.dylanbeattie.net/magick/filters/result.html
$filter = ($destformat === 'png' /* createTmb */) ? Imagick::FILTER_BOX : Imagick::FILTER_LANCZOS;
$ani = ($img->getNumberImages() > 1);
if ($ani && is_null($destformat)) {
$img = $img->coalesceImages();
$img->resizeImage($size_w, $size_h, $filter, 1);
} while ($img->nextImage());
$img->optimizeImageLayers();
$result = $img->writeImages($path, true);
$img->setFirstIterator();
if (strtoupper($img->getImageFormat()) === 'JPEG') {
$img->setImageCompression(imagick::COMPRESSION_JPEG);
$img->setImageCompressionQuality($jpgQuality);
if (isset($options['preserveExif']) && !$options['preserveExif']) {
$orientation = $img->getImageOrientation();
} catch (ImagickException $e) {
$img->setImageOrientation($orientation);
if ($this->options['jpgProgressive']) {
$img->setInterlaceScheme(Imagick::INTERLACE_PLANE);
$img->resizeImage($size_w, $size_h, $filter, true);
$result = $this->imagickImage($img, $path, $destformat, $jpgQuality);
$result = $img->writeImage($path);
return $result ? $path : false;
extract($this->imageMagickConvertPrepare($path, $destformat, $jpgQuality, $s));
* @var string $deconstruct
* @var string $jpgQuality
* @var string $quotedPath
* @var string $quotedDstPath
$filter = ($destformat === 'png' /* createTmb */) ? '-filter Box' : '-filter Lanczos';
$strip = (isset($options['preserveExif']) && !$options['preserveExif']) ? ' -strip' : '';
$cmd = sprintf('%s %s%s%s%s%s %s -geometry %dx%d! %s %s', ELFINDER_CONVERT_PATH, $quotedPath, $coalesce, $jpgQuality, $strip, $interlace, $filter, $size_w, $size_h, $deconstruct, $quotedDstPath);
if ($this->procExec($cmd) === 0) {
return $result ? $path : false;
elFinder::expandMemoryForGD(array($s, array($size_w, $size_h)));
$img = $this->gdImageCreate($path, $s['mime']);
if ($img && false != ($tmp = imagecreatetruecolor($size_w, $size_h))) {
if ($s[2] === IMAGETYPE_GIF && (!$destformat || $destformat === 'gif')) {
$bgIdx = imagecolortransparent($img);
$c = imagecolorsforindex($img, $bgIdx);
$bgNum = imagecolorallocate($tmp, $c['red'], $c['green'], $c['blue']);
imagefill($tmp, 0, 0, $bgNum);
imagecolortransparent($tmp, $bgNum);
$this->gdImageBackground($tmp, 'transparent');
if (!imagecopyresampled($tmp, $img, 0, 0, 0, 0, $size_w, $size_h, $s[0], $s[1])) {
$result = $this->gdImage($tmp, $path, $destformat, $s['mime'], $jpgQuality);
return $result ? $path : false;
* @param string $path image file
* @param int $width crop width
* @param int $height crop height
* @param bool $x crop left offset
* @param bool $y crop top offset
* @param string $destformat image destination format
* @param int $jpgQuality JEPG quality (1-100)
* @throws elFinderAbortException
* @author Dmitry (dio) Levashov
* @author Alexey Sukhotin
protected function imgCrop($path, $width, $height, $x, $y, $destformat = null, $jpgQuality = null)
if (($s = getimagesize($path)) == false) {
$jpgQuality = $this->options['jpgQuality'];
elFinder::extendTimeLimit(300);
$img = new imagick($path);