<?php 
 
namespace League\Flysystem; 
 
use League\Flysystem\Util\MimeType; 
use LogicException; 
 
class Util 
{ 
    /** 
     * Get normalized pathinfo. 
     * 
     * @param string $path 
     * 
     * @return array pathinfo 
     */ 
    public static function pathinfo($path) 
    { 
        $pathinfo = pathinfo($path) + compact('path'); 
        $pathinfo['dirname'] = array_key_exists('dirname', $pathinfo) 
            ? static::normalizeDirname($pathinfo['dirname']) : ''; 
 
        return $pathinfo; 
    } 
 
    /** 
     * 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]; 
    } 
} 
 
 |