123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533 |
- <?php
- namespace League\Flysystem\Adapter;
- use DirectoryIterator;
- use FilesystemIterator;
- use finfo as Finfo;
- use League\Flysystem\Config;
- use League\Flysystem\Exception;
- use League\Flysystem\NotSupportedException;
- use League\Flysystem\UnreadableFileException;
- use League\Flysystem\Util;
- use LogicException;
- use RecursiveDirectoryIterator;
- use RecursiveIteratorIterator;
- use SplFileInfo;
- class Local extends AbstractAdapter
- {
- /**
- * @var int
- */
- const SKIP_LINKS = 0001;
- /**
- * @var int
- */
- const DISALLOW_LINKS = 0002;
- /**
- * @var array
- */
- protected static $permissions = [
- 'file' => [
- 'public' => 0644,
- 'private' => 0600,
- ],
- 'dir' => [
- 'public' => 0755,
- 'private' => 0700,
- ],
- ];
- /**
- * @var string
- */
- protected $pathSeparator = DIRECTORY_SEPARATOR;
- /**
- * @var array
- */
- protected $permissionMap;
- /**
- * @var int
- */
- protected $writeFlags;
- /**
- * @var int
- */
- private $linkHandling;
- /**
- * Constructor.
- *
- * @param string $root
- * @param int $writeFlags
- * @param int $linkHandling
- * @param array $permissions
- *
- * @throws LogicException
- */
- public function __construct($root, $writeFlags = LOCK_EX, $linkHandling = self::DISALLOW_LINKS, array $permissions = [])
- {
- $root = is_link($root) ? realpath($root) : $root;
- $this->permissionMap = array_replace_recursive(static::$permissions, $permissions);
- $this->ensureDirectory($root);
- if ( ! is_dir($root) || ! is_readable($root)) {
- throw new LogicException('The root path ' . $root . ' is not readable.');
- }
- $this->setPathPrefix($root);
- $this->writeFlags = $writeFlags;
- $this->linkHandling = $linkHandling;
- }
- /**
- * Ensure the root directory exists.
- *
- * @param string $root root directory path
- *
- * @return void
- *
- * @throws Exception in case the root directory can not be created
- */
- protected function ensureDirectory($root)
- {
- if ( ! is_dir($root)) {
- $umask = umask(0);
- if ( ! @mkdir($root, $this->permissionMap['dir']['public'], true)) {
- $mkdirError = error_get_last();
- }
- umask($umask);
- clearstatcache(false, $root);
- if ( ! is_dir($root)) {
- $errorMessage = isset($mkdirError['message']) ? $mkdirError['message'] : '';
- throw new Exception(sprintf('Impossible to create the root directory "%s". %s', $root, $errorMessage));
- }
- }
- }
- /**
- * @inheritdoc
- */
- public function has($path)
- {
- $location = $this->applyPathPrefix($path);
- return file_exists($location);
- }
- /**
- * @inheritdoc
- */
- public function write($path, $contents, Config $config)
- {
- $location = $this->applyPathPrefix($path);
- $this->ensureDirectory(dirname($location));
- if (($size = file_put_contents($location, $contents, $this->writeFlags)) === false) {
- return false;
- }
- $type = 'file';
- $result = compact('contents', 'type', 'size', 'path');
- if ($visibility = $config->get('visibility')) {
- $result['visibility'] = $visibility;
- $this->setVisibility($path, $visibility);
- }
- return $result;
- }
- /**
- * @inheritdoc
- */
- public function writeStream($path, $resource, Config $config)
- {
- $location = $this->applyPathPrefix($path);
- $this->ensureDirectory(dirname($location));
- $stream = fopen($location, 'w+b');
- if ( ! $stream || stream_copy_to_stream($resource, $stream) === false || ! fclose($stream)) {
- return false;
- }
- $type = 'file';
- $result = compact('type', 'path');
- if ($visibility = $config->get('visibility')) {
- $this->setVisibility($path, $visibility);
- $result['visibility'] = $visibility;
- }
- return $result;
- }
- /**
- * @inheritdoc
- */
- public function readStream($path)
- {
- $location = $this->applyPathPrefix($path);
- $stream = fopen($location, 'rb');
- return ['type' => 'file', 'path' => $path, 'stream' => $stream];
- }
- /**
- * @inheritdoc
- */
- public function updateStream($path, $resource, Config $config)
- {
- return $this->writeStream($path, $resource, $config);
- }
- /**
- * @inheritdoc
- */
- public function update($path, $contents, Config $config)
- {
- $location = $this->applyPathPrefix($path);
- $size = file_put_contents($location, $contents, $this->writeFlags);
- if ($size === false) {
- return false;
- }
- $type = 'file';
- $result = compact('type', 'path', 'size', 'contents');
- if ($visibility = $config->get('visibility')) {
- $this->setVisibility($path, $visibility);
- $result['visibility'] = $visibility;
- }
- return $result;
- }
- /**
- * @inheritdoc
- */
- public function read($path)
- {
- $location = $this->applyPathPrefix($path);
- $contents = @file_get_contents($location);
- if ($contents === false) {
- return false;
- }
- return ['type' => 'file', 'path' => $path, 'contents' => $contents];
- }
- /**
- * @inheritdoc
- */
- public function rename($path, $newpath)
- {
- $location = $this->applyPathPrefix($path);
- $destination = $this->applyPathPrefix($newpath);
- $parentDirectory = $this->applyPathPrefix(Util::dirname($newpath));
- $this->ensureDirectory($parentDirectory);
- return rename($location, $destination);
- }
- /**
- * @inheritdoc
- */
- public function copy($path, $newpath)
- {
- $location = $this->applyPathPrefix($path);
- $destination = $this->applyPathPrefix($newpath);
- $this->ensureDirectory(dirname($destination));
- return copy($location, $destination);
- }
- /**
- * @inheritdoc
- */
- public function delete($path)
- {
- $location = $this->applyPathPrefix($path);
- return @unlink($location);
- }
- /**
- * @inheritdoc
- */
- public function listContents($directory = '', $recursive = false)
- {
- $result = [];
- $location = $this->applyPathPrefix($directory);
- if ( ! is_dir($location)) {
- return [];
- }
- $iterator = $recursive ? $this->getRecursiveDirectoryIterator($location) : $this->getDirectoryIterator($location);
- foreach ($iterator as $file) {
- $path = $this->getFilePath($file);
- if (preg_match('#(^|/|\\\\)\.{1,2}$#', $path)) {
- continue;
- }
- $result[] = $this->normalizeFileInfo($file);
- }
- unset($iterator);
- return array_filter($result);
- }
- /**
- * @inheritdoc
- */
- public function getMetadata($path)
- {
- $location = $this->applyPathPrefix($path);
- clearstatcache(false, $location);
- $info = new SplFileInfo($location);
- return $this->normalizeFileInfo($info);
- }
- /**
- * @inheritdoc
- */
- public function getSize($path)
- {
- return $this->getMetadata($path);
- }
- /**
- * @inheritdoc
- */
- public function getMimetype($path)
- {
- $location = $this->applyPathPrefix($path);
- $finfo = new Finfo(FILEINFO_MIME_TYPE);
- $mimetype = $finfo->file($location);
- if (in_array($mimetype, ['application/octet-stream', 'inode/x-empty', 'application/x-empty'])) {
- $mimetype = Util\MimeType::detectByFilename($location);
- }
- return ['path' => $path, 'type' => 'file', 'mimetype' => $mimetype];
- }
- /**
- * @inheritdoc
- */
- public function getTimestamp($path)
- {
- return $this->getMetadata($path);
- }
- /**
- * @inheritdoc
- */
- public function getVisibility($path)
- {
- $location = $this->applyPathPrefix($path);
- clearstatcache(false, $location);
- $permissions = octdec(substr(sprintf('%o', fileperms($location)), -4));
- $type = is_dir($location) ? 'dir' : 'file';
- foreach ($this->permissionMap[$type] as $visibility => $visibilityPermissions) {
- if ($visibilityPermissions == $permissions) {
- return compact('path', 'visibility');
- }
- }
- $visibility = substr(sprintf('%o', fileperms($location)), -4);
- return compact('path', 'visibility');
- }
- /**
- * @inheritdoc
- */
- public function setVisibility($path, $visibility)
- {
- $location = $this->applyPathPrefix($path);
- $type = is_dir($location) ? 'dir' : 'file';
- $success = chmod($location, $this->permissionMap[$type][$visibility]);
- if ($success === false) {
- return false;
- }
- return compact('path', 'visibility');
- }
- /**
- * @inheritdoc
- */
- public function createDir($dirname, Config $config)
- {
- $location = $this->applyPathPrefix($dirname);
- $umask = umask(0);
- $visibility = $config->get('visibility', 'public');
- $return = ['path' => $dirname, 'type' => 'dir'];
- if ( ! is_dir($location)) {
- if (false === @mkdir($location, $this->permissionMap['dir'][$visibility], true)
- || false === is_dir($location)) {
- $return = false;
- }
- }
- umask($umask);
- return $return;
- }
- /**
- * @inheritdoc
- */
- public function deleteDir($dirname)
- {
- $location = $this->applyPathPrefix($dirname);
- if ( ! is_dir($location)) {
- return false;
- }
- $contents = $this->getRecursiveDirectoryIterator($location, RecursiveIteratorIterator::CHILD_FIRST);
- /** @var SplFileInfo $file */
- foreach ($contents as $file) {
- $this->guardAgainstUnreadableFileInfo($file);
- $this->deleteFileInfoObject($file);
- }
- unset($contents);
- return rmdir($location);
- }
- /**
- * @param SplFileInfo $file
- */
- protected function deleteFileInfoObject(SplFileInfo $file)
- {
- switch ($file->getType()) {
- case 'dir':
- rmdir($file->getRealPath());
- break;
- case 'link':
- unlink($file->getPathname());
- break;
- default:
- unlink($file->getRealPath());
- }
- }
- /**
- * Normalize the file info.
- *
- * @param SplFileInfo $file
- *
- * @return array|void
- *
- * @throws NotSupportedException
- */
- protected function normalizeFileInfo(SplFileInfo $file)
- {
- if ( ! $file->isLink()) {
- return $this->mapFileInfo($file);
- }
- if ($this->linkHandling & self::DISALLOW_LINKS) {
- throw NotSupportedException::forLink($file);
- }
- }
- /**
- * Get the normalized path from a SplFileInfo object.
- *
- * @param SplFileInfo $file
- *
- * @return string
- */
- protected function getFilePath(SplFileInfo $file)
- {
- $location = $file->getPathname();
- $path = $this->removePathPrefix($location);
- return trim(str_replace('\\', '/', $path), '/');
- }
- /**
- * @param string $path
- * @param int $mode
- *
- * @return RecursiveIteratorIterator
- */
- protected function getRecursiveDirectoryIterator($path, $mode = RecursiveIteratorIterator::SELF_FIRST)
- {
- return new RecursiveIteratorIterator(
- new RecursiveDirectoryIterator($path, FilesystemIterator::SKIP_DOTS),
- $mode
- );
- }
- /**
- * @param string $path
- *
- * @return DirectoryIterator
- */
- protected function getDirectoryIterator($path)
- {
- $iterator = new DirectoryIterator($path);
- return $iterator;
- }
- /**
- * @param SplFileInfo $file
- *
- * @return array
- */
- protected function mapFileInfo(SplFileInfo $file)
- {
- $normalized = [
- 'type' => $file->getType(),
- 'path' => $this->getFilePath($file),
- ];
- $normalized['timestamp'] = $file->getMTime();
- if ($normalized['type'] === 'file') {
- $normalized['size'] = $file->getSize();
- }
- return $normalized;
- }
- /**
- * @param SplFileInfo $file
- *
- * @throws UnreadableFileException
- */
- protected function guardAgainstUnreadableFileInfo(SplFileInfo $file)
- {
- if ( ! $file->isReadable()) {
- throw UnreadableFileException::forFileInfo($file);
- }
- }
- }
|