Как получить размер каталога в 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% до завершения выполнения скрипта? Можно ли что-то сделать для его оптимизации? или есть ли другой альтернативный способ проверки папок и папок внутри него?

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

Если на хосте 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'; } ?> 

Иначе, если на хосте 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; ?> 
 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
  • Выполняет итерацию только в том случае, если путь действителен и существует папка
  • Пропускает . и .. файлы
  • Оптимизирован для работы

Чистый пример php.

 <?php $units = explode(' ', 'B KB MB GB TB PB'); $SIZE_LIMIT = 5368709120; // 5 GB $disk_used = foldersize("/webData/users/vdbuilder@yahoo.com"); $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]; } ?> 

размер каталога, используя 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; } 
 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; } 

Благодаря Джонатану Сэмпсону, Адаму Пирсу и Джениту Чинтане я сделал это, проверяя наиболее эффективный способ получить размер каталога. Должен работать на хостах 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); } } 

Пример Linux Джонатана Сампсона для меня не так хорош. Вот улучшенная версия:

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

Я нашел этот подход более коротким и более совместимым. По какой-то причине версия «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 в байтах.

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

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

Что посмотреть

При запуске du во вновь создаваемом каталоге он может возвращать 4K вместо 0 . Это может даже стать более запутанным после удаления файлов из соответствующего каталога, указав полный размер каталога, который не соответствует сумме размеров файлов внутри него. Зачем? Команда 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; } 

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

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

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); 

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

Что касается примера Linux Джонатана Сампсона, обратите внимание, когда вы делаете intval по результату функции «du», если размер> 2 ГБ, он будет показывать 2 ГБ.

Заменить:

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

от:

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

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

Еще одна функция, использующая встроенные функции 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; } 

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

Из ответа 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); } 

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

 /** * 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; }