PK s~N Fd deprecations.mdnu W+A # Deprecations This document lists all the planned deprecations. ## Handlers will be removed in 2.0 The `Handler` type and associated calls will be removed in version 2.0. ### Upgrade path You should create your own implementation for handling OOP usage, but it's recommended to move away from using an OOP-style wrapper entirely. The reason for this is that it's too easy for implementation details (for your application this is Flysystem) to leak into the application. The most important part for Flysystem is that it improves portability and creates a solid boundary between your application core and the infrastructure you use. The OOP-style handling breaks this principle, therefore I want to stop promoting it. PK s~Nwx x src/RootViolationException.phpnu W+A '']; } /** * Normalize a dirname return value. * * @param string $dirname * * @return string normalized dirname */ public static function normalizeDirname($dirname) { return $dirname === '.' ? '' : $dirname; } /** * Get a normalized dirname from a path. * * @param string $path * * @return string dirname */ public static function dirname($path) { return static::normalizeDirname(dirname($path)); } /** * Map result arrays. * * @param array $object * @param array $map * * @return array mapped result */ public static function map(array $object, array $map) { $result = []; foreach ($map as $from => $to) { if ( ! isset($object[$from])) { continue; } $result[$to] = $object[$from]; } return $result; } /** * Normalize path. * * @param string $path * * @throws LogicException * * @return string */ public static function normalizePath($path) { return static::normalizeRelativePath($path); } /** * Normalize relative directories in a path. * * @param string $path * * @throws LogicException * * @return string */ public static function normalizeRelativePath($path) { $path = str_replace('\\', '/', $path); $path = static::removeFunkyWhiteSpace($path); $parts = []; foreach (explode('/', $path) as $part) { switch ($part) { case '': case '.': break; case '..': if (empty($parts)) { throw new LogicException( 'Path is outside of the defined root, path: [' . $path . ']' ); } array_pop($parts); break; default: $parts[] = $part; break; } } return implode('/', $parts); } /** * Removes unprintable characters and invalid unicode characters. * * @param string $path * * @return string $path */ protected static function removeFunkyWhiteSpace($path) { // We do this check in a loop, since removing invalid unicode characters // can lead to new characters being created. while (preg_match('#\p{C}+|^\./#u', $path)) { $path = preg_replace('#\p{C}+|^\./#u', '', $path); } return $path; } /** * Normalize prefix. * * @param string $prefix * @param string $separator * * @return string normalized path */ public static function normalizePrefix($prefix, $separator) { return rtrim($prefix, $separator) . $separator; } /** * Get content size. * * @param string $contents * * @return int content size */ public static function contentSize($contents) { return defined('MB_OVERLOAD_STRING') ? mb_strlen($contents, '8bit') : strlen($contents); } /** * Guess MIME Type based on the path of the file and it's content. * * @param string $path * @param string|resource $content * * @return string|null MIME Type or NULL if no extension detected */ public static function guessMimeType($path, $content) { $mimeType = MimeType::detectByContent($content); if ( ! (empty($mimeType) || in_array($mimeType, ['application/x-empty', 'text/plain', 'text/x-asm']))) { return $mimeType; } return MimeType::detectByFilename($path); } /** * Emulate directories. * * @param array $listing * * @return array listing with emulated directories */ public static function emulateDirectories(array $listing) { $directories = []; $listedDirectories = []; foreach ($listing as $object) { list($directories, $listedDirectories) = static::emulateObjectDirectories($object, $directories, $listedDirectories); } $directories = array_diff(array_unique($directories), array_unique($listedDirectories)); foreach ($directories as $directory) { $listing[] = static::pathinfo($directory) + ['type' => 'dir']; } return $listing; } /** * Ensure a Config instance. * * @param null|array|Config $config * * @return Config config instance * * @throw LogicException */ public static function ensureConfig($config) { if ($config === null) { return new Config(); } if ($config instanceof Config) { return $config; } if (is_array($config)) { return new Config($config); } throw new LogicException('A config should either be an array or a Flysystem\Config object.'); } /** * Rewind a stream. * * @param resource $resource */ public static function rewindStream($resource) { if (ftell($resource) !== 0 && static::isSeekableStream($resource)) { rewind($resource); } } public static function isSeekableStream($resource) { $metadata = stream_get_meta_data($resource); return $metadata['seekable']; } /** * Get the size of a stream. * * @param resource $resource * * @return int stream size */ public static function getStreamSize($resource) { $stat = fstat($resource); return $stat['size']; } /** * Emulate the directories of a single object. * * @param array $object * @param array $directories * @param array $listedDirectories * * @return array */ protected static function emulateObjectDirectories(array $object, array $directories, array $listedDirectories) { if ($object['type'] === 'dir') { $listedDirectories[] = $object['path']; } if (empty($object['dirname'])) { return [$directories, $listedDirectories]; } $parent = $object['dirname']; while ( ! empty($parent) && ! in_array($parent, $directories)) { $directories[] = $parent; $parent = static::dirname($parent); } if (isset($object['type']) && $object['type'] === 'dir') { $listedDirectories[] = $object['path']; return [$directories, $listedDirectories]; } return [$directories, $listedDirectories]; } /** * Returns the trailing name component of the path. * * @param string $path * * @return string */ private static function basename($path) { $separators = DIRECTORY_SEPARATOR === '/' ? '/' : '\/'; $path = rtrim($path, $separators); $basename = preg_replace('#.*?([^' . preg_quote($separators, '#') . ']+$)#', '$1', $path); if (DIRECTORY_SEPARATOR === '/') { return $basename; } // @codeCoverageIgnoreStart // Extra Windows path munging. This is tested via AppVeyor, but code // coverage is not reported. // Handle relative paths with drive letters. c:file.txt. while (preg_match('#^[a-zA-Z]{1}:[^\\\/]#', $basename)) { $basename = substr($basename, 2); } // Remove colon for standalone drive letter names. if (preg_match('#^[a-zA-Z]{1}:$#', $basename)) { $basename = rtrim($basename, ':'); } return $basename; // @codeCoverageIgnoreEnd } } PK s~NJT T src/File.phpnu W+A filesystem->has($this->path); } /** * Read the file. * * @return string|false file contents */ public function read() { return $this->filesystem->read($this->path); } /** * Read the file as a stream. * * @return resource|false file stream */ public function readStream() { return $this->filesystem->readStream($this->path); } /** * Write the new file. * * @param string $content * * @return bool success boolean */ public function write($content) { return $this->filesystem->write($this->path, $content); } /** * Write the new file using a stream. * * @param resource $resource * * @return bool success boolean */ public function writeStream($resource) { return $this->filesystem->writeStream($this->path, $resource); } /** * Update the file contents. * * @param string $content * * @return bool success boolean */ public function update($content) { return $this->filesystem->update($this->path, $content); } /** * Update the file contents with a stream. * * @param resource $resource * * @return bool success boolean */ public function updateStream($resource) { return $this->filesystem->updateStream($this->path, $resource); } /** * Create the file or update if exists. * * @param string $content * * @return bool success boolean */ public function put($content) { return $this->filesystem->put($this->path, $content); } /** * Create the file or update if exists using a stream. * * @param resource $resource * * @return bool success boolean */ public function putStream($resource) { return $this->filesystem->putStream($this->path, $resource); } /** * Rename the file. * * @param string $newpath * * @return bool success boolean */ public function rename($newpath) { if ($this->filesystem->rename($this->path, $newpath)) { $this->path = $newpath; return true; } return false; } /** * Copy the file. * * @param string $newpath * * @return File|false new file or false */ public function copy($newpath) { if ($this->filesystem->copy($this->path, $newpath)) { return new File($this->filesystem, $newpath); } return false; } /** * Get the file's timestamp. * * @return string|false The timestamp or false on failure. */ public function getTimestamp() { return $this->filesystem->getTimestamp($this->path); } /** * Get the file's mimetype. * * @return string|false The file mime-type or false on failure. */ public function getMimetype() { return $this->filesystem->getMimetype($this->path); } /** * Get the file's visibility. * * @return string|false The visibility (public|private) or false on failure. */ public function getVisibility() { return $this->filesystem->getVisibility($this->path); } /** * Get the file's metadata. * * @return array|false The file metadata or false on failure. */ public function getMetadata() { return $this->filesystem->getMetadata($this->path); } /** * Get the file size. * * @return int|false The file size or false on failure. */ public function getSize() { return $this->filesystem->getSize($this->path); } /** * Delete the file. * * @return bool success boolean */ public function delete() { return $this->filesystem->delete($this->path); } } PK s~Ns src/Handler.phpnu W+A path = $path; $this->filesystem = $filesystem; } /** * Check whether the entree is a directory. * * @return bool */ public function isDir() { return $this->getType() === 'dir'; } /** * Check whether the entree is a file. * * @return bool */ public function isFile() { return $this->getType() === 'file'; } /** * Retrieve the entree type (file|dir). * * @return string file or dir */ public function getType() { $metadata = $this->filesystem->getMetadata($this->path); return $metadata['type']; } /** * Set the Filesystem object. * * @param FilesystemInterface $filesystem * * @return $this */ public function setFilesystem(FilesystemInterface $filesystem) { $this->filesystem = $filesystem; return $this; } /** * Retrieve the Filesystem object. * * @return FilesystemInterface */ public function getFilesystem() { return $this->filesystem; } /** * Set the entree path. * * @param string $path * * @return $this */ public function setPath($path) { $this->path = $path; return $this; } /** * Retrieve the entree path. * * @return string path */ public function getPath() { return $this->path; } /** * Plugins pass-through. * * @param string $method * @param array $arguments * * @return mixed */ public function __call($method, array $arguments) { array_unshift($arguments, $this->path); $callback = [$this->filesystem, $method]; try { return call_user_func_array($callback, $arguments); } catch (BadMethodCallException $e) { throw new BadMethodCallException( 'Call to undefined method ' . get_called_class() . '::' . $method ); } } } PK s~Nu: src/FileExistsException.phpnu W+A path = $path; parent::__construct('File already exists at path: ' . $this->getPath(), $code, $previous); } /** * Get the path which was found. * * @return string */ public function getPath() { return $this->path; } } PK s~N~ ~ src/Adapter/SynologyFtp.phpnu W+A [ '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 ($mimetype = Util::guessMimeType($path, $contents)) { $result['mimetype'] = $mimetype; } 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); } return array_filter($result); } /** * @inheritdoc */ public function getMetadata($path) { $location = $this->applyPathPrefix($path); $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'])) { $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)); $visibility = $permissions & 0044 ? AdapterInterface::VISIBILITY_PUBLIC : AdapterInterface::VISIBILITY_PRIVATE; 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'); if ( ! is_dir($location) && ! mkdir($location, $this->permissionMap['dir'][$visibility], true)) { $return = false; } else { $return = ['path' => $dirname, 'type' => 'dir']; } 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); } 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); } } } PK s~N*: : " src/Adapter/AbstractFtpAdapter.phpnu W+A safeStorage = new SafeStorage(); $this->setConfig($config); } /** * Set the config. * * @param array $config * * @return $this */ public function setConfig(array $config) { foreach ($this->configurable as $setting) { if ( ! isset($config[$setting])) { continue; } $method = 'set' . ucfirst($setting); if (method_exists($this, $method)) { $this->$method($config[$setting]); } } return $this; } /** * Returns the host. * * @return string */ public function getHost() { return $this->host; } /** * Set the host. * * @param string $host * * @return $this */ public function setHost($host) { $this->host = $host; return $this; } /** * Set the public permission value. * * @param int $permPublic * * @return $this */ public function setPermPublic($permPublic) { $this->permPublic = $permPublic; return $this; } /** * Set the private permission value. * * @param int $permPrivate * * @return $this */ public function setPermPrivate($permPrivate) { $this->permPrivate = $permPrivate; return $this; } /** * Returns the ftp port. * * @return int */ public function getPort() { return $this->port; } /** * Returns the root folder to work from. * * @return string */ public function getRoot() { return $this->root; } /** * Set the ftp port. * * @param int|string $port * * @return $this */ public function setPort($port) { $this->port = (int) $port; return $this; } /** * Set the root folder to work from. * * @param string $root * * @return $this */ public function setRoot($root) { $this->root = rtrim($root, '\\/') . $this->separator; return $this; } /** * Returns the ftp username. * * @return string username */ public function getUsername() { $username = $this->safeStorage->retrieveSafely('username'); return $username !== null ? $username : 'anonymous'; } /** * Set ftp username. * * @param string $username * * @return $this */ public function setUsername($username) { $this->safeStorage->storeSafely('username', $username); return $this; } /** * Returns the password. * * @return string password */ public function getPassword() { return $this->safeStorage->retrieveSafely('password'); } /** * Set the ftp password. * * @param string $password * * @return $this */ public function setPassword($password) { $this->safeStorage->storeSafely('password', $password); return $this; } /** * Returns the amount of seconds before the connection will timeout. * * @return int */ public function getTimeout() { return $this->timeout; } /** * Set the amount of seconds before the connection should timeout. * * @param int $timeout * * @return $this */ public function setTimeout($timeout) { $this->timeout = (int) $timeout; return $this; } /** * Return the FTP system type. * * @return string */ public function getSystemType() { return $this->systemType; } /** * Set the FTP system type (windows or unix). * * @param string $systemType * * @return $this */ public function setSystemType($systemType) { $this->systemType = strtolower($systemType); return $this; } /** * True to enable timestamps for FTP servers that return unix-style listings * * @param bool $bool * @return $this */ public function setEnableTimestampsOnUnixListings($bool = false) { $this->enableTimestampsOnUnixListings = $bool; return $this; } /** * @inheritdoc */ public function listContents($directory = '', $recursive = false) { return $this->listDirectoryContents($directory, $recursive); } abstract protected function listDirectoryContents($directory, $recursive = false); /** * Normalize a directory listing. * * @param array $listing * @param string $prefix * * @return array directory listing */ protected function normalizeListing(array $listing, $prefix = '') { $base = $prefix; $result = []; $listing = $this->removeDotDirectories($listing); while ($item = array_shift($listing)) { if (preg_match('#^.*:$#', $item)) { $base = preg_replace('~^\./*|:$~', '', $item); continue; } $result[] = $this->normalizeObject($item, $base); } return $this->sortListing($result); } /** * Sort a directory listing. * * @param array $result * * @return array sorted listing */ protected function sortListing(array $result) { $compare = function ($one, $two) { return strnatcmp($one['path'], $two['path']); }; usort($result, $compare); return $result; } /** * Normalize a file entry. * * @param string $item * @param string $base * * @return array normalized file array * * @throws NotSupportedException */ protected function normalizeObject($item, $base) { $systemType = $this->systemType ?: $this->detectSystemType($item); if ($systemType === 'unix') { return $this->normalizeUnixObject($item, $base); } elseif ($systemType === 'windows') { return $this->normalizeWindowsObject($item, $base); } throw NotSupportedException::forFtpSystemType($systemType); } /** * Normalize a Unix file entry. * * Given $item contains: * '-rw-r--r-- 1 ftp ftp 409 Aug 19 09:01 file1.txt' * * This function will return: * [ * 'type' => 'file', * 'path' => 'file1.txt', * 'visibility' => 'public', * 'size' => 409, * 'timestamp' => 1566205260 * ] * * @param string $item * @param string $base * * @return array normalized file array */ protected function normalizeUnixObject($item, $base) { $item = preg_replace('#\s+#', ' ', trim($item), 7); if (count(explode(' ', $item, 9)) !== 9) { throw new RuntimeException("Metadata can't be parsed from item '$item' , not enough parts."); } list($permissions, /* $number */, /* $owner */, /* $group */, $size, $month, $day, $timeOrYear, $name) = explode(' ', $item, 9); $type = $this->detectType($permissions); $path = $base === '' ? $name : $base . $this->separator . $name; if ($type === 'dir') { return compact('type', 'path'); } $permissions = $this->normalizePermissions($permissions); $visibility = $permissions & 0044 ? AdapterInterface::VISIBILITY_PUBLIC : AdapterInterface::VISIBILITY_PRIVATE; $size = (int) $size; $result = compact('type', 'path', 'visibility', 'size'); if ($this->enableTimestampsOnUnixListings) { $timestamp = $this->normalizeUnixTimestamp($month, $day, $timeOrYear); $result += compact('timestamp'); } return $result; } /** * Only accurate to the minute (current year), or to the day * * Inadequacies in timestamp accuracy are due to limitations of the FTP 'LIST' command * * Note: The 'MLSD' command is a machine-readable replacement for 'LIST' * but many FTP servers do not support it :( * * @param string $month e.g. 'Aug' * @param string $day e.g. '19' * @param string $timeOrYear e.g. '09:01' OR '2015' * @return int */ protected function normalizeUnixTimestamp($month, $day, $timeOrYear) { if (is_numeric($timeOrYear)) { $year = $timeOrYear; $hour = '00'; $minute = '00'; $seconds = '00'; } else { $year = date('Y'); list($hour, $minute) = explode(':', $timeOrYear); $seconds = '00'; } $dateTime = DateTime::createFromFormat('Y-M-j-G:i:s', "{$year}-{$month}-{$day}-{$hour}:{$minute}:{$seconds}"); return $dateTime->getTimestamp(); } /** * Normalize a Windows/DOS file entry. * * @param string $item * @param string $base * * @return array normalized file array */ protected function normalizeWindowsObject($item, $base) { $item = preg_replace('#\s+#', ' ', trim($item), 3); if (count(explode(' ', $item, 4)) !== 4) { throw new RuntimeException("Metadata can't be parsed from item '$item' , not enough parts."); } list($date, $time, $size, $name) = explode(' ', $item, 4); $path = $base === '' ? $name : $base . $this->separator . $name; // Check for the correct date/time format $format = strlen($date) === 8 ? 'm-d-yH:iA' : 'Y-m-dH:i'; $dt = DateTime::createFromFormat($format, $date . $time); $timestamp = $dt ? $dt->getTimestamp() : (int) strtotime("$date $time"); if ($size === '