What is the best way to get the size of a directory in PHP? I'm looking for a lightweight way to do this since the directories I'll use this for are pretty huge.
There already was a question about this on SO, but it's three years old and the solutions are outdated.(Nowadays fopen is disabled for security reasons.)
Is the RecursiveDirectoryIterator available to you?
$bytes = 0;
$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir));
foreach ($iterator as $i)
{
$bytes += $i->getSize();
}
You could try the execution operator with the unix command du:
$output = du -s $folder;
FROM: http://www.darian-brown.com/get-php-directory-size/
Or write a custom function to total the filesize of all the files in the directory:
function getDirectorySize($path)
{
$totalsize = 0;
$totalcount = 0;
$dircount = 0;
if($handle = opendir($path))
{
while (false !== ($file = readdir($handle)))
{
$nextpath = $path . '/' . $file;
if($file != '.' && $file != '..' && !is_link ($nextpath))
{
if(is_dir($nextpath))
{
$dircount++;
$result = getDirectorySize($nextpath);
$totalsize += $result['size'];
$totalcount += $result['count'];
$dircount += $result['dircount'];
}
else if(is_file ($nextpath))
{
$totalsize += filesize ($nextpath);
$totalcount++;
}
}
}
}
closedir($handle);
$total['size'] = $totalsize;
$total['count'] = $totalcount;
$total['dircount'] = $dircount;
return $total;
}
Related
I am wanting to calculate the weight of a directory in php, then display the data as per the example below.
Example:
Storage
50 GB (14.12%) of 353 GB used
I have the following function, with which I show in a list the folders that are inside the root.
<?php
$dir = ('D:\data');
echo "Size : " Fsize($dir);
function Fsize($dir)
{
if (is_dir($dir))
{
if ($gd = opendir($dir))
{
$cont = 0;
while (($file = readdir($gd)) !== false)
{
if ($file != "." && $file != ".." )
{
if (is_dir($file))
{
$cont += Fsize($dir."/".$file);
}
else
{
$cont += filesize($dir."/".$file);
echo "file : " . $dir."/".$file . " " . filesize($dir."/".$file)."<br />";
}
}
}
closedir($gd);
}
}
return $cont;
}
?>
The size it shows me of the folder is 3891923, but it is not the real size, when validating the directory the real size is 191791104 bytes
Can you help me, please?
Your test for directory is incorrect here:
if (is_dir($file)) // This test is missing the directory component
{
$cont += Fsize($dir."/".$file);
}
else
Try:
if (is_dir("$dir/$file")) // This test adds the directory path
{
$cont += Fsize($dir."/".$file);
}
else
PHP offers a number of iterators that can simplify operations like this:
$path = "path/to/folder";
$Directory = new RecursiveDirectoryIterator($path);
$Iterator = new RecursiveIteratorIterator($Directory);
$Iterator->setFlags(FilesystemIterator::SKIP_DOTS);
$totalFilesize = 0;
foreach($Iterator as $file){
if ($file->isFile()) {
$totalFilesize += $file->getSize();
}
}
echo "Total: $totalFilesize";
I took over this site for management. the former developer used opendir() which opens only one level before getting the files in the folder. I would like to create multi-level folders before the final files. I created the sub-folders on the server but I need to modify the code to dynamically recognise the sub-folders as folders not file.
if ($handle = opendir("parentfolder/".$pageid.'/')) {
$list = array();
while (false !== ($file = readdir($handle))) {
if ($file != "." && $file != "..") {
$list[] = "$file\n";
}
}
rsort($list);
$clength = count($list);
for($x = 0; $x <$clength; $x++){
$pubFolders .= "<a href='".$maindomain."/reports/".$list[$x]."' class='imagefolders'><img src='".$maindomain."/images/icons/image.png' alt=''/><br>".$list[$x]."</a>";
}
$data = $data.$pubFolders;
closedir($handle);
}
Use glob() with GLOB_ONLYDIR; some example functions are as follows:
function findDirectories($rootPath) {
$directories = array();
foreach (glob($rootPath . "/*", GLOB_ONLYDIR) as $directory) {
$directories[] = $directory;
}
return $directories;
}
function findFiles($rootPath, $extension) {
$files = array();
foreach (glob($rootPath . "/*.$extension") as $file) {
$files[] = $file;
}
return $files;
}
function findFilesRecursive($rootPath,$extension) {
$files = findFiles($rootPath,$extension);
$directories = findDirectories($rootPath);
if (!empty($directories)) {
foreach ($directories as $key=>$directory) {
$foundFiles = findFilesRecursive($directory,$extension);
foreach ($foundFiles as $foundFile) {
$files[] = $foundFile;
}
}
}
return $files;
}
If you don't care about defining specific extensions, just pass in * as the $extension parameter.
I'm using this function to get the file size & file count from a given directory:
function getDirSize($path) {
$total_size = 0;
$total_files = 0;
$path = realpath($path);
if($path !== false){
foreach(new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path, FilesystemIterator::SKIP_DOTS)) as $object) {
$total_size += $object->getSize();
$total_files++;
}
}
$t['size'] = $total_size;
$t['count'] = $total_files;
return $t;
}
I need to skip a single directory (in the root of $path). Is there a simple way to do this? I looked at other answers referring to FilterIterator, but I'm not very familiar with it.
If you don't want to involve a FilterIterator you can add a simple path match:
function getDirSize($path, $ignorePath) {
$total_size = 0;
$total_files = 0;
$path = realpath($path);
$ignorePath = realpath($path . DIRECTORY_SEPARATOR . $ignorePath);
if($path !== false){
foreach(new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path, FilesystemIterator::SKIP_DOTS)) as $object) {
if (strpos($object->getPath(), $ignorePath) !== 0) {
$total_size += $object->getSize();
$total_files++;
}
}
}
$t['size'] = $total_size;
$t['count'] = $total_files;
return $t;
}
// Get total file size and count of current directory,
// excluding the 'ignoreme' subdir
print_r(getDirSize(__DIR__ , 'ignoreme'));
How to count the number of files in a directory using PHP?
Please answer for the following things:
1. Recursive Search: The directory (which is being searched) might be having several other directories and files.
2. Non-Recursive Search: All the directories should be ignored which are inside the directory that is being searched. Only files to be considered.
I am having the following code, but looking for a better solution.
<?php
$files = array();
$dir = opendir('./items/2/l');
while(($file = readdir($dir)) !== false)
{
if($file !== '.' && $file !== '..' && !is_dir($file))
{
$files[] = $file;
}
}
closedir($dir);
//sort($files);
$nooffiles = count($files);
?>
Recursive:
$it = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir));
$count = 0;
while($it->next()) $count++;
Most of the mentioned ways for "Non-Recursive Search" work, though it can be shortened using PHP's glob filesystem function.
It basically finds pathnames matching a pattern and thus can be used as:
$count = 0;
foreach (glob('path\to\dir\*.*') as $file) {
$count++;
}
The asterisk before the dot denotes the filename, and the one after denotes the file extension. Thus, its use can further be extended to counting files with specific filenames, specific extensions or both.
non-recrusive:
$dir = opendir('dir/');
$i = 0;
while (false !== ($file = readdir($dir))){
if (!in_array($file, array('.', '..') and !is_dir($file)) $i++;
}
echo "There were $i files";
recrusive:
function crawl($dir){
$dir = opendir($dir);
$i = 0;
while (false !== ($file = readdir($dir)){
if (is_dir($file) and !in_array($file, array('.', '..'))){
$i += crawl($file);
}else{
$i++;
}
}
return $i;
}
$i = crawl('dir/');
echo "There were $i files";
Might be useful for you:
http://www.php.net/manual/en/class.dir.php
http://www.php.net/manual/en/function.is-file.php
But, i think, there is no other good solutions.
Rather than posting code for you, I would provide the outline of what you should do as you seem to have the basic code already.
Place your code in a function. Have two parameters ($path, $recursive = FALSE) and within your code, separate the is_dir() and if that's true and the recursive flag is true, then pass the new path (path to the current file) back to the function (self reference).
Hope this helps you learn, rather than copy paste :-)
Something like this might work:
(might need to add some checks for '/' for the $dir.$file concatenation)
$files = array();
$dir = './items/2/l';
countFiles($dir, $files); // Recursive
countFiles($dir, $files, false); // Not recursive;
var_dump(count($files));
function countFiles($directory, &$fileArray, $recursive = true){
$currDir = opendir($directory);
while(($file = readdir($dir)) !== false)
{
if(is_dir($file) && $recursive){
countFiles($directory.$fileArray, $saveArray);
}
else if($file !== '.' && $file !== '..' && !is_dir($file))
{
$fileArray[] = $file;
}
}
}
Recursive:
function count_files($path) {
// (Ensure that the path contains an ending slash)
$file_count = 0;
$dir_handle = opendir($path);
if (!$dir_handle) return -1;
while ($file = readdir($dir_handle)) {
if ($file == '.' || $file == '..') continue;
if (is_dir($path . $file)){
$file_count += count_files($path . $file . DIRECTORY_SEPARATOR);
}
else {
$file_count++; // increase file count
}
}
closedir($dir_handle);
return $file_count;
}
Non-Recursive:
$directory = ".. path/";
if (glob($directory . "*.") != false)
{
$filecount = count(glob($directory . "*."));
echo $filecount;
}
else
{
echo 0;
}
Courtesy of Russell Dias
You can use the SPL DirectoryIterator to do this in a non-recursive (or with a recursive iterator in a recursive) fashion:
iterator_count(new DirectoryIterator($directory));
It's good to note that this will not just count regular files, but also directories, dot files and symbolic links. For regular files only, you can use:
$directory = new DirectoryIterator($directory);
$count = 0;
foreach($directory as $file ){ $count += ($file->isFile()) ? 1 : 0;}
PHP 5.4.0 also offers:
iterator_count(new CallbackFilterIterator($directory, function($current) { return $current->isFile(); }));
$dir = opendir('dir/');
$i = 0;
while (false !== ($file = readdir($dir))){
if (!in_array($file, array('.', '..' ))and (!is_dir($file)))
$i++;
}
echo "There were $i files";
<?php
function scan_dir($dirname) {
$file_count = 0 ;
$dir_count = 0 ;
$dir = opendir($dirname);
while (($file = readdir($dir)) !== false) {
if($file != "." && $file != "..") {
if(is_file($dirname."/".$file))
++$file_count;
if(is_dir($dirname."/".$file)) {
++ $dir_count;
scan_dir($dirname."/".$file);
}
}
}
closedir($dir);
echo "There are $dir_count catalogues and $file_count files.<br>";
}
$dirname = "/home/user/path";
scan_dir($dirname);
?>
Hello,
I have a recursive function for count files and catalogues. It returns result for each catalogue.
But I need a common result. How to change the script?
It returns :
There are 0 catalogues and 3 files.
There are 0 catalogues and 1 files.
There are 2 catalogues and 14 files.
I want:
There are 2 catalogues and 18 files.
You could tidy up the code a lot with RecursiveDirectoryIterator.
$dirs = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator(dirname(__FILE__))
, TRUE);
$dirsCount = $filesCount = 0;
while ($dirs->valid()) {
if ($dirs->isDot()) {
$dirs->next();
} else if ($dirs->isDir()) {
$dirsCount++;
} else if ($dirs->isFile()) {
$filesCount++;
}
$dirs->next();
}
var_dump($dirsCount, $filesCount);
You can return values from each recursive call, and sum those and return back to its caller.
<?php
function scan_dir($dirname) {
$file_count = 0 ;
$dir_count = 0 ;
$dir = opendir($dirname);
$sub_count = 0;
while (($file = readdir($dir)) !== false) {
if($file != "." && $file != "..") {
if(is_file($dirname."/".$file))
++$file_count;
if(is_dir($dirname."/".$file)) {
++ $dir_count;
$sub_count += scan_dir($dirname."/".$file);
}
}
}
closedir($dir);
echo "There are $dir_count catalogues and $file_count files.<br>";
return $sub_count + $dir_count + $file_count;
}
$dirname = "/home/user/path";
echo "Total count is ". scan_dir($dirname);
?>
The code will give you the net count of every item.
With a simple modification. Just, for example, keep the counts in an array that you can return from the function to add up to the previous counts, like so:
<?php
function scan_dir($dirname) {
$count['file'] = 0;
$count['dir'] = 0;
$dir = opendir($dirname);
while (($file = readdir($dir)) !== false) {
if($file != "." && $file != "..") {
if(is_file($dirname."/".$file))
$count['file']++;
if(is_dir($dirname."/".$file)) {
$count['dir']++;
$counts = scan_dir($dirname."/".$file);
$count['dir'] += $counts['dir'];
$count['file'] += $counts['file'];
}
}
}
closedir($dir);
return $count;
}
$dirname = "/home/user/path";
$count = scan_dir($dirname);
echo "There are $count[dir] catalogues and $count[file] files.<br>";
?>
In my opnion, you should separate counting file & counting dir to 2 different function. It will clear things up:
<?php
function scan_dir_for_file($dirname) {
$file_count = 0 ;
$dir = opendir($dirname);
while (($file = readdir($dir)) !== false) {
if($file != "." && $file != "..") {
if(is_file($dirname."/".$file))
{
++$file_count;
} else {
$file_count = $file_count + scan_dir($dirname."/".$file);
}
}
}
return $file_count
}
?>
The directory_count function is similar.