Подтвердить что ты не робот

Как получить размер каталога в PHP

function foldersize($path) {
  $total_size = 0;
  $files = scandir($path);

  foreach($files as $t) {
    if (is_dir(rtrim($path, '/') . '/' . $t)) {
      if ($t<>"." && $t<>"..") {
          $size = foldersize(rtrim($path, '/') . '/' . $t);

          $total_size += $size;
      }
    } else {
      $size = filesize(rtrim($path, '/') . '/' . $t);
      $total_size += $size;
    }
  }
  return $total_size;
}

function format_size($size) {
  $mod = 1024;
  $units = explode(' ','B KB MB GB TB PB');
  for ($i = 0; $size > $mod; $i++) {
    $size /= $mod;
  }

  return round($size, 2) . ' ' . $units[$i];
}

$SIZE_LIMIT = 5368709120; // 5 GB

$sql="select * from users order by id";
$result=mysql_query($sql);

while($row=mysql_fetch_array($result)) {
  $disk_used = foldersize("C:/xampp/htdocs/freehosting/".$row['name']);

  $disk_remaining = $SIZE_LIMIT - $disk_used;
  print 'Name: ' . $row['name'] . '<br>';

  print 'diskspace used: ' . format_size($disk_used) . '<br>';
  print 'diskspace left: ' . format_size($disk_remaining) . '<br><hr>';
}

php disk_total_space

Любая идея, почему использование процессора увеличивается слишком высоко или на 100% до завершения выполнения script? Можно ли что-то сделать для его оптимизации? или есть ли другой альтернативный способ проверки папки и папок внутри него?

4b9b3361

Ответ 1

Ниже перечислены другие решения предлагаемые в другом месте:

Если на хосте Windows:

<?
    $f = 'f:/www/docs';
    $obj = new COM ( 'scripting.filesystemobject' );
    if ( is_object ( $obj ) )
    {
        $ref = $obj->getfolder ( $f );
        echo 'Directory: ' . $f . ' => Size: ' . $ref->size;
        $obj = null;
    }
    else
    {
        echo 'can not create object';
    }
?>

Else, если на хосте Linux:

<?
    $f = './path/directory';
    $io = popen ( '/usr/bin/du -sk ' . $f, 'r' );
    $size = fgets ( $io, 4096);
    $size = substr ( $size, 0, strpos ( $size, "\t" ) );
    pclose ( $io );
    echo 'Directory: ' . $f . ' => Size: ' . $size;
?>

Ответ 2

function GetDirectorySize($path){
    $bytestotal = 0;
    $path = realpath($path);
    if($path!==false && $path!='' && file_exists($path)){
        foreach(new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path, FilesystemIterator::SKIP_DOTS)) as $object){
            $bytestotal += $object->getSize();
        }
    }
    return $bytestotal;
}

Та же идея, что и Дженит Чинтанана. С несколькими исправлениями:

  • Преобразует $path в realpath
  • Выполняет итерацию только в том случае, если путь действителен и существует папка
  • Пропускает . и .. файлы
  • Оптимизирован для производительности

Ответ 3

Пример с чистым php.

<?php
    $units = explode(' ', 'B KB MB GB TB PB');
    $SIZE_LIMIT = 5368709120; // 5 GB
    $disk_used = foldersize("/webData/users/[email protected]");

    $disk_remaining = $SIZE_LIMIT - $disk_used;

    echo("<html><body>");
    echo('diskspace used: ' . format_size($disk_used) . '<br>');
    echo( 'diskspace left: ' . format_size($disk_remaining) . '<br><hr>');
    echo("</body></html>");


function foldersize($path) {
    $total_size = 0;
    $files = scandir($path);
    $cleanPath = rtrim($path, '/'). '/';

    foreach($files as $t) {
        if ($t<>"." && $t<>"..") {
            $currentFile = $cleanPath . $t;
            if (is_dir($currentFile)) {
                $size = foldersize($currentFile);
                $total_size += $size;
            }
            else {
                $size = filesize($currentFile);
                $total_size += $size;
            }
        }   
    }

    return $total_size;
}


function format_size($size) {
    global $units;

    $mod = 1024;

    for ($i = 0; $size > $mod; $i++) {
        $size /= $mod;
    }

    $endIndex = strpos($size, ".")+3;

    return substr( $size, 0, $endIndex).' '.$units[$i];
}

?>

Ответ 4

с помощью php filesize и RecursiveIteratorIterator.

Это работает с любой платформой, имеющей версию php 5 или более поздней версии.

**
 * Get the directory size
 * @param directory $directory
 * @return integer
 */
function dirSize($directory) {
    $size = 0;
    foreach(new RecursiveIteratorIterator(new RecursiveDirectoryIterator($directory)) as $file){
        $size+=$file->getSize();
    }
    return $size;
} 

Ответ 5

function get_dir_size($directory){
    $size = 0;
    $files= glob($directory.'/*');
    foreach($files as $path){
        is_file($path) && $size += filesize($path);
        is_dir($path) && get_dir_size($path);
    }
    return $size;
} 

Ответ 6

Благодаря Джонатану Сэмпсону, Адаму Пирсу и Джениту Чинтане я сделал это, проверяя наиболее эффективный способ получить размер каталога. Должен работать на хостах Windows и Linux.

static function getTotalSize($dir)
{
    $dir = rtrim(str_replace('\\', '/', $dir), '/');

    if (is_dir($dir) === true) {
        $totalSize = 0;
        $os        = strtoupper(substr(PHP_OS, 0, 3));
        // If on a Unix Host (Linux, Mac OS)
        if ($os !== 'WIN') {
            $io = popen('/usr/bin/du -sb ' . $dir, 'r');
            if ($io !== false) {
                $totalSize = intval(fgets($io, 80));
                pclose($io);
                return $totalSize;
            }
        }
        // If on a Windows Host (WIN32, WINNT, Windows)
        if ($os === 'WIN' && extension_loaded('com_dotnet')) {
            $obj = new \COM('scripting.filesystemobject');
            if (is_object($obj)) {
                $ref       = $obj->getfolder($dir);
                $totalSize = $ref->size;
                $obj       = null;
                return $totalSize;
            }
        }
        // If System calls did't work, use slower PHP 5
        $files = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($dir));
        foreach ($files as $file) {
            $totalSize += $file->getSize();
        }
        return $totalSize;
    } else if (is_file($dir) === true) {
        return filesize($dir);
    }
}

Ответ 7

Пример Johnathan Sampson Linux для меня не так хорош. Здесь улучшенная версия:

function getDirSize($path)
{
    $io = popen('/usr/bin/du -sb '.$path, 'r');
    $size = intval(fgets($io,80));
    pclose($io);
    return $size;
}

Ответ 8

Я нашел этот подход более коротким и более совместимым. По какой-то причине версия "du" для Mac OS X не поддерживает параметр -b (или --bytes), поэтому это относится к более-совместимой опции -k.

$file_directory = './directory/path';
$output = exec('du -sk ' . $file_directory);
$filesize = trim(str_replace($file_directory, '', $output)) * 1024;

Возвращает $filesize в байтах.

Ответ 9

Несмотря на то, что на этот пост уже много ответов, я чувствую, что мне нужно добавить еще один вариант для хостов unix, который возвращает сумму всех размеров файлов в каталоге (рекурсивно).

Если вы посмотрите на ответ Джонатана, он использует команду du. Эта команда вернет общий размер каталога, но чистые PHP-решения, размещенные другими пользователями, вернут сумму всех размеров файлов. Большая разница!

Что нужно искать

При запуске du во вновь создаваемом каталоге он может возвращать 4K вместо 0. Это может даже стать более запутанным после удаления файлов из рассматриваемого каталога, указав du общий размер каталога, который не соответствует сумме размеров файлов внутри него. Зачем? Команда du возвращает отчет на основе некоторых настроек файла, так как Hermann Ingjaldsson прокомментировал этот пост.

Решение

Чтобы сформировать решение, которое ведет себя как некоторые скрипты только для PHP, вы можете использовать команду ls и передать ее в awk следующим образом:

ls -ltrR /path/to/dir |awk '{print \$5}'|awk 'BEGIN{sum=0} {sum=sum+\$1} END {print sum}'

В качестве функции PHP вы можете использовать что-то вроде этого:

function getDirectorySize( $path )
{
    if( !is_dir( $path ) ) {
        return 0;
    }

    $path   = strval( $path );
    $io     = popen( "ls -ltrR {$path} |awk '{print \$5}'|awk 'BEGIN{sum=0} {sum=sum+\$1} END {print sum}'", 'r' );
    $size   = intval( fgets( $io, 80 ) );
    pclose( $io );

    return $size;
}

Ответ 10

Есть несколько вещей, которые вы могли бы сделать для оптимизации script, но максимальный успех сделает его привязанным к IO, а не привязанным к ЦП:

  • Вычислить rtrim($path, '/') вне цикла.
  • сделать if ($t<>"." && $t<>"..") внешний тест - ему не нужно указывать путь
  • Рассчитать rtrim($path, '/') . '/' . $t один раз за цикл - внутри 2) и учитывать 1).
  • Рассчитать explode(' ','B KB MB GB TB PB'); один раз, а не каждый вызов?

Ответ 11

PHP получить размер каталога (с FTP-доступом)

После тяжелой работы этот код отлично работает!!!! и я хочу поделиться с сообществом (по MundialSYS)

function dirFTPSize($ftpStream, $dir) {
    $size = 0;
    $files = ftp_nlist($ftpStream, $dir);

    foreach ($files as $remoteFile) {
        if(preg_match('/.*\/\.\.$/', $remoteFile) || preg_match('/.*\/\.$/', $remoteFile)){
            continue;
        }
        $sizeTemp = ftp_size($ftpStream, $remoteFile);
        if ($sizeTemp > 0) {
            $size += $sizeTemp;
        }elseif($sizeTemp == -1){//directorio
            $size += dirFTPSize($ftpStream, $remoteFile);
        }
    }

    return $size;
}

$hostname = '127.0.0.1'; // or 'ftp.domain.com'
$username = 'username';
$password = 'password';
$startdir = '/public_html'; // absolute path
$files = array();
$ftpStream = ftp_connect($hostname);
$login = ftp_login($ftpStream, $username, $password);
if (!$ftpStream) {
    echo 'Wrong server!';
    exit;
} else if (!$login) {
    echo 'Wrong username/password!';
    exit;
} else {
    $size = dirFTPSize($ftpStream, $startdir);
}

echo number_format(($size / 1024 / 1024), 2, '.', '') . ' MB';

ftp_close($ftpStream);

Хороший код! Фернандо

Ответ 12

Что касается примера Johnathan Sampson Linux, обратите внимание, когда вы делаете intval по результату функции "du", если размеp > 2 ГБ, он будет показывать 2 ГБ.

Заменить:

$totalSize = intval(fgets($io, 80));

по

strtok(fgets($io, 80), " ");

предполагается, что ваша функция "du" возвращает размер, разделенный пробелом, за которым следует имя каталога/файла.

Ответ 13

Еще одна функция, использующая встроенные функции php.

function dirSize($dir)
    {
        $dirSize = 0;
        if(!is_dir($dir)){return false;};
        $files = scandir($dir);if(!$files){return false;}
        $files = array_diff($files, array('.','..'));

        foreach ($files as $file) {
            if(is_dir("$dir/$file")){
                 $dirSize += dirSize("$dir/$file");
            }else{
                $dirSize += filesize("$dir/$file");
            }
        }
        return $dirSize;
    }

ПРИМЕЧАНИЕ: эта функция возвращает размеры файлов, а не размер на диске

Ответ 14

Из ответа Nate Haugs я создал короткую функцию для моего проекта:

function uf_getDirSize($dir, $unit = 'm')
{
    $dir = trim($dir, '/');
    if (!is_dir($dir)) {
        trigger_error("{$dir} not a folder/dir/path.", E_USER_WARNING);
        return false;
    }
    if (!function_exists('exec')) {
        trigger_error('The function exec() is not available.', E_USER_WARNING);
        return false;
    }
    $output = exec('du -sb ' . $dir);
    $filesize = (int) trim(str_replace($dir, '', $output));
    switch ($unit) {
        case 'g': $filesize = number_format($filesize / 1073741824, 3); break;  // giga
        case 'm': $filesize = number_format($filesize / 1048576, 1);    break;  // mega
        case 'k': $filesize = number_format($filesize / 1024, 0);       break;  // kilo
        case 'b': $filesize = number_format($filesize, 0);              break;  // byte
    }
    return ($filesize + 0);
}

Ответ 15

Объектно-ориентированный подход:

/**
 * Returns a directory size
 *
 * @param string $directory
 *
 * @return int $size directory size in bytes
 *
 */
function dir_size($directory)
{
    $size = 0;
    foreach(new RecursiveIteratorIterator(new RecursiveDirectoryIterator($directory)) as $file)
    {
        $size += $file->getSize();
    }
    return $size;
}

Быстрый и яростный подход:

function dir_size2($dir)
{
    $line = exec('du -sh ' . $dir);
    $line = trim(str_replace($dir, '', $line));
    return $line;
}