: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
* Return true if all mimes is directory or files
* @param string $mime1 mimetype
* @param string $mime2 mimetype
* @author Dmitry (dio) Levashov
protected function isSameType($mime1, $mime2)
return ($mime1 == 'directory' && $mime1 == $mime2) || ($mime1 != 'directory' && $mime2 != 'directory');
* If file has required attr == $val - return file path,
* If dir has child with has required attr == $val - return child path
* @param string $path file path
* @param string $attr attribute name
* @param bool $val attribute value
* @author Dmitry (dio) Levashov
protected function closestByAttr($path, $attr, $val)
$stat = $this->stat($path);
$v = isset($stat[$attr]) ? $stat[$attr] : false;
return $stat['mime'] == 'directory'
? $this->childsByAttr($path, $attr, $val)
* Return first found children with required attr == $val
* @param string $path file path
* @param string $attr attribute name
* @param bool $val attribute value
* @author Dmitry (dio) Levashov
protected function childsByAttr($path, $attr, $val)
foreach ($this->scandirCE($path) as $p) {
if (($_p = $this->closestByAttr($p, $attr, $val)) != false) {
protected function isMyReload($target = '', $ARGtarget = '')
if ($this->rootModified || (!empty($this->ARGS['cmd']) && $this->ARGS['cmd'] === 'parents')) {
if (!empty($this->ARGS['reload'])) {
$ARGtarget = isset($this->ARGS['target']) ? $this->ARGS['target']
: ((isset($this->ARGS['targets']) && is_array($this->ARGS['targets']) && count($this->ARGS['targets']) === 1) ?
$this->ARGS['targets'][0] : '');
$ARGtarget = strval($ARGtarget);
return (strpos($ARGtarget, $this->id) === 0);
$target = strval($target);
return ($target === $ARGtarget);
* Update subdirs cache data
protected function updateSubdirsCache($path, $subdirs)
if (isset($this->cache[$path])) {
$this->cache[$path]['dirs'] = 1;
unset($this->cache[$path]['dirs']);
if ($this->sessionCaching['subdirs']) {
$this->sessionCache['subdirs'][$path] = $subdirs;
if ($this->sessionCaching['rootstat'] && $path == $this->root) {
unset($this->sessionCache['rootstat'][$this->getRootstatCachekey()]);
/***************** get content *******************/
* Return required dir's files info.
* If onlyMimes is set - return only dirs and files of required mimes
* @param string $path dir path
* @author Dmitry (dio) Levashov
protected function getScandir($path)
!isset($this->dirsCache[$path]) && $this->cacheDir($path);
foreach ($this->dirsCache[$path] as $p) {
if (($stat = $this->stat($p)) && empty($stat['hidden'])) {
* @param string $path parent dir path
* @param int $deep tree deep
* @author Dmitry (dio) Levashov
protected function gettree($path, $deep, $exclude = '')
!isset($this->dirsCache[$path]) && $this->cacheDir($path);
foreach ($this->dirsCache[$path] as $p) {
if ($stat && empty($stat['hidden']) && $p != $exclude && $stat['mime'] == 'directory') {
if ($deep > 0 && !empty($stat['dirs'])) {
$dirs = array_merge($dirs, $this->gettree($p, $deep - 1));
* @param string $path dir path
* @param string $q search string
* @throws elFinderAbortException
* @author Dmitry (dio) Levashov
protected function doSearch($path, $q, $mimes)
$matchMethod = empty($this->doSearchCurrentQuery['matchMethod']) ? 'searchMatchName' : $this->doSearchCurrentQuery['matchMethod'];
$timeout = $this->options['searchTimeout'] ? $this->searchStart + $this->options['searchTimeout'] : 0;
if ($timeout && $timeout < time()) {
$this->setError(elFinder::ERROR_SEARCH_TIMEOUT, $this->path($this->encode($path)));
foreach ($this->scandirCE($path) as $p) {
elFinder::extendTimeLimit($this->options['searchTimeout'] + 30);
if ($timeout && ($this->error || $timeout < time())) {
!$this->error && $this->setError(elFinder::ERROR_SEARCH_TIMEOUT, $this->path($this->encode($path)));
if (!$stat) { // invalid links
if (!empty($stat['hidden']) || !$this->mimeAccepted($stat['mime'], $mimes)) {
if ($this->doSearchCurrentQuery['excludes']) {
foreach ($this->doSearchCurrentQuery['excludes'] as $exclude) {
if ($this->stripos($name, $exclude) !== false) {
if ((!$mimes || $stat['mime'] !== 'directory') && $this->$matchMethod($name, $q, $p) !== false) {
$stat['path'] = $this->path($stat['hash']);
if ($this->URL && !isset($stat['url'])) {
$path = str_replace($this->separator, '/', substr($p, strlen($this->root) + 1));
$path = str_replace('%2F', '/', rawurlencode($this->convEncIn($path, true)));
$path = str_replace('%2F', '/', rawurlencode($path));
$stat['url'] = $this->URL . $path;
if ($stat['mime'] == 'directory' && $stat['read'] && !isset($stat['alias'])) {
if (!$this->options['searchExDirReg'] || !preg_match($this->options['searchExDirReg'], $p)) {
$result = array_merge($result, $this->doSearch($p, $q, $mimes));
/********************** manuipulations ******************/
* Copy file/recursive copy dir only in current volume.
* Return new file path or false.
* @param string $src source path
* @param string $dst destination dir path
* @param string $name new file name (optionaly)
* @throws elFinderAbortException
* @author Dmitry (dio) Levashov
protected function copy($src, $dst, $name)
elFinder::checkAborted();
$srcStat = $this->stat($src);
if (!empty($srcStat['thash'])) {
$target = $this->decode($srcStat['thash']);
if (!$this->inpathCE($target, $this->root)) {
return $this->setError(elFinder::ERROR_COPY, $this->path($srcStat['hash']), elFinder::ERROR_MKOUTLINK);
$stat = $this->stat($target);
return $stat && $this->symlinkCE($target, $dst, $name)
? $this->joinPathCE($dst, $name)
: $this->setError(elFinder::ERROR_COPY, $this->path($srcStat['hash']));
if ($srcStat['mime'] === 'directory') {
$testStat = $this->isNameExists($this->joinPathCE($dst, $name));
if (($testStat && $testStat['mime'] !== 'directory') || (!$testStat && !$testStat = $this->mkdir($this->encode($dst), $name))) {
return $this->setError(elFinder::ERROR_COPY, $this->path($srcStat['hash']));
$dst = $this->decode($testStat['hash']);
$stime = microtime(true);
foreach ($this->getScandir($src) as $stat) {
if (empty($stat['hidden'])) {
$ctime = microtime(true);
if (($ctime - $stime) > 2) {
elFinder::checkAborted();
$_src = $this->decode($stat['hash']);
if (!$this->copy($_src, $dst, $name)) {
$this->remove($dst, true); // fall back
return $this->setError($this->error, elFinder::ERROR_COPY, $this->_path($src));
$this->added[] = $testStat;
if ($this->options['copyJoin']) {
$test = $this->joinPathCE($dst, $name);
if ($this->isNameExists($test)) {
if ($res = $this->convEncOut($this->_copy($this->convEncIn($src), $this->convEncIn($dst), $this->convEncIn($name)))) {
$path = is_string($res) ? $res : $this->joinPathCE($dst, $name);
$this->added[] = $this->stat($path);
return $this->setError(elFinder::ERROR_COPY, $this->path($srcStat['hash']));
* Return new file path or false.
* @param string $src source path
* @param string $dst destination dir path
* @param string $name new file name
* @throws elFinderAbortException
* @author Dmitry (dio) Levashov
protected function move($src, $dst, $name)
$stat = $this->stat($src);
$stat['realpath'] = $src;
$this->rmTmb($stat); // can not do rmTmb() after _move()
$res = $this->convEncOut($this->_move($this->convEncIn($src), $this->convEncIn($dst), $this->convEncIn($name)));
// if moving it didn't work try to copy / delete
if ($this->copy($src, $dst, $name)) {
$res = $this->remove($src);
if ($stat['mime'] === 'directory') {
$this->updateSubdirsCache($dst, true);
$path = is_string($res) ? $res : $this->joinPathCE($dst, $name);
$this->added[] = $this->stat($path);
$this->removed[] = $stat;
return $this->setError(elFinder::ERROR_MOVE, $this->path($stat['hash']));
* Copy file from another volume.
* Return new file path or false.
* @param Object $volume source volume
* @param string $src source file hash
* @param string $destination destination dir path
* @param string $name file name
* @throws elFinderAbortException
* @author Dmitry (dio) Levashov
protected function copyFrom($volume, $src, $destination, $name)
elFinder::checkAborted();
if (($source = $volume->file($src)) == false) {
return $this->addError(elFinder::ERROR_COPY, '#' . $src, $volume->error());
$srcIsDir = ($source['mime'] === 'directory');
$errpath = $volume->path($source['hash']);
$thash = $this->encode($destination);
elFinder::$instance->trigger('paste.copyfrom', array(&$thash, &$name, '', elFinder::$instance, $this), $errors);
} catch (elFinderTriggerException $e) {
return $this->addError(elFinder::ERROR_COPY, $name, $errors);
if (!$this->nameAccepted($name, $srcIsDir)) {
return $this->addError(elFinder::ERROR_COPY, $name, $srcIsDir ? elFinder::ERROR_INVALID_DIRNAME : elFinder::ERROR_INVALID_NAME);
if (!$this->allowCreate($destination, $name, $srcIsDir)) {
return $this->addError(elFinder::ERROR_COPY, $name, elFinder::ERROR_PERM_DENIED);
return $this->addError(elFinder::ERROR_COPY, $errpath, elFinder::ERROR_PERM_DENIED);
$test = $this->isNameExists($this->joinPathCE($destination, $name));
if (($test && $test['mime'] != 'directory') || (!$test && !$test = $this->mkdir($this->encode($destination), $name))) {
return $this->addError(elFinder::ERROR_COPY, $errpath);
//$path = $this->joinPathCE($destination, $name);
$path = $this->decode($test['hash']);
foreach ($volume->scandir($src) as $entr) {
$this->copyFrom($volume, $entr['hash'], $path, $entr['name']);
if (!isset($source['size']) || $source['size'] > $this->uploadMaxSize) {
return $this->setError(elFinder::ERROR_UPLOAD_FILE_SIZE);
$mimeByName = $this->mimetype($source['name'], true);
if ($source['mime'] === $mimeByName) {
if (!$this->allowPutMime($source['mime']) || ($mimeByName && !$this->allowPutMime($mimeByName))) {
return $this->addError(elFinder::ERROR_UPLOAD_FILE_MIME, $errpath);
if (strpos($source['mime'], 'image') === 0 && ($dim = $volume->dimensions($src))) {
$dim = isset($dim['dim']) ? $dim['dim'] : null;
$source['width'] = $s[0];
$source['height'] = $s[1];
if (($fp = $volume->open($src)) == false
|| ($path = $this->saveCE($fp, $destination, $name, $source)) == false) {
$fp && $volume->close($fp, $src);
return $this->addError(elFinder::ERROR_COPY, $errpath);
$volume->close($fp, $src);
$this->added[] = $this->stat($path);;
* Remove file/ recursive remove dir
* @param string $path file path
* @param bool $force try to remove even if file locked
* @throws elFinderAbortException
* @author Dmitry (dio) Levashov
protected function remove($path, $force = false)
$stat = $this->stat($path);
return $this->setError(elFinder::ERROR_RM, $this->relpathCE($path), elFinder::ERROR_FILE_NOT_FOUND);
$stat['realpath'] = $path;
if (!$force && !empty($stat['locked'])) {
return $this->setError(elFinder::ERROR_LOCKED, $this->path($stat['hash']));
if ($stat['mime'] == 'directory' && empty($stat['thash'])) {
$ret = $this->delTree($this->convEncIn($path));