diff --git a/src/Gaufrette/Adapter/Phpseclib3Sftp.php b/src/Gaufrette/Adapter/Phpseclib3Sftp.php new file mode 100644 index 00000000..e7f7b5d0 --- /dev/null +++ b/src/Gaufrette/Adapter/Phpseclib3Sftp.php @@ -0,0 +1,242 @@ +sftp = $sftp; + $this->directory = $directory; + $this->create = $create; + } + + /** + * {@inheritdoc} + */ + public function read($key) + { + return $this->sftp->get($this->computePath($key)); + } + + /** + * {@inheritdoc} + */ + public function rename($sourceKey, $targetKey) + { + $this->initialize(); + + $sourcePath = $this->computePath($sourceKey); + $targetPath = $this->computePath($targetKey); + + $this->ensureDirectoryExists(\Gaufrette\Util\Path::dirname($targetPath), true); + + return $this->sftp->rename($sourcePath, $targetPath); + } + + /** + * {@inheritdoc} + */ + public function write($key, $content) + { + $this->initialize(); + + $path = $this->computePath($key); + $this->ensureDirectoryExists(\Gaufrette\Util\Path::dirname($path), true); + if ($this->sftp->put($path, $content)) { + return $this->sftp->filesize($path); + } + + return false; + } + + /** + * {@inheritdoc} + */ + public function exists($key) + { + $this->initialize(); + + return false !== $this->sftp->stat($this->computePath($key)); + } + + /** + * {@inheritdoc} + */ + public function isDirectory($key) + { + $this->initialize(); + + $pwd = $this->sftp->pwd(); + if ($this->sftp->chdir($this->computePath($key))) { + $this->sftp->chdir($pwd); + + return true; + } + + return false; + } + + /** + * {@inheritdoc} + */ + public function keys() + { + $keys = $this->fetchKeys(); + + return $keys['keys']; + } + + /** + * {@inheritdoc} + */ + public function listKeys($prefix = '') + { + preg_match('/(.*?)[^\/]*$/', $prefix, $match); + $directory = rtrim($match[1], '/'); + + $keys = $this->fetchKeys($directory, false); + + if ($directory === $prefix) { + return $keys; + } + + $filteredKeys = []; + foreach (['keys', 'dirs'] as $hash) { + $filteredKeys[$hash] = []; + foreach ($keys[$hash] as $key) { + if (0 === strpos($key, $prefix)) { + $filteredKeys[$hash][] = $key; + } + } + } + + return $filteredKeys; + } + + /** + * {@inheritdoc} + */ + public function mtime($key) + { + $this->initialize(); + + $stat = $this->sftp->stat($this->computePath($key)); + + return $stat['mtime'] ?? false; + } + + /** + * {@inheritdoc} + */ + public function delete($key) + { + return $this->sftp->delete($this->computePath($key), false); + } + + /** + * {@inheritdoc} + */ + public function createFile($key, Filesystem $filesystem) + { + $file = new File($key, $filesystem); + + $stat = $this->sftp->stat($this->computePath($key)); + if (isset($stat['size'])) { + $file->setSize($stat['size']); + } + + return $file; + } + + /** + * Performs the adapter's initialization. + * + * It will ensure the root directory exists + */ + protected function initialize() + { + if ($this->initialized) { + return; + } + + $this->ensureDirectoryExists($this->directory, $this->create); + + $this->initialized = true; + } + + protected function ensureDirectoryExists($directory, $create) + { + $pwd = $this->sftp->pwd(); + if ($this->sftp->chdir($directory)) { + $this->sftp->chdir($pwd); + } elseif ($create) { + if (!$this->sftp->mkdir($directory, 0777, true)) { + throw new \RuntimeException(sprintf('The directory \'%s\' does not exist and could not be created (%s).', $this->directory, $this->sftp->getLastSFTPError())); + } + } else { + throw new \RuntimeException(sprintf('The directory \'%s\' does not exist.', $this->directory)); + } + } + + protected function computePath($key) + { + return $this->directory . '/' . ltrim($key, '/'); + } + + protected function fetchKeys($directory = '', $onlyKeys = true) + { + $keys = ['keys' => [], 'dirs' => []]; + $computedPath = $this->computePath($directory); + + if (!$this->sftp->file_exists($computedPath)) { + return $keys; + } + + $list = $this->sftp->rawlist($computedPath); + foreach ((array) $list as $filename => $stat) { + if ('.' === $filename || '..' === $filename) { + continue; + } + + $path = ltrim($directory . '/' . $filename, '/'); + if (isset($stat['type']) && $stat['type'] === NET_SFTP_TYPE_DIRECTORY) { + $keys['dirs'][] = $path; + } else { + $keys['keys'][] = $path; + } + } + + $dirs = $keys['dirs']; + + if ($onlyKeys && !empty($dirs)) { + $keys['keys'] = array_merge($keys['keys'], $dirs); + $keys['dirs'] = []; + } + + foreach ($dirs as $dir) { + $keys = array_merge_recursive($keys, $this->fetchKeys($dir, $onlyKeys)); + } + + return $keys; + } +}