: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
$class = 'elFinderPlugin' . $name;
if (!class_exists($class)) {
$p_file = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'plugins' . DIRECTORY_SEPARATOR . $name . DIRECTORY_SEPARATOR . 'plugin.php';
if (class_exists($class, false)) {
$this->plugins[$key] = new $class($opts);
$this->plugins[$key] = false;
return $this->plugins[$key];
/***************************************************************************/
/***************************************************************************/
* Normalize error messages
* @author Dmitry (dio) Levashov
foreach (func_get_args() as $msg) {
$errors = array_merge($errors, $msg);
return count($errors) ? $errors : array(self::ERROR_UNKNOWN);
* @throws elFinderAbortException
protected function netmount($args)
$protocol = $args['protocol'];
if ($protocol === 'netunmount') {
if (!empty($args['user']) && $volume = $this->volume($args['user'])) {
if ($this->removeNetVolume($args['host'], $volume)) {
return array('removed' => array(array('hash' => $volume->root())));
return array('sync' => true, 'error' => $this->error(self::ERROR_NETUNMOUNT));
$driver = isset(self::$netDrivers[$protocol]) ? self::$netDrivers[$protocol] : '';
$class = 'elFinderVolume' . $driver;
if (!class_exists($class)) {
return array('error' => $this->error(self::ERROR_NETMOUNT, $args['host'], self::ERROR_NETMOUNT_NO_DRIVER));
foreach ($args as $k => $v) {
if ($k != 'options' && $k != 'protocol' && $v) {
if (is_array($args['options'])) {
foreach ($args['options'] as $key => $value) {
/* @var elFinderVolumeDriver $volume */
$volume->setSession($this->session);
$volume->setNeedOnline(true);
if (is_callable(array($volume, 'netmountPrepare'))) {
$options = $volume->netmountPrepare($options);
if (isset($options['exit'])) {
if ($options['exit'] === 'callback') {
$this->callback($options['out']);
if (!empty($options['toast'])) {
$toast = $options['toast'];
unset($options['toast']);
$netVolumes = $this->getNetVolumes();
if (!isset($options['id'])) {
if (!$options['id'] = $this->getNetVolumeUniqueId($netVolumes)) {
return array('error' => $this->error(self::ERROR_NETMOUNT, $args['host'], 'Could\'t given volume id.'));
// load additional volume root options
if (!empty($this->optionsNetVolumes['*'])) {
$options = array_merge($this->optionsNetVolumes['*'], $options);
if (!empty($this->optionsNetVolumes[$protocol])) {
$options = array_merge($this->optionsNetVolumes[$protocol], $options);
if (!$key = $volume->netMountKey) {
$key = md5($protocol . '-' . serialize($options));
$options['netkey'] = $key;
if (!isset($netVolumes[$key]) && $volume->mount($options)) {
// call post-process function of netmount
if (is_callable(array($volume, 'postNetmount'))) {
$volume->postNetmount($options);
$options['driver'] = $driver;
$netVolumes[$key] = $options;
$this->saveNetVolumes($netVolumes);
$rootstat = $volume->file($volume->root());
$res = array('added' => array($rootstat));
$this->removeNetVolume(null, $volume);
return array('error' => $this->error(self::ERROR_NETMOUNT, $args['host'], implode(' ', $volume->error())));
* Return array with following elements
* - cwd - opened dir info
* - files - opened dir content [and dirs tree if $args[tree]]
* - api - api version (if $args[init])
* - uplMaxSize - if $args[init]
* @param array command arguments
* @throws elFinderAbortException
* @author Dmitry (dio) Levashov
protected function open($args)
$target = $args['target'];
$init = !empty($args['init']);
$tree = !empty($args['tree']);
$volume = $this->volume($target);
$cwd = $volume ? $volume->dir($target) : false;
$hash = $init ? 'default folder' : '#' . $target;
// on init request we can get invalid dir hash -
// dir which can not be opened now, but remembered by client,
if ((!$cwd || !$cwd['read']) && $init) {
$volume = $this->default;
$target = $volume->defaultPath();
$cwd = $volume->dir($target);
return array('error' => $this->error(self::ERROR_OPEN, $hash, self::ERROR_DIR_NOT_FOUND));
return array('error' => $this->error(self::ERROR_OPEN, $hash, self::ERROR_PERM_DENIED));
// get current working directory files list
if (($ls = $volume->scandir($cwd['hash'])) === false) {
return array('error' => $this->error(self::ERROR_OPEN, $cwd['name'], $volume->error()));
if (isset($cwd['dirs']) && $cwd['dirs'] != 1) {
$cwd = $volume->dir($target);
foreach ($this->volumes as $id => $v) {
$files[] = $v->file($v->root());
$sleep = max(1, (int)$volume->getOption('lsPlSleep'));
$standby = (int)$volume->getOption('plStandby');
if ($standby > 0 && $sleep > $standby) {
$limit = max(0, floor($standby / $sleep)) + 1;
elFinder::extendTimeLimit(30 + $sleep);
$_mtime = max($_mtime, $_f['ts']);
$compare = strval(count($ls)) . ':' . strval($_mtime);
if ($compare !== $args['compare']) {
$volume->clearstatcache();
if (($ls = $volume->scandir($cwd['hash'])) === false) {
return array('error' => $this->error(self::ERROR_OPEN, $cwd['name'], $volume->error()));
$files = array_merge($files, $ls);
'options' => $volume->options($cwd['hash']),
$result['cwd']['compare'] = $compare;
if (!empty($args['init'])) {
$result['api'] = sprintf('%.1F%03d', self::$ApiVersion, self::$ApiRevision);
$result['uplMaxSize'] = ini_get('upload_max_filesize');
$result['uplMaxFile'] = ini_get('max_file_uploads');
$result['netDrivers'] = array_keys(self::$netDrivers);
$result['maxTargets'] = $this->maxTargets;
$result['cwd']['root'] = $volume->root();
if (elfinder::$textMimes) {
$result['textMimes'] = elfinder::$textMimes;
* Return dir files names list
* @param array command arguments
* @author Dmitry (dio) Levashov
protected function ls($args)
$target = $args['target'];
$intersect = isset($args['intersect']) ? $args['intersect'] : array();
if (($volume = $this->volume($target)) == false
|| ($list = $volume->ls($target, $intersect)) === false) {
return array('error' => $this->error(self::ERROR_OPEN, '#' . $target));
return array('list' => $list);
* Return subdirs for required directory
* @param array command arguments
* @author Dmitry (dio) Levashov
protected function tree($args)
$target = $args['target'];
if (($volume = $this->volume($target)) == false
|| ($tree = $volume->tree($target)) == false) {
return array('error' => $this->error(self::ERROR_OPEN, '#' . $target));
return array('tree' => $tree);
* Return parents dir for required directory
* @param array command arguments
* @throws elFinderAbortException
* @author Dmitry (dio) Levashov
protected function parents($args)
$target = $args['target'];
if (($volume = $this->volume($target)) == false
|| ($tree = $volume->parents($target, false, $until)) == false) {
return array('error' => $this->error(self::ERROR_OPEN, '#' . $target));
return array('tree' => $tree);
* Return new created thumbnails list
* @param array command arguments
* @throws ImagickException
* @throws elFinderAbortException
* @author Dmitry (dio) Levashov
protected function tmb($args)
$result = array('images' => array());
$targets = $args['targets'];
foreach ($targets as $target) {
elFinder::checkAborted();
if (($volume = $this->volume($target)) != false
&& (($tmb = $volume->tmb($target)) != false)) {
$result['images'][$target] = $tmb;
* Download files/folders as an archive file
* 1st: Return srrsy contains download archive file info
* 2nd: Return array contains opened file pointer, root itself and required headers
* @param array command arguments
protected function zipdl($args)
$targets = $args['targets'];
$download = !empty($args['download']);
$h404 = 'HTTP/1.x 404 Not Found';
$CriOS = isset($_SERVER['HTTP_USER_AGENT'])? (strpos($_SERVER['HTTP_USER_AGENT'], 'CriOS') !== false) : false;
//1st: Return array contains download archive file info
$error = array(self::ERROR_ARCHIVE);
if (($volume = $this->volume($targets[0])) !== false) {
if ($dlres = $volume->zipdl($targets)) {
register_shutdown_function(array('elFinder', 'rmFileInDisconnected'), $path);
if (count($targets) === 1) {
$name = basename($volume->path($targets[0]));
$name = $dlres['prefix'] . '_Files';
$name .= '.' . $dlres['ext'];
set_transient("zipdl$uniqid", basename($path),MINUTE_IN_SECONDS);
$this->session->set('zipdl' . $uniqid, basename($path));
'file' => $CriOS? basename($path) : $uniqid,
$error = array_merge($error, $volume->error());
return array('error' => $error);
// 2nd: Return array contains opened file session key, root itself and required headers
// It has access twice on downloading
$accept = isset($_SERVER['HTTP_ACCEPT'])? $_SERVER['HTTP_ACCEPT'] : '';
if ($accept && $accept !== '*' && $accept !== '*/*') {
if (count($targets) !== 4 ||
($volume = $this->volume($targets[0])) == false ||
!($file = $CriOS ? $targets[1] : ( ZEND_THREAD_SAFE ? get_transient( "zipdl$targets[1]" ) : $this->session->get( 'zipdl' . $targets[1] ) ) )) {
return array('error' => 'File not found', 'header' => $h404, 'raw' => true);
$path = $volume->getTempPath() . DIRECTORY_SEPARATOR . basename($file);
// remove session data of "zipdl..."
delete_transient("zipdl$targets[1]");
$this->session->remove('zipdl' . $targets[1]);
// register auto delete on shutdown
$GLOBALS['elFinderTempFiles'][$path] = true;
if ($volume->commandDisabled('zipdl')) {
return array('error' => 'File not found', 'header' => $h404, 'raw' => true);
if (!is_readable($path) || !is_writable($path)) {
return array('error' => 'File not found', 'header' => $h404, 'raw' => true);
$filenameEncoded = rawurlencode($name);
if (strpos($filenameEncoded, '%') === false) { // ASCII only
$filename = 'filename="' . $name . '"';
$ua = $_SERVER['HTTP_USER_AGENT'];
if (preg_match('/MSIE [4-8]/', $ua)) { // IE < 9 do not support RFC 6266 (RFC 2231/RFC 5987)
$filename = 'filename="' . $filenameEncoded . '"';
} elseif (strpos($ua, 'Chrome') === false && strpos($ua, 'Safari') !== false && preg_match('#Version/[3-5]#', $ua)) { // Safari < 6
$filename = 'filename="' . str_replace('"', '', $name) . '"';
} else { // RFC 6266 (RFC 2231/RFC 5987)
$filename = 'filename*=UTF-8\'\'' . $filenameEncoded;
$fp = fopen($path, 'rb');
'Content-Type: ' . $mime,
'Content-Disposition: attachment; ' . $filename,
'Content-Transfer-Encoding: binary',
'Content-Length: ' . $file['size'],
// add cache control headers
if ($cacheHeaders = $volume->getOption('cacheHeaders')) {
$result['header'] = array_merge($result['header'], $cacheHeaders);
* Required to output file in browser when volume URL is not set
* Return array contains opened file pointer, root itself and required headers
* @param array command arguments
* @throws elFinderAbortException
* @author Dmitry (dio) Levashov
protected function file($args)