: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
* Simple elFinder driver for GoogleDrive
* google-api-php-client-2.x or above.
* @author Dmitry (dio) Levashov
* @author Cem (discofever)
class elFinderVolumeGoogleDrive extends elFinderVolumeDriver
* Must be started from letter and contains [a-z0-9]
* Used as part of volume id.
protected $driverId = 'gd';
* Google API client object.
protected $client = null;
* GoogleDrive service object.
protected $service = null;
* Cache of parents of each directories.
* Cache of chiled directories of each directories.
protected $directories = null;
* Cache of itemID => name of each items.
* MIME tyoe of directory.
const DIRMIME = 'application/vnd.google-apps.folder';
const FETCHFIELDS_LIST = 'files(id,name,mimeType,modifiedTime,parents,permissions,size,imageMediaMetadata(height,width),thumbnailLink,webContentLink,webViewLink),nextPageToken';
const FETCHFIELDS_GET = 'id,name,mimeType,modifiedTime,parents,permissions,size,imageMediaMetadata(height,width),thumbnailLink,webContentLink,webViewLink';
* Directory for tmp files
* If not set driver will try to use tmbDir as tmpDir.
public $netMountKey = '';
* Extend options with required fields.
* @author Dmitry (dio) Levashov
* @author Cem (DiscoFever)
public function __construct()
'serviceAccountConfigFile' => '',
'gdAlias' => '%s@GDrive',
'rootCssClass' => 'elfinder-navbar-root-googledrive',
'application/vnd.google-apps.document' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'application/vnd.google-apps.spreadsheet' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'application/vnd.google-apps.drawing' => 'application/pdf',
'application/vnd.google-apps.presentation' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
'application/vnd.google-apps.script' => 'application/vnd.google-apps.script+json',
'default' => 'application/pdf',
$this->options = array_merge($this->options, $opts);
$this->options['mimeDetect'] = 'internal';
/*********************************************************************/
/*********************************************************************/
* Get Parent ID, Item ID, Parent Path as an array from path.
protected function _gd_splitPath($path)
$path = trim($path, '/');
$path = str_replace('\\/', chr(0), $path);
$paths = explode('/', $path);
$id = str_replace(chr(0), '/', $id);
$parent = '/' . implode('/', $paths);
$pid = array_pop($paths);
$rootid = ($this->root === '/') ? 'root' : trim($this->root, '/');
return array($pid, $id, $parent);
* Drive query and fetchAll.
private function _gd_query($opts)
'fields' => self::FETCHFIELDS_LIST,
$parameters = array_merge($parameters, $opts);
$parameters['pageToken'] = $pageToken;
$files = $this->service->files->listFiles($parameters);
$result = array_merge($result, $files->getFiles());
$pageToken = $files->getNextPageToken();
* Get dat(googledrive metadata) from GoogleDrive.
* @return array googledrive metadata
private function _gd_getFile($path, $fields = '')
list(, $itemId) = $this->_gd_splitPath($path);
$fields = self::FETCHFIELDS_GET;
$file = $this->service->files->get($itemId, ['fields' => $fields]);
if ($file instanceof Google_Service_Drive_DriveFile) {
* Parse line from googledrive metadata output and return file stat (array).
* @param array $raw line from ftp_rawlist() output
* @author Dmitry Levashov
protected function _gd_parseRaw($raw)
$stat['iid'] = isset($raw['id']) ? $raw['id'] : 'root';
$stat['name'] = isset($raw['name']) ? $raw['name'] : '';
if (isset($raw['modifiedTime'])) {
$stat['ts'] = strtotime($raw['modifiedTime']);
if ($raw['mimeType'] === self::DIRMIME) {
$stat['mime'] = 'directory';
$stat['mime'] = $raw['mimeType'] == 'image/bmp' ? 'image/x-ms-bmp' : $raw['mimeType'];
$stat['size'] = (int)$raw['size'];
if ($size = $raw->getImageMediaMetadata()) {
$stat['width'] = $size['width'];
$stat['height'] = $size['height'];
$published = $this->_gd_isPublished($raw);
if ($this->options['useGoogleTmb']) {
if (isset($raw['thumbnailLink'])) {
$stat['tmb'] = 'drive.google.com/thumbnail?authuser=0&sz=s' . $this->options['tmbSize'] . '&id=' . $raw['id'];
$stat['tmb'] = substr($raw['thumbnailLink'], 8); // remove "https://"
$stat['url'] = $this->_gd_getLink($raw);
} elseif (!$this->disabledGetUrl) {
* Get dat(googledrive metadata) from GoogleDrive.
* @return array googledrive metadata
private function _gd_getNameByPath($path)
list(, $itemId) = $this->_gd_splitPath($path);
$this->_gd_getDirectoryData();
return isset($this->names[$itemId]) ? $this->names[$itemId] : '';
* Make cache of $parents, $names and $directories.
protected function _gd_getDirectoryData($usecache = true)
$cache = $this->session->get($this->id . $this->netMountKey, []);
$this->parents = $cache['parents'];
$this->names = $cache['names'];
$this->directories = $cache['directories'];
if ($this->root === '/') {
if ($res = $this->_gd_getFile('/', 'id')) {
'fields' => 'files(id, name, parents)',
'q' => sprintf('trashed=false and mimeType="%s"', self::DIRMIME),
$res = $this->_gd_query($opts);
if ($parents = $raw->getParents()) {
$this->parents[$id] = $parents;
$this->names[$id] = $raw->getName();
foreach ($parents as $p) {
if ($root && isset($data[$root])) {
$data['root'] = $data[$root];
$this->directories = $data;
$this->session->set($this->id . $this->netMountKey, [
'parents' => $this->parents,
'directories' => $this->directories,
* Get descendants directories.
protected function _gd_getDirectories($itemId)
if ($this->directories === null) {
$this->_gd_getDirectoryData();
$data = $this->directories;
if (isset($data[$itemId])) {
foreach ($data[$itemId] as $cid) {
$ret = array_merge($ret, $this->_gd_getDirectories($cid));
* Get ID based path from item ID.
protected function _gd_getMountPaths($id)
if ($this->directories === null) {
$this->_gd_getDirectoryData();
list($pid) = explode('/', $id, 2);
if ('/' . $pid === $this->root) {
} elseif (!isset($this->parents[$pid])) {
$path = ltrim(substr($path, strlen($pid)), '/');
if ($this->root === '/' || strpos('/' . $path, $this->root) === 0) {
$res = [(strpos($path, '/') === false) ? '/' : ('/' . $path)];
foreach ($this->parents[$pid] as $p) {
$res = array_merge($res, $this->_gd_getMountPaths($_p));
protected function _gd_isPublished($file)
$pType = $this->options['publishPermission']['type'];
$pRole = $this->options['publishPermission']['role'];
if ($permissions = $file->getPermissions()) {
foreach ($permissions as $permission) {
if ($permission->type === $pType && $permission->role === $pRole) {
protected function _gd_getLink($file)
if (strpos($file->mimeType, 'application/vnd.google-apps.') !== 0) {
if ($url = $file->getWebContentLink()) {
return str_replace('export=download', 'export=media', $url);
if ($url = $file->getWebViewLink()) {
* @param Google_Service_Drive_DriveFile $file
protected function _gd_getDownloadUrl($file)
if (strpos($file->mimeType, 'application/vnd.google-apps.') !== 0) {
return 'https://www.googleapis.com/drive/v3/files/' . $file->getId() . '?alt=media';
$mimeMap = $this->options['appsExportMap'];
if (isset($mimeMap[$file->getMimeType()])) {
$mime = $mimeMap[$file->getMimeType()];
$mime = $mimeMap['default'];
$mime = rawurlencode($mime);
return 'https://www.googleapis.com/drive/v3/files/' . $file->getId() . '/export?mimeType=' . $mime;