: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
* @author Dmitry (dio) Levashov
protected function uncrypt($hash)
* Validate file name based on $this->options['acceptedName'] regexp or function
* @param string $name file name
* @author Dmitry (dio) Levashov
protected function nameAccepted($name, $isDir = false)
if (json_encode($name) === false) {
$nameValidator = $isDir ? $this->dirnameValidator : $this->nameValidator;
if (is_callable($nameValidator)) {
$res = call_user_func($nameValidator, $name);
if (preg_match($nameValidator, '') !== false) {
return preg_match($nameValidator, $name);
* Return session rootstat cache key
protected function getRootstatCachekey()
return md5($this->root . (isset($this->options['alias']) ? $this->options['alias'] : ''));
* Return new unique name based on file name and suffix
* @param string $suffix suffix append to name
* @internal param string $path file path
* @author Dmitry (dio) Levashov
public function uniqueName($dir, $name, $suffix = ' copy', $checkNum = true, $start = 1)
$splits = elFinder::splitFileExtention($name);
if ($checkNum && preg_match('/(' . preg_quote($suffix, '/') . ')(\d*)$/i', $name, $m)) {
$name = substr($name, 0, strlen($name) - strlen($m[2]));
if (isset($lasts[$name])) {
$i = max($i, $lasts[$name]);
$n = $name . ($i > 0 ? sprintf($this->options['uniqueNumFormat'], $i) : '') . $ext;
if (!$this->isNameExists($this->joinPathCE($dir, $n))) {
return $name . md5($dir) . $ext;
* Converts character encoding from UTF-8 to server's one
* @param mixed $var target string or array var
* @param bool $restoreLocale do retore global locale, default is false
* @param string $unknown replaces character for unknown
public function convEncIn($var = null, $restoreLocale = false, $unknown = '_')
return (!$this->encoding) ? $var : $this->convEnc($var, 'UTF-8', $this->encoding, $this->options['locale'], $restoreLocale, $unknown);
* Converts character encoding from server's one to UTF-8
* @param mixed $var target string or array var
* @param bool $restoreLocale do retore global locale, default is true
* @param string $unknown replaces character for unknown
public function convEncOut($var = null, $restoreLocale = true, $unknown = '_')
return (!$this->encoding) ? $var : $this->convEnc($var, $this->encoding, 'UTF-8', $this->options['locale'], $restoreLocale, $unknown);
* Converts character encoding (base function)
* @param mixed $var target string or array var
* @param string $from from character encoding
* @param string $to to character encoding
* @param string $locale local locale
* @param string $unknown replaces character for unknown
protected function convEnc($var, $from, $to, $locale, $restoreLocale, $unknown = '_')
if (strtoupper($from) !== strtoupper($to)) {
setlocale(LC_ALL, $locale);
foreach ($var as $_k => $_v) {
$_ret[$_k] = $this->convEnc($_v, $from, $to, '', false, $unknown = '_');
$errlev = error_reporting();
error_reporting($errlev ^ E_NOTICE);
if (false !== ($_var = iconv($from, $to . '//TRANSLIT', $_var))) {
$_var = str_replace('?', $unknown, $_var);
error_reporting($errlev);
setlocale(LC_ALL, elFinder::$locale);
* Normalize MIME-Type by options['mimeMap']
* @param string $type MIME-Type
* @param string $name Filename
* @param string $ext File extention without first dot (optional)
* @return string Normalized MIME-Type
public function mimeTypeNormalize($type, $name, $ext = '')
$ext = (false === $pos = strrpos($name, '.')) ? '' : substr($name, $pos + 1);
$_checkKey = strtolower($ext . ':' . $type);
$_keylen = strlen($_checkKey);
foreach ($this->options['mimeMap'] as $_key => $_type) {
if (substr($_key, 0, $_keylen) === $_checkKey) {
} else if (isset($this->options['mimeMap'][$_checkKey])) {
$type = $this->options['mimeMap'][$_checkKey];
$_checkKey = strtolower($ext . ':*');
if (isset($this->options['mimeMap'][$_checkKey])) {
$type = $this->options['mimeMap'][$_checkKey];
$_checkKey = strtolower('*:' . $type);
if (isset($this->options['mimeMap'][$_checkKey])) {
$type = $this->options['mimeMap'][$_checkKey];
/*********************** util mainly for inheritance class *********************/
* Get temporary filename. Tempfile will be removed when after script execution finishes or exit() is called.
* When needing the unique file to a path, give $path to parameter.
* @param string $path for get unique file to a path
protected function getTempFile($path = '')
$key = $this->id . '#' . $path;
if (isset($cache[$key])) {
if ($tmpdir = $this->getTempPath()) {
$name = tempnam($tmpdir, 'ELF');
// register auto delete on shutdown
$GLOBALS['elFinderTempFiles'][$name] = true;
* File path of local server side work file path
* @param string $path path need convert encoding to server encoding
protected function getWorkFile($path)
if ($wfp = $this->tmpfile()) {
if ($fp = $this->_fopen($path)) {
fwrite($wfp, fread($fp, 8192));
$info = stream_get_meta_data($wfp);
if ($info && !empty($info['uri'])) {
* Get image size array with `dimensions`
* @param string $path path need convert encoding to server encoding
* @param string $mime file mime type
* @throws ImagickException
* @throws elFinderAbortException
public function getImageSize($path, $mime = '')
if ($mime === '' || strtolower(substr($mime, 0, 5)) === 'image') {
if ($work = $this->getWorkFile($path)) {
if ($size = getimagesize($work)) {
$size['dimensions'] = $size[0] . 'x' . $size[1];
$srcfp = fopen($work, 'rb');
$cArgs = elFinder::$currentArgs;
if (!empty($cArgs['target']) && $subImgLink = $this->getSubstituteImgLink($cArgs['target'], $size, $srcfp)) {
$size['url'] = $subImgLink;
is_file($work) && unlink($work);
* @param string $localpath path need convert encoding to server encoding
* @throws elFinderAbortException
protected function delTree($localpath)
foreach ($this->_scandir($localpath) as $p) {
elFinder::checkAborted();
$stat = $this->stat($this->convEncOut($p));
($stat['mime'] === 'directory') ? $this->delTree($p) : $this->_unlink($p);
$res = $this->_rmdir($localpath);
$res && $this->clearstatcache();
* Copy items to a new temporary directory on the local server
* @param array $hashes target hashes
* @param string $dir destination directory (for recurcive)
* @param string $canLink it can use link() (for recurcive)
* @return string|false saved path name
* @throws elFinderAbortException
protected function getItemsInHand($hashes, $dir = null, $canLink = null)
$banChrs = DIRECTORY_SEPARATOR !== '/'? array('\\', '/', ':', '*', '?', '"', '<', '>', '|') : array('\\', '/');
if (!$tmpDir = $this->getTempPath()) {
$dir = tempnam($tmpDir, 'elf');
if (!unlink($dir) || !mkdir($dir, 0700, true)) {
register_shutdown_function(array($this, 'rmdirRecursive'), $dir);
$canLink = ($this instanceof elFinderVolumeLocalFileSystem);
elFinder::checkAborted();
foreach ($hashes as $hash) {
if (($file = $this->file($hash)) == false) {
// remove ctrl characters
$name = preg_replace('/[[:cntrl:]]+/', '', $name);
// replace ban characters
$name = str_replace($banChrs, '_', $name);
// for call from search results
if (isset($files[$name])) {
$name = preg_replace('/^(.*?)(\..*)?$/', '$1_' . $files[$name]++ . '$2', $name);
$target = $dir . DIRECTORY_SEPARATOR . $name;
if ($file['mime'] === 'directory') {
$_files = $this->scandir($hash);
foreach ($_files as $_file) {
$chashes[] = $_file['hash'];
if (($res = mkdir($target, 0700, true)) && $chashes) {
$res = $this->getItemsInHand($chashes, $target, $canLink);
!empty($file['ts']) && touch($target, $file['ts']);
$path = $this->decode($hash);
if (!$canLink || !($canLink = $this->localFileSystemSymlink($path, $target))) {
if (file_exists($target)) {
if ($fp = $this->fopenCE($path)) {
if ($tfp = fopen($target, 'wb')) {
$totalSize += stream_copy_to_stream($fp, $tfp);
!empty($file['ts']) && touch($target, $file['ts']);
$this->fcloseCE($fp, $path);
$totalSize += filesize($path);
if ($this->options['maxArcFilesSize'] > 0 && $this->options['maxArcFilesSize'] < $totalSize) {
$res = $this->setError(elFinder::ERROR_ARC_MAXSIZE);
return $res ? $dir : false;
/*********************** file stat *********************/
* @param string $path file path
* @param string $name attribute name (read|write|locked|hidden)
* @param bool $val attribute value returned by file system
* @param bool $isDir path is directory (true: directory, false: file)
* @author Dmitry (dio) Levashov
protected function attr($path, $name, $val = null, $isDir = null)
if (!isset($this->defaults[$name])) {
$relpath = $this->relpathCE($path);
if ($this->separator !== '/') {
$relpath = str_replace($this->separator, '/', $relpath);
$relpath = '/' . $relpath;
$perm = call_user_func($this->access, $name, $path, $this->options['accessControlData'], $this, $isDir, $relpath);
foreach ($this->attributes as $attrs) {
if (isset($attrs[$name]) && isset($attrs['pattern']) && preg_match($attrs['pattern'], $relpath)) {
return $perm === null ? (is_null($val) ? $this->defaults[$name] : $val) : !!$perm;
* Return true if file with given name can be created in given folder.
* @param string $dir parent dir path
* @param string $name new file name
* @author Dmitry (dio) Levashov
protected function allowCreate($dir, $name, $isDir = null)
return $this->attr($this->joinPathCE($dir, $name), 'write', true, $isDir);
* Return true if file MIME type can save with check uploadOrder config.
protected function allowPutMime($mime)
// logic based on http://httpd.apache.org/docs/2.2/mod/mod_authz_host.html#order
$allow = $this->mimeAccepted($mime, $this->uploadAllow, null);
$deny = $this->mimeAccepted($mime, $this->uploadDeny, null);
if (strtolower($this->uploadOrder[0]) == 'allow') { // array('allow', 'deny'), default is to 'deny'
$res = false; // default is deny