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'));
Related
In index.php I have arrays listing folders. Function.php has code that counts the size of the folder. The code works when I type the folder name manually. I don't know how to make the code in function.php count for all folders in index.php. In index.php I made a loop foreach ($nameFolders as $index => $value) {echo $nameFolders[$index];} but it does not work in function.php $disk_used = foldersize ($nameFolders[$index]);
index.php
$nameFolders = array("nameFolder1", "nameFolder2", "nameFolder3");
foreach ($nameFolders as $index => $value) {
echo $nameFolders[$index];
}
include 'function.php';
function.php
$units = explode(' ', 'B KB MB GB');
$disk_used = foldersize($nameFolders[$index]);
$totalSize = format_size($disk_used);
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];
}
There are several things wrong with your code, starting with the include order. If you include (and thus declare) the functions AFTER your loop, you cannot use them inside the loop; I understand that you are trying to print all the folders with their sizes.
index.php
<?php
include_once('function.php'); // this needs to happen before.
$name_folders = array('nameFolder1', 'nameFolder2', 'nameFolder3');
// no need for key => value here if you don't use that
foreach ($name_folders as $folder) {
$disk_used = folder_size($folder);
$totalSize = format_size($disk_used);
echo "$folder: $totalSize\n";
}
function.php
<?php
$units = explode(' ', 'B KB MB GB');
function folder_size($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 = folder_size($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];
}
Please note that this "include function.php" style of PHP is how we did it in 1999, and it's not really a modern practice. Same goes for the use of global there. Try sticking to ONE naming convention: you mix camelCase with snake_case.
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 am working on a PHP function that will scan a given folder and return the total size of all the files in the folder. My issue is that, even though it works for files stored in the root of that folder, it doesn't work for files in any subfolder. My code is:
function get_total_size($system)
{
$size = 0;
$path = scandir($system);
unset($path[0], $path[1]);
foreach($path as $file)
{
if(is_dir($file))
{
get_total_size("{$system}/{$file}");
}
else
{
$size = $size + filesize("{$system}/{$file}");
}
}
$size = $size / 1024;
return number_format($size, 2, ".", ",");
}
I'm unsetting the 0th and 1st elements of the array since these are the dot and the double dot to go up a directory. Any help would be greatly appreciated
You may try this procedure. When you check this file is_dir then you have to count the file size also. And when you check is_dir you have to concat it with root directory otherwise it show an error.
function get_total_size($system)
{
$size = 0;
$path = scandir($system);
unset($path[0], $path[1]);
foreach($path as $file)
{
if(is_dir($system.'/'.$file))
{
$size+=get_total_size("{$system}/{$file}");
}
else
{
$size = $size + filesize("{$system}/{$file}");
}
}
$size = $size / 1024;
return number_format($size, 2, ".", ",");
}
I think it will work fine
Happy coding :)
You forgot to count the size of the subfolders. you have to add it to the $size variable.
function get_total_size($system)
{
$size = 0;
$path = scandir($system);
unset($path[0], $path[1]);
foreach($path as $file)
{
if(is_dir($file))
{
$size += get_total_size("{$system}/{$file}"); // <--- HERE
}
else
{
$size = $size + filesize("{$system}/{$file}");
}
}
return $size;
}
This might however give a problem because you are using the number_format function. I would not do this and add the formatting after receiving the result of the get_total_size function.
you can use recursive directory iterator for the same. Have a look on below solution:
<?php
$total_size = 0;
$di = new RecursiveDirectoryIterator('/directory/path');
foreach (new RecursiveIteratorIterator($di) as $filename => $file) {
if($file->isFile()) {
echo $filename . ' - ' . $file->getSize() . ' bytes <br/>';
$total_size += $file->getSize();
}
}
echo $total_size; //in bytes
?>
The recursiveIterator family of classes could be of use to you.
function filesize_callback( $obj, &$total ){
foreach( $obj as $file => $info ){
if( $obj->isFile() ) {
echo 'path: '.$obj->getPath().' filename: '.$obj->getFilename().' filesize: '.filesize( $info->getPathName() ).BR;
$total+=filesize( $info->getPathName() );
} else filesize_callback( $info,&$total );
}
}
$total=0;
$folder='C:\temp';
$iterator=new RecursiveIteratorIterator( new RecursiveDirectoryIterator( $folder, RecursiveDirectoryIterator::KEY_AS_PATHNAME ), RecursiveIteratorIterator::CHILD_FIRST );
call_user_func( 'filesize_callback', $iterator, &$total );
echo BR.'Grand-Total: '.$total.BR;
I'm trying to make scandir(); function go beyond its written limits, I need more than the alpha sorting it currently supports. I need to sort the scandir(); results to be sorted by modification date.
I've tried a few solutions I found here and some other solutions from different websites, but none worked for me, so I think it's reasonable for me to post here.
What I've tried so far is this:
function scan_dir($dir)
{
$files_array = scandir($dir);
$img_array = array();
$img_dsort = array();
$final_array = array();
foreach($files_array as $file)
{
if(($file != ".") && ($file != "..") && ($file != ".svn") && ($file != ".htaccess"))
{
$img_array[] = $file;
$img_dsort[] = filemtime($dir . '/' . $file);
}
}
$merge_arrays = array_combine($img_dsort, $img_array);
krsort($merge_arrays);
foreach($merge_arrays as $key => $value)
{
$final_array[] = $value;
}
return (is_array($final_array)) ? $final_array : false;
}
But, this doesn't seem to work for me, it returns 3 results only, but it should return 16 results, because there are 16 images in the folder.
function scan_dir($dir) {
$ignored = array('.', '..', '.svn', '.htaccess');
$files = array();
foreach (scandir($dir) as $file) {
if (in_array($file, $ignored)) continue;
$files[$file] = filemtime($dir . '/' . $file);
}
arsort($files);
$files = array_keys($files);
return ($files) ? $files : false;
}
This is a great question and Ryon Sherman’s answer provides a solid answer, but I needed a bit more flexibility for my needs so I created this newer function: better_scandir.
The goal is to allow having scandir sorting order flags work as expected; not just the reverse array sort method in Ryon’s answer. And also explicitly setting SORT_NUMERIC for the array sort since those time values are clearly numbers.
Usage is like this; just switch out SCANDIR_SORT_DESCENDING to SCANDIR_SORT_ASCENDING or even leave it empty for default:
better_scandir(<filepath goes here>, SCANDIR_SORT_DESCENDING);
And here is the function itself:
function better_scandir($dir, $sorting_order = SCANDIR_SORT_ASCENDING) {
/****************************************************************************/
// Roll through the scandir values.
$files = array();
foreach (scandir($dir, $sorting_order) as $file) {
if ($file[0] === '.') {
continue;
}
$files[$file] = filemtime($dir . '/' . $file);
} // foreach
/****************************************************************************/
// Sort the files array.
if ($sorting_order == SCANDIR_SORT_ASCENDING) {
asort($files, SORT_NUMERIC);
}
else {
arsort($files, SORT_NUMERIC);
}
/****************************************************************************/
// Set the final return value.
$ret = array_keys($files);
/****************************************************************************/
// Return the final value.
return ($ret) ? $ret : false;
} // better_scandir
Alternative example..
$dir = "/home/novayear/public_html/backups";
chdir($dir);
array_multisort(array_map('filemtime', ($files = glob("*.{sql,php,7z}", GLOB_BRACE))), SORT_DESC, $files);
foreach($files as $filename)
{
echo "<a>".substr($filename, 0, -4)."</a><br>";
}
Another scandir keep latest 5 files:
public function checkmaxfiles()
{
$dir = APPLICATION_PATH . '\\modules\\yourmodulename\\public\\backup\\';
// '../notes/';
$ignored = array('.', '..', '.svn', '.htaccess');
$files = array();
foreach (scandir($dir) as $file) {
if (in_array($file, $ignored)) continue;
$files[$file] = filemtime($dir . '/' . $file);
}
arsort($files);
$files = array_keys($files);
$length = count($files);
if($length < 4 ){
return;
}
for ($i = $length; $i > 4; $i--) {
echo "Erase : " .$dir.$files[$i];
unlink($dir.$files[$i]);
}
}
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;
}