355 lines
		
	
	
		
			8.3 KiB
		
	
	
	
		
			PHP
		
	
	
		
		
			
		
	
	
			355 lines
		
	
	
		
			8.3 KiB
		
	
	
	
		
			PHP
		
	
	
|  | <?php | ||
|  | 
 | ||
|  | namespace League\Flysystem; | ||
|  | 
 | ||
|  | use League\Flysystem\Util\MimeType; | ||
|  | use LogicException; | ||
|  | 
 | ||
|  | use function strcmp; | ||
|  | 
 | ||
|  | class Util | ||
|  | { | ||
|  |     /** | ||
|  |      * Get normalized pathinfo. | ||
|  |      * | ||
|  |      * @param string $path | ||
|  |      * | ||
|  |      * @return array pathinfo | ||
|  |      */ | ||
|  |     public static function pathinfo($path) | ||
|  |     { | ||
|  |         $pathinfo = compact('path'); | ||
|  | 
 | ||
|  |         if ('' !== $dirname = dirname($path)) { | ||
|  |             $pathinfo['dirname'] = static::normalizeDirname($dirname); | ||
|  |         } | ||
|  | 
 | ||
|  |         $pathinfo['basename'] = static::basename($path); | ||
|  | 
 | ||
|  |         $pathinfo += pathinfo($pathinfo['basename']); | ||
|  | 
 | ||
|  |         return $pathinfo + ['dirname' => '']; | ||
|  |     } | ||
|  | 
 | ||
|  |     /** | ||
|  |      * 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; | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         $path = implode('/', $parts); | ||
|  | 
 | ||
|  |         return $path; | ||
|  |     } | ||
|  | 
 | ||
|  |     /** | ||
|  |      * Rejects unprintable characters and invalid unicode characters. | ||
|  |      * | ||
|  |      * @param string $path | ||
|  |      * | ||
|  |      * @return string $path | ||
|  |      */ | ||
|  |     protected static function removeFunkyWhiteSpace($path) | ||
|  |     { | ||
|  |         if (preg_match('#\p{C}+#u', $path)) { | ||
|  |             throw CorruptedPathDetected::forPath($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) { | ||
|  |             [$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|null stream size | ||
|  |      */ | ||
|  |     public static function getStreamSize($resource) | ||
|  |     { | ||
|  |         $stat = fstat($resource); | ||
|  | 
 | ||
|  |         if ( ! is_array($stat) || ! isset($stat['size'])) { | ||
|  |             return null; | ||
|  |         } | ||
|  | 
 | ||
|  |         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 ( ! isset($object['dirname']) || trim($object['dirname']) === '') { | ||
|  |             return [$directories, $listedDirectories]; | ||
|  |         } | ||
|  | 
 | ||
|  |         $parent = $object['dirname']; | ||
|  | 
 | ||
|  |         while (isset($parent) && trim($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
 | ||
|  |     } | ||
|  | } |