: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
if ($this->options['path'] == 'root') {
$this->options['path'] = '/';
$this->root = $this->options['path'] = $this->_normpath($this->options['path']);
if (empty($this->options['alias'])) {
$this->options['root'] = ($this->options['root'] === '')? $this->_gd_getNameByPath('root') : $this->options['root'];
$this->options['alias'] = ($this->options['path'] === '/') ? $this->options['root'] : sprintf($this->options['gdAlias'], $this->_gd_getNameByPath($this->options['path']));
if (!empty($this->options['netkey'])) {
elFinder::$instance->updateNetVolumeOption($this->options['netkey'], 'alias', $this->options['alias']);
$this->options['root'] = ($this->options['root'] === '')? 'GoogleDrive' : $this->options['root'];
$this->options['alias'] = $this->options['root'];
$this->rootName = isset($this->options['alias'])? $this->options['alias'] : 'GoogleDrive';
if (!empty($this->options['tmpPath'])) {
if ((is_dir($this->options['tmpPath']) || mkdir($this->options['tmpPath'])) && is_writable($this->options['tmpPath'])) {
$this->tmp = $this->options['tmpPath'];
if (!$this->tmp && ($tmp = elFinder::getStaticVar('commonTempPath'))) {
// This driver dose not support `syncChkAsTs`
$this->options['syncChkAsTs'] = false;
// 'lsPlSleep' minmum 10 sec
$this->options['lsPlSleep'] = max(10, $this->options['lsPlSleep']);
if ($this->options['useGoogleTmb']) {
$this->options['tmbURL'] = 'https://';
$this->options['tmbPath'] = '';
// enable command archive
$this->options['useRemoteArchive'] = true;
* Configure after successfull mount.
* @author Dmitry (dio) Levashov
protected function configure()
// fallback of $this->tmp
if (!$this->tmp && $this->tmbPathWritable) {
$this->tmp = $this->tmbPath;
if ($this->needOnline && $this->isMyReload()) {
$this->_gd_getDirectoryData(false);
/*********************************************************************/
/*********************************************************************/
* Close opened connection.
* @author Dmitry (dio) Levashov
* @param string $path dir path
* @author Dmitry Levashov
protected function cacheDir($path)
$this->dirsCache[$path] = [];
list(, $pid) = $this->_gd_splitPath($path);
'fields' => self::FETCHFIELDS_LIST,
'q' => sprintf('trashed=false and "%s" in parents', $pid),
$res = $this->_gd_query($opts);
$mountPath = $this->_normpath($path . '/');
if ($stat = $this->_gd_parseRaw($raw)) {
$stat = $this->updateCache($mountPath . $raw->id, $stat);
if (empty($stat['hidden']) && $path !== $mountPath . $raw->id) {
if (!$hasDir && $stat['mime'] === 'directory') {
$this->dirsCache[$path][] = $mountPath . $raw->id;
if (isset($this->sessionCache['subdirs'])) {
$this->sessionCache['subdirs'][$path] = $hasDir;
return $this->dirsCache[$path];
* Recursive files search.
* @param string $path dir path
* @param string $q search string
* @throws elFinderAbortException
protected function doSearch($path, $q, $mimes)
if (!empty($this->doSearchCurrentQuery['matchMethod'])) {
// has custom match method use elFinderVolumeDriver::doSearch()
return parent::doSearch($path, $q, $mimes);
list(, $itemId) = $this->_gd_splitPath($path);
$path = $this->_normpath($path . '/');
if ($itemId !== 'root') {
$dirs = array_merge([$itemId], $this->_gd_getDirectories($itemId));
$query = '(\'' . implode('\' in parents or \'', $dirs) . '\' in parents)';
foreach (explode(' ', $q) as $_v) {
$tmp[] = 'fullText contains \'' . str_replace('\'', '\\\'', $_v) . '\'';
$query .= ($query ? ' and ' : '') . implode(' and ', $tmp);
foreach ($mimes as $_v) {
$tmp[] = 'mimeType contains \'' . str_replace('\'', '\\\'', $_v) . '\'';
$query .= ($query ? ' and ' : '') . '(' . implode(' or ', $tmp) . ')';
'q' => sprintf('trashed=false and (%s)', $query),
$res = $this->_gd_query($opts);
$timeout = $this->options['searchTimeout'] ? $this->searchStart + $this->options['searchTimeout'] : 0;
if ($timeout && $timeout < time()) {
$this->setError(elFinder::ERROR_SEARCH_TIMEOUT, $this->_path($path));
if ($stat = $this->_gd_parseRaw($raw)) {
if ($parents = $raw->getParents()) {
foreach ($parents as $parent) {
$paths = $this->_gd_getMountPaths($parent);
foreach ($paths as $path) {
$path = ($path === '') ? '/' : (rtrim($path, '/') . '/');
if (!isset($this->cache[$path . $raw->id])) {
$stat = $this->updateCache($path . $raw->id, $stat);
$stat = $this->cache[$path . $raw->id];
if (empty($stat['hidden'])) {
$stat['path'] = $this->_path($path) . $stat['name'];
* 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)
* @author Dmitry (dio) Levashov
protected function copy($src, $dst, $name)
$res = $this->_gd_getFile($src);
if ($res['mimeType'] == self::DIRMIME) {
$newDir = $this->_mkdir($dst, $name);
list(, $itemId) = $this->_gd_splitPath($newDir);
list(, $srcId) = $this->_gd_splitPath($src);
$path = $this->_joinPath($dst, $itemId);
'q' => sprintf('trashed=false and "%s" in parents', $srcId),
$res = $this->_gd_query($opts);
$raw['mimeType'] == self::DIRMIME ? $this->copy($src . '/' . $raw['id'], $path, $raw['name']) : $this->_copy($src . '/' . $raw['id'], $path, $raw['name']);
$ret = $this->_joinPath($dst, $itemId);
$this->added[] = $this->stat($ret);
$ret = $this->setError(elFinder::ERROR_COPY, $this->_path($src));
if ($itemId = $this->_copy($src, $dst, $name)) {
$ret = $this->_joinPath($dst, $itemId);
$this->added[] = $this->stat($ret);
$ret = $this->setError(elFinder::ERROR_COPY, $this->_path($src));
* 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, $recursive = false)
$stat = $this->stat($path);
$stat['realpath'] = $path;
return $this->setError(elFinder::ERROR_RM, $this->_path($path), elFinder::ERROR_FILE_NOT_FOUND);
if (!$force && !empty($stat['locked'])) {
return $this->setError(elFinder::ERROR_LOCKED, $this->_path($path));
if ($stat['mime'] == 'directory') {
if (!$recursive && !$this->_rmdir($path)) {
return $this->setError(elFinder::ERROR_RM, $this->_path($path));
if (!$recursive && !$this->_unlink($path)) {
return $this->setError(elFinder::ERROR_RM, $this->_path($path));
$this->removed[] = $stat;
* Create thumnbnail and return it's URL on success.
* @param string $path file path
* @throws ImagickException
* @throws elFinderAbortException
* @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;
// copy image into tmbPath so some drivers does not store files on local fs
if (!$data = $this->_gd_getThumbnail($path)) {
if (!file_put_contents($tmb, $data)) {
$tmbSize = $this->tmbSize;
if (($s = getimagesize($tmb)) == false) {
/* 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 (($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($tmb, $tmbSize, $tmbSize, $x, $y, 'png');
$result = $this->imgResize($tmb, $tmbSize, $tmbSize, true, true, 'png');
$result = $this->imgSquareFit($tmb, $tmbSize, $tmbSize, 'center', 'middle', $this->options['tmbBgColor'], 'png');
* Return thumbnail file name for required file.
* @param array $stat file stat
* @author Dmitry (dio) Levashov
protected function tmbname($stat)
return $this->netMountKey . $stat['iid'] . $stat['ts'] . '.png';
* Return content URL (for netmout volume driver)
* If file.url == 1 requests from JavaScript client with XHR.
* @param string $hash file hash
* @param array $options options array
public function getContentUrl($hash, $options = [])
if (!empty($options['onetime']) && $this->options['onetimeUrl']) {
return parent::getContentUrl($hash, $options);
if (!empty($options['temporary'])) {
// try make temporary file
$url = parent::getContentUrl($hash, $options);
if (($file = $this->file($hash)) == false || !$file['url'] || $file['url'] == 1) {
$path = $this->decode($hash);
if ($this->_gd_publish($path)) {
if ($raw = $this->_gd_getFile($path)) {
return $this->_gd_getLink($raw);
* Return debug info for client.
if (!empty($this->options['netkey']) && empty($this->options['refresh_token']) && $this->options['access_token'] && isset($this->options['access_token']['refresh_token'])) {
$res['refresh_token'] = $this->options['access_token']['refresh_token'];
/*********************** paths/urls *************************/
* Return parent directory path.
* @param string $path file path
* @author Dmitry (dio) Levashov
protected function _dirname($path)
list(, , $parent) = $this->_gd_splitPath($path);
return $this->_normpath($parent);
* @param string $path file path
* @author Dmitry (dio) Levashov
protected function _basename($path)
list(, $basename) = $this->_gd_splitPath($path);
* Join dir name and file name and retur full path.
* @author Dmitry (dio) Levashov
protected function _joinPath($dir, $name)
return $this->_normpath($dir . '/' . str_replace('/', '\\/', $name));
* Return normalized path, this works the same as os.path.normpath() in Python.
* @param string $path path
protected function _normpath($path)
if (DIRECTORY_SEPARATOR !== '/') {
$path = str_replace(DIRECTORY_SEPARATOR, '/', $path);
$path = '/' . ltrim($path, '/');
* Return file path related to root dir.
* @param string $path file path
* @author Dmitry (dio) Levashov
protected function _relpath($path)