: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
if (!$deny && ($allow === true)) { // match only allow
}// else (both match | no match | match only deny) { deny }
} else { // array('deny', 'allow'), default is to 'allow' - this is the default rule
$res = true; // default is allow
if (($deny === true) && !$allow) { // match only deny
} // else (both match | no match | match only allow) { allow }
* @param string $path file cache
* @author Dmitry (dio) Levashov
protected function stat($path)
if ($path === false || is_null($path)) {
$is_root = ($path == $this->root);
$rootKey = $this->getRootstatCachekey();
if ($this->sessionCaching['rootstat'] && !isset($this->sessionCache['rootstat'])) {
$this->sessionCache['rootstat'] = array();
if (!isset($this->cache[$path]) && !$this->isMyReload()) {
// need $path as key for netmount/netunmount
if ($this->sessionCaching['rootstat'] && isset($this->sessionCache['rootstat'][$rootKey])) {
if ($ret = $this->sessionCache['rootstat'][$rootKey]) {
if ($this->options['rootRev'] === $ret['rootRev']) {
if (isset($this->options['phash'])) {
$ret['phash'] = $this->options['phash'];
if (isset($this->cache[$path])) {
$ret = $this->cache[$path];
if ($is_root && !empty($this->options['rapidRootStat']) && is_array($this->options['rapidRootStat']) && !$this->needOnline) {
$ret = $this->updateCache($path, $this->options['rapidRootStat'], true);
$ret = $this->updateCache($path, $this->convEncOut($this->_stat($this->convEncIn($path))), true);
if ($is_root && !empty($rootKey) && $this->sessionCaching['rootstat']) {
$this->rootModified = false;
$this->sessionCache['rootstat'][$rootKey] = $ret;
if (isset($this->options['phash'])) {
$ret['phash'] = $this->options['phash'];
} else if (!empty($rootKey) && $this->sessionCaching['rootstat']) {
unset($this->sessionCache['rootstat'][$rootKey]);
* Get root stat extra key values
* @return array stat extras
protected function getRootStatExtra()
$stat['name'] = $this->rootName;
$stat['rootRev'] = $this->options['rootRev'];
$stat['options'] = $this->options(null);
* Return fileinfo based on filename
* For item ID based path file system
* Please override if needed on each drivers
* @param string $path file cache
protected function isNameExists($path)
return $this->stat($path);
* Put file stat in cache and return it
* @param string $path file path
* @param array $stat file stat
* @author Dmitry (dio) Levashov
protected function updateCache($path, $stat)
if (empty($stat) || !is_array($stat)) {
return $this->cache[$path] = array();
if (func_num_args() > 2) {
$fromStat = func_get_arg(2);
$stat['hash'] = $this->encode($path);
$root = $path == $this->root;
$stat = array_merge($stat, $this->getRootStatExtra());
if (!isset($stat['name']) || $stat['name'] === '') {
$stat['name'] = $this->basenameCE($path);
if (empty($stat['phash'])) {
$parent = $this->dirnameCE($path);
$stat['phash'] = $this->encode($parent);
$parent = $this->decode($stat['phash']);
if (isset($stat['name']) && !$jeName = json_encode($stat['name'])) {
return $this->cache[$path] = array();
if ($this->options['utf8fix'] && $this->options['utf8patterns'] && $this->options['utf8replace']) {
$stat['name'] = json_decode(str_replace($this->options['utf8patterns'], $this->options['utf8replace'], $jeName));
if (!isset($stat['size'])) {
$stat['size'] = 'unknown';
$mime = isset($stat['mime']) ? $stat['mime'] : '';
if ($isDir = ($mime === 'directory')) {
$stat['volumeid'] = $this->id;
if (empty($stat['mime']) || $stat['size'] == 0) {
$stat['mime'] = $this->mimetype($stat['name'], true, $stat['size'], $mime);
$stat['mime'] = $this->mimeTypeNormalize($stat['mime'], $stat['name']);
$stat['read'] = intval($this->attr($path, 'read', isset($stat['read']) ? !!$stat['read'] : null, $isDir));
$stat['write'] = intval($this->attr($path, 'write', isset($stat['write']) ? !!$stat['write'] : null, $isDir));
if ($this->options['type'] !== '') {
$stat['type'] = $this->options['type'];
// lock when parent directory is not writable
if (!isset($stat['locked'])) {
$pstat = $this->stat($parent);
if (isset($pstat['write']) && !$pstat['write']) {
if ($this->attr($path, 'locked', isset($stat['locked']) ? !!$stat['locked'] : null, $isDir)) {
} elseif ($this->attr($path, 'hidden', isset($stat['hidden']) ? !!$stat['hidden'] : null, $isDir)
|| !$this->mimeAccepted($stat['mime'])) {
if ($stat['read'] && empty($stat['hidden'])) {
// caching parent's subdirs
$this->updateSubdirsCache($parent, true);
// for dir - check for subdirs
if ($this->options['checkSubfolders']) {
if (!isset($stat['dirs']) && intval($this->options['checkSubfolders']) === -1) {
if (isset($stat['dirs'])) {
if ($stat['dirs'] == -1) {
$stat['dirs'] = ($this->sessionCaching['subdirs'] && isset($this->sessionCache['subdirs'][$path])) ? (int)$this->sessionCache['subdirs'][$path] : -1;
} elseif (!empty($stat['alias']) && !empty($stat['target'])) {
$stat['dirs'] = isset($this->cache[$stat['target']])
? intval(isset($this->cache[$stat['target']]['dirs']))
: $this->subdirsCE($stat['target']);
} elseif ($this->subdirsCE($path)) {
if ($this->options['dirUrlOwn'] === true) {
// Set `null` to use the client option `commandsOptions.info.nullUrlDirLinkSelf = true`
} else if ($this->options['dirUrlOwn'] === 'hide') {
// to hide link in info dialog of the elFinder client
// for files - check for thumbnails
$p = isset($stat['target']) ? $stat['target'] : $path;
if ($this->tmbURL && !isset($stat['tmb']) && $this->canCreateTmb($p, $stat)) {
$tmb = $this->gettmb($p, $stat);
$stat['tmb'] = $tmb ? $tmb : 1;
if (!isset($stat['url']) && $this->URL && $this->encoding) {
$_path = str_replace($this->separator, '/', substr($path, strlen($this->root) + 1));
$stat['url'] = rtrim($this->URL, '/') . '/' . str_replace('%2F', '/', rawurlencode((substr(PHP_OS, 0, 3) === 'WIN') ? $_path : $this->convEncIn($_path, true)));
if (!empty($stat['alias']) && !empty($stat['target'])) {
$stat['thash'] = $this->encode($stat['target']);
//$this->cache[$stat['target']] = $stat;
$this->cache[$path] = $stat;
if (!$fromStat && $root && $this->sessionCaching['rootstat']) {
// to update session cache
* Get stat for folder content and put in cache
* @author Dmitry (dio) Levashov
protected function cacheDir($path)
$this->dirsCache[$path] = array();
foreach ($this->scandirCE($path) as $p) {
if (($stat = $this->stat($p)) && empty($stat['hidden'])) {
if (!$hasDir && $stat['mime'] === 'directory') {
$this->dirsCache[$path][] = $p;
$this->updateSubdirsCache($path, $hasDir);
* @author Dmitry (dio) Levashov
protected function clearcache()
$this->cache = $this->dirsCache = array();
* @param string $path file path
* @param string|bool $name
* @param string $mime was notified from the volume driver
* @author Dmitry (dio) Levashov
protected function mimetype($path, $name = '', $size = null, $mime = null)
} else if ($name === true) {
if (!$this instanceof elFinderVolumeLocalFileSystem) {
$ext = (false === $pos = strrpos($name, '.')) ? '' : strtolower(substr($name, $pos + 1));
if (!$nameCheck && $size === null) {
$size = file_exists($path) ? filesize($path) : -1;
if (!$nameCheck && is_readable($path) && $size > 0) {
if ($this->mimeDetect === 'finfo') {
$type = finfo_file($this->finfo, $path);
} else if ($this->mimeDetect === 'mime_content_type') {
$type = mime_content_type($path);
$type = explode(';', $type);
if ($ext && preg_match('~^application/(?:octet-stream|(?:x-)?zip|xml)$~', $type)) {
// load default MIME table file "mime.types"
if (!elFinderVolumeDriver::$mimetypesLoaded) {
elFinderVolumeDriver::loadMimeTypes();
if (isset(elFinderVolumeDriver::$mimetypes[$ext])) {
$type = elFinderVolumeDriver::$mimetypes[$ext];
} else if ($ext === 'js' && preg_match('~^text/~', $type)) {
$type = 'text/javascript';
$type = elFinderVolumeDriver::mimetypeInternalDetect($name);
if ($type === 'unknown') {
$type = ($size == 0) ? 'text/plain' : $this->options['mimeTypeUnknown'];
// mime type normalization
$type = $this->mimeTypeNormalize($type, $name, $ext);
* Load file of mime.types
* @param string $mimeTypesFile The mime types file
static protected function loadMimeTypes($mimeTypesFile = '')
if (!elFinderVolumeDriver::$mimetypesLoaded) {
elFinderVolumeDriver::$mimetypesLoaded = true;
if (!empty($mimeTypesFile) && file_exists($mimeTypesFile)) {
} elseif (elFinder::$defaultMimefile && file_exists(elFinder::$defaultMimefile)) {
$file = elFinder::$defaultMimefile;
} elseif (file_exists(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mime.types')) {
$file = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mime.types';
} elseif (file_exists(dirname(dirname(__FILE__)) . DIRECTORY_SEPARATOR . 'mime.types')) {
$file = dirname(dirname(__FILE__)) . DIRECTORY_SEPARATOR . 'mime.types';
if ($file && file_exists($file)) {
foreach ($mimecf as $line_num => $line) {
if (!preg_match('/^\s*#/', $line)) {
$mime = preg_split('/\s+/', $line, -1, PREG_SPLIT_NO_EMPTY);
for ($i = 1, $size = count($mime); $i < $size; $i++) {
if (!isset(self::$mimetypes[$mime[$i]])) {
self::$mimetypes[$mime[$i]] = $mime[0];
* Detect file mimetype using "internal" method or Loading mime.types with $path = ''
* @param string $path file path
* @author Dmitry (dio) Levashov
static protected function mimetypeInternalDetect($path = '')
// load default MIME table file "mime.types"
if (!elFinderVolumeDriver::$mimetypesLoaded) {
elFinderVolumeDriver::loadMimeTypes();
$pinfo = pathinfo($path);
$ext = isset($pinfo['extension']) ? strtolower($pinfo['extension']) : '';
$res = ($ext && isset(elFinderVolumeDriver::$mimetypes[$ext])) ? elFinderVolumeDriver::$mimetypes[$ext] : 'unknown';
// Recursive check if MIME type is unknown with multiple extensions
if ($res === 'unknown' && strpos($pinfo['filename'], '.')) {
return elFinderVolumeDriver::mimetypeInternalDetect($pinfo['filename']);
* Return file/total directory size infomation
* @param string $path file path
* @throws elFinderAbortException
* @author Dmitry (dio) Levashov
protected function countSize($path)
elFinder::checkAborted();
$result = array('size' => 0, 'files' => 0, 'dirs' => 0);
$stat = $this->stat($path);
if (empty($stat) || !$stat['read'] || !empty($stat['hidden'])) {
$result['size'] = 'unknown';
if ($stat['mime'] !== 'directory') {
$result['size'] = intval($stat['size']);
$subdirs = $this->options['checkSubfolders'];
$this->options['checkSubfolders'] = true;
foreach ($this->getScandir($path) as $stat) {
if ($isDir = ($stat['mime'] === 'directory' && $stat['read'])) {
? $this->countSize($this->decode($stat['hash']))
: (isset($stat['size']) ? array('size' => intval($stat['size'])) : array());
if (!empty($res['size']) && is_numeric($res['size'])) {
$result['size'] += $res['size'];
if (!empty($res['files']) && is_numeric($res['files'])) {
$result['files'] += $res['files'];
if (!empty($res['dirs']) && is_numeric($res['dirs'])) {
$result['dirs'] += $res['dirs'];
$this->options['checkSubfolders'] = $subdirs;