/** * Create new file and write into it from file pointer. * Return new file path or false on error. * * @param resource $fp file pointer * @param string $dir target dir path * @param string $name file name * @param array $stat file stat (required by some virtual fs) * * @return bool|string * * @author Dmitry (dio) Levashov **/ protected function _save($fp, $path, $name, $stat) { if ($name !== '') { $path .= '/' . $name; } list($parentId, $itemId, $parent) = $this->_gd_splitPath($path); if ($name === '') { $stat['iid'] = $itemId; } if (!$stat || empty($stat['iid'])) { $opts = ['q' => sprintf('trashed=false and "%s" in parents and name="%s"', $parentId, $name), 'fields' => self::FETCHFIELDS_LIST]; $srcFile = $this->_gd_query($opts); $srcFile = empty($srcFile) ? null : $srcFile[0]; } else { $srcFile = $this->_gd_getFile($path); } try { $mode = 'update'; $mime = isset($stat['mime']) ? $stat['mime'] : ''; $file = new Google_Service_Drive_DriveFile(); if ($srcFile) { $mime = $srcFile->getMimeType(); } else { $mode = 'insert'; $file->setName($name); $file->setParents([$parentId]); } if (!$mime) { $mime = self::mimetypeInternalDetect($name); } if ($mime === 'unknown') { $mime = 'application/octet-stream'; } $file->setMimeType($mime); $size = 0; if (isset($stat['size'])) { $size = $stat['size']; } else { $fstat = fstat($fp); if (!empty($fstat['size'])) { $size = $fstat['size']; } } // set chunk size (max: 100MB) $chunkSizeBytes = 100 * 1024 * 1024; if ($size > 0) { $memory = elFinder::getIniBytes('memory_limit'); if ($memory) { $chunkSizeBytes = min([$chunkSizeBytes, intval($memory / 4 / 256) * 256]); } } if ($size > $chunkSizeBytes) { $client = $this->client; // Call the API with the media upload, defer so it doesn't immediately return. $client->setDefer(true); if ($mode === 'insert') { $request = $this->service->files->create($file, ['fields' => self::FETCHFIELDS_GET]); } else { $request = $this->service->files->update($srcFile->getId(), $file, ['fields' => self::FETCHFIELDS_GET]); } // Create a media file upload to represent our upload process. $media = new Google_Http_MediaFileUpload($client, $request, $mime, null, true, $chunkSizeBytes); $media->setFileSize($size); // Upload the various chunks. $status will be false until the process is // complete. $status = false; while (!$status && !feof($fp)) { elFinder::extendTimeLimit(); // read until you get $chunkSizeBytes from TESTFILE // fread will never return more than 8192 bytes if the stream is read buffered and it does not represent a plain file // An example of a read buffered file is when reading from a URL $chunk = $this->_gd_readFileChunk($fp, $chunkSizeBytes); $status = $media->nextChunk($chunk); } // The final value of $status will be the data from the API for the object // that has been uploaded. if ($status !== false) { $obj = $status; } $client->setDefer(false); } else { $params = ['data' => stream_get_contents($fp), 'uploadType' => 'media', 'fields' => self::FETCHFIELDS_GET]; if ($mode === 'insert') { $obj = $this->service->files->create($file, $params); } else { $obj = $this->service->files->update($srcFile->getId(), $file, $params); } } if ($obj instanceof Google_Service_Drive_DriveFile) { return $this->_joinPath($parent, $obj->getId()); } else { return false; } } catch (Exception $e) { return $this->setError('GoogleDrive error: ' . $e->getMessage()); } }
/** * Recursive files search * * @param string $path dir path * @param string $q search string * @param array $mimes * @return array * @author Dmitry (dio) Levashov * @author Naoki Sawada **/ protected function doSearch($path, $q, $mimes) { if ($this->encoding || !class_exists('FilesystemIterator', false)) { // non UTF-8 use elFinderVolumeDriver::doSearch() return parent::doSearch($path, $q, $mimes); } $result = array(); $timeout = $this->options['searchTimeout'] ? $this->searchStart + $this->options['searchTimeout'] : 0; if ($timeout && $timeout < time()) { $this->setError(elFinder::ERROR_SEARCH_TIMEOUT, $this->path($this->encode($path))); return $result; } elFinder::extendTimeLimit($this->options['searchTimeout'] + 30); $match = array(); try { $iterator = new RecursiveIteratorIterator(new RecursiveCallbackFilterIterator(new RecursiveDirectoryIterator($path, FilesystemIterator::KEY_AS_PATHNAME | FilesystemIterator::SKIP_DOTS | (defined('RecursiveDirectoryIterator::FOLLOW_SYMLINKS') && $this->options['followSymLinks'] ? RecursiveDirectoryIterator::FOLLOW_SYMLINKS : 0)), array($this, 'localFileSystemSearchIteratorFilter')), RecursiveIteratorIterator::SELF_FIRST, RecursiveIteratorIterator::CATCH_GET_CHILD); foreach ($iterator as $key => $node) { if ($timeout && ($this->error || $timeout < time())) { !$this->error && $this->setError(elFinder::ERROR_SEARCH_TIMEOUT, $this->path($this->encode($node->getPath))); break; } if ($node->isDir()) { if ($this->stripos($node->getFilename(), $q) !== false) { $match[] = $key; } } else { $match[] = $key; } } } catch (Exception $e) { } if ($match) { foreach ($match as $p) { if ($timeout && ($this->error || $timeout < time())) { !$this->error && $this->setError(elFinder::ERROR_SEARCH_TIMEOUT, $this->path($this->encode(dirname($p)))); break; } $stat = $this->stat($p); if (!$stat) { // invalid links continue; } if (!empty($stat['hidden']) || !$this->mimeAccepted($stat['mime'], $mimes)) { continue; } $name = $stat['name']; if (!$mimes || $stat['mime'] !== 'directory') { $stat['path'] = $this->path($stat['hash']); if ($this->URL && !isset($stat['url'])) { $_path = str_replace(DIRECTORY_SEPARATOR, '/', substr($p, strlen($this->root) + 1)); $stat['url'] = $this->URL . str_replace('%2F', '/', rawurlencode($_path)); } $result[] = $stat; } } } return $result; }
/** * Return file info (used by client "places" ui) * * @param array $args command arguments * @return array * @author Dmitry Levashov **/ protected function info($args) { $files = array(); $sleep = 0; $compare = null; // long polling mode if ($args['compare'] && count($args['targets']) === 1) { $compare = intval($args['compare']); $hash = $args['targets'][0]; if ($volume = $this->volume($hash)) { $standby = (int) $volume->getOption('plStandby'); $_compare = false; if (($syncCheckFunc = $volume->getOption('syncCheckFunc')) && is_callable($syncCheckFunc)) { $_compare = call_user_func_array($syncCheckFunc, array($volume->realpath($hash), $standby, $compare, $volume, $this)); } if ($_compare !== false) { $compare = $_compare; } else { $sleep = max(1, (int) $volume->getOption('tsPlSleep')); $limit = max(1, $standby / $sleep) + 1; do { elFinder::extendTimeLimit(30 + $sleep); $volume->clearstatcache(); if (($info = $volume->file($hash)) != false) { if ($info['ts'] != $compare) { $compare = $info['ts']; break; } } else { $compare = 0; break; } if (--$limit) { sleep($sleep); } } while ($limit); } } } else { foreach ($args['targets'] as $hash) { if (($volume = $this->volume($hash)) != false && ($info = $volume->file($hash)) != false) { $info['path'] = $volume->path($hash); $files[] = $info; } } } $result = array('files' => $files); if (!is_null($compare)) { $result['compare'] = strval($compare); } return $result; }
/** * Remove directory recursive on local file system * * @param string $dir Target dirctory path * @return boolean * @author Naoki Sawada */ public function rmdirRecursive($dir) { if (!is_link($dir) && is_dir($dir)) { chmod($dir, 0777); if ($handle = opendir($dir)) { while (false !== ($file = readdir($handle))) { if ($file === '.' || $file === '..') { continue; } elFinder::extendTimeLimit(30); $path = $dir . DIRECTORY_SEPARATOR . $file; if (!is_link($dir) && is_dir($path)) { $this->rmdirRecursive($path); } else { chmod($path, 0666); unlink($path); } } closedir($handle); } return rmdir($dir); } elseif (is_file($dir) || is_link($dir)) { chmod($dir, 0666); return unlink($dir); } return false; }