web-dev-qa-db-fra.com

Comment obtenir la taille du répertoire dans 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

Avez-vous une idée de la raison pour laquelle l'utilisation du processeur augmente trop ou 100% jusqu'à la fin de l'exécution du script? Peut-on faire quelque chose pour l'optimiser? ou existe-t-il un autre moyen de vérifier le dossier et les dossiers qu'il contient?

48
Mr Bosh

Voici d'autres solutions offertes ailleurs :

Si sur un hôte 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';
    }
?>

Sinon, si sur un hôte 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;
?>
39
Sampson
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;
}

La même idée que Janith Chinthana a suggéré. Avec quelques corrections:

  • Convertit $path en realpath
  • Effectue l'itération uniquement si le chemin est valide et que le dossier existe
  • Ignore les fichiers . et ..
  • Optimisé pour la performance
56
Alph.Dev

Un exemple pur en 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];
}

?>
27
vdbuilder

taille du répertoire en utilisant php taille du fichier et RecursiveIteratorIterator

Cela fonctionne avec n'importe quelle plate-forme ayant une version de PHP 5 ou supérieure.

**
 * 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;
} 
24
Janith Chinthana
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;
} 
13
Alex Kashin

Grâce à Jonathan Sampson, Adam Pierce et Janith Chinthana, je l’ai vérifiée pour trouver la manière la plus performante d’obtenir la taille du répertoire. Devrait fonctionner sur les hôtes Windows et 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);
    }
}
9
André Fiedler

J'ai trouvé cette approche plus courte et plus compatible. La version "du" pour Mac OS X ne prend pas en charge l’option -b (ou --bytes) pour une raison quelconque; elle est donc liée à l’option plus compatible -k.

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

Renvoie la taille de fichier $ en octets.

6
Nate Lampton

L'exemple Linux de Johnathan Sampson n'a pas fonctionné aussi bien pour moi. Voici une version améliorée:

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

Même s'il y a déjà beaucoup de réponses à ce message, j'estime devoir ajouter une autre option pour les hôtes Unix qui ne renvoie que la somme de toutes les tailles de fichiers du répertoire (récursivement).

Si vous regardez la réponse de Jonathan, il utilise la commande du. Cette commande renverra la taille totale du répertoire, mais les solutions pures PHP publiées par d’autres ici renverront la somme de toutes les tailles de fichiers. Grande différence!

Que chercher

Lors de l'exécution de du sur un répertoire nouvellement créé, il peut renvoyer 4K au lieu de 0. Cela peut même devenir plus déroutant après avoir supprimé des fichiers du répertoire en question et avoir du rapportant une taille de répertoire totale qui ne correspond pas à la somme des tailles des fichiers qu'il contient. Pourquoi? La commande du renvoie un rapport basé sur certains paramètres de fichier, comme l'a commenté Hermann Ingjaldsson sur this post .

La solution

Pour former une solution qui se comporte comme certains des scripts PHP uniquement publiés ici, vous pouvez utiliser la commande ls et la transmettre à awk comme ceci:

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

En tant que fonction PHP, vous pouvez utiliser quelque chose comme ceci:

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;
}
5
halfpastfour.am

Vous pouvez optimiser le script de différentes manières, mais le maximum de succès le rendrait lié à l'IO plutôt qu'à l'unité centrale:

  1. Calculez rtrim($path, '/') en dehors de la boucle.
  2. faire if ($t<>"." && $t<>"..") le test externe - il n'a pas besoin de stat sur le chemin
  3. Calculez rtrim($path, '/') . '/' . $t une fois par boucle - à l'intérieur de 2) et en prenant 1) en compte.
  4. Calculez explode(' ','B KB MB GB TB PB'); une fois plutôt que chaque appel?
2
Douglas Leeder

PHP obtenir la taille du répertoire (avec accès FTP)

Après un travail acharné, ce code fonctionne très bien !!!! et je veux partager avec la communauté (par 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);

Bon code! Fernando

2
Fernando

Juste une autre fonction utilisant les fonctions PHP natives.

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

REMARQUE: cette fonction renvoie la taille des fichiers, PAS la taille sur le disque

1
Accountant م

Approche Orientée Objet: 

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

Approche rapide et furieuse:

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

En ce qui concerne l'exemple Linux de Johnathan Sampson, faites attention lorsque vous effectuez un intval sur le résultat de la fonction "du", si la taille est> 2 Go, il continue d'afficher 2 Go.

Remplacer:  

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

par:

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

supposé que votre fonction "du" retourne la taille séparée par un espace suivi du nom du répertoire/fichier.

1
M J

Evolue à partir de la réponse de Nate Haugs, j’ai créé une fonction courte pour mon projet:

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);
}
0
maxpower9000

Cela fonctionne parfaitement bien.

     public static function folderSize($dir)
     {
        $size = 0;

        foreach (glob(rtrim($dir, '/') . '/*', GLOB_NOSORT) as $each) {
            $func_name = __FUNCTION__;
            $size += is_file($each) ? filesize($each) : static::$func_name($each);
        }

        return $size;
      }
0
akshaypjoshi

Une solution one-liner. Résultat en octets.

$size=array_sum(array_map('filesize', glob("{$dir}/*.*")));

Bonus supplémentaire: vous pouvez simplement changer le masque de fichier comme bon vous semble, et ne compter que certains fichiers (par exemple, par extension).

0
Steve Horvath

Code ajusté pour accéder au répertoire principal et à tous les sous-dossiers qu'il contient. Cela renverrait la taille complète du répertoire.

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

        if (is_dir($path))
        {
            $size += get_dir_size($path);
        }
    }
    return $size;
}
0
Ifeanyi Amadi