PHP i określenie wielkości pliku / katalogu

bytes

W moim ostatnim wpisie pisałem o operacjach na plikach i katalogach w języku PHP. Opisałem kilka funkcji, w tym jedną, która pozwalała na określenie rozmiaru pliku lub całego katalogu.

Chciałbym ją nieco rozwinąć i pokazać bardziej rozbudowane użycie, które pozwoli w ludzki sposób formatować ilość bajtów otrzymanych w ramach obliczeń.

Przypomnienie funkcji – rozmiar pliku lub katalogu

/**
 * Rozmiar pliku lub katalogu
 *
 * UWAGA: Na systemach 32bitowych mozemy otrzymac niespodziewane wyniki dla plikow majacych rozmiar ponad 2GB
 *
 * @param string $path sciezka do pliku lub katalogu
 * @return int rozmiar (w bajtach)
 */
function sizeRecursive($path) {
    $size = 0;
    if (is_dir($path)) {
        $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path));

        foreach ($iterator as $file) {
            $size += $file->getSize();
        }
    } else {
        $size = filesize($path);
    }

    return $size;
}

W ramach rozwinięcia powyższego, zbuduję klasę, która pozwoli mi zrealizować formatowanie zwracanych danych.

/**
 * Klasa do zarzadzania plikami / katalogami w systemie plikow
 */
class FileManagment {

    /**
     * Tablica jednostek wielkosci
     *
     * @var array
     */
    private static $units = array('B', 'KB', 'MB', 'GB', 'TB');

    /**
     * Funkcja automatycznie obliczajaca najbardziej odpowiednia jednostke 
     * oraz ograniczajaca liczbe miejsc po przecinku do wskazanej w parametrze $precision ilosci
     * 
     * @param string $path          sciezka do pliku lub katalogu
     * @param integer $precision    precyzja podawanego wyniku (po przecinku)
     * @return mixed                false - gdy niepoprawny parametr $precision
     *                              string - wynik obliczen
     */
    public static function autoSize($path, $precision = 2) {
        if (!is_numeric($precision)) {
            return false;
        }
        $bytes = self::sizeRecursive(trim($path));
        $bytes = max($bytes, 0);
        $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
        $pow = min($pow, count(self::$units) - 1);
        $bytes /= pow(1024, $pow);
        $retValue = round($bytes, $precision).' '.self::$units[$pow];

        return $retValue;
    }

    /**
     * Funkcja obliczajaca rozmiar wedle konkretnie zadanej jednostki
     * 
     * @param string $path          sciezka do pliku lub katalogu
     * @param string $unitType      jednostka w jakiej zwrocony ma byc wynik
     * @param integer $precision    precyzja podawanego wyniku (po przecinku)
     * @return mixed                false - gdy niepoprawny parametr $precision
     *                              string - wynik obliczen
     */
    public static function sizeWithOption($path, $unitType = 'KB', $precision = 2) {
        if (!is_numeric($precision)) {
            return false;
        }
        $bytes = self::sizeRecursive(trim($path));
        switch($unitType) {
            case self::$units[0]: 
                $size = number_format($bytes, $precision) ; 
                break;
            case self::$units[1]: 
                $size = number_format(($bytes / 1024), $precision) ; 
                break;
            case self::$units[2]: 
                $size = number_format(($bytes / 1024 / 1024), $precision) ; 
                break;
            case self::$units[3]: 
                $size = number_format(($bytes / 1024 / 1024 / 1024), $precision) ; 
                break;
            case self::$units[4]: 
                $size = number_format(($bytes / 1024 / 1024 / 1024 / 1024), $precision) ; 
                break;
        }
        $retValue = $size.' '.$unitType;

        return $retValue;
    }

    /**
     * Rozmiar pliku lub katalogu
     *
     * UWAGA: Na systemach 32bitowych mozemy otrzymac niespodziewane wyniki dla plikow majacych rozmiar ponad 2GB
     *
     * @param string $path          sciezka do pliku lub katalogu
     * @return int                  rozmiar (w bajtach)
     */
    private static function sizeRecursive($path) {
        $size = 0;
        if (is_dir($path)) {
            $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path));

            foreach ($iterator as $file) {
                $size += $file->getSize();
            }
        } elseif (is_file($path)) {
            $size = filesize($path);
        }

        return $size;
    }

}

Przykład użycia

require_once('FileManagment.php');
$fileManagment = new FileManagment();

echo 'autoSize: '.$fileManagment::autoSize('Zdjecia');
// autoSize: 41.89 MB
echo 'sizeWithOption: '.$fileManagment::sizeWithOption('Zdjecia', 'GB', 4);
// sizeWithOption: 0.0409 GB

Mam nadzieję, że przykład ten jest na tyle jasny, że nie wymaga on dalszego omawiania. Jeżeli jednak pojawią się jakieś pytania, to jak zawsze odpowiem w komentarzach poniżej.