i need help with disk_total_space function..
i have this on my code
<?php
$sql="select * from users order by id";
$result=mysql_query($sql);
while($row=mysql_fetch_array($result)) {
?>
Name : <?php echo $row['name']; ?>
Email : <?php echo $row['email']; ?>
Diskspace Available : <?php
$dir = "C:/xampp/htdocs/freehosting/".$row['name'];
disk_total_space($dir);
} ?>
However this return me same disk space for every users ..
Anyone can shed me some light?
thanks :)
http://us2.php.net/disk_total_space says,
"Given a string containing a directory, this function will return the total number of bytes on the corresponding filesystem or disk partition."
You're likely seeing the total_space of C:
Alternative solutions do exist for both Windows and Linux.
I think what you want is something like this:
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>';
}
edit: the recursive function had a bug in it originally. Now it should also read folders inside the original folders, and folders inside those folders, and so on.
The comments on the function on PHP.net appear to indicate that this gives the space of the drive/partition $dir is in, not the size of $dir itself.
I think that method will only tell you information about the filesystem or partition the given directory is on. You could try simply shelling out to du though:
$space_used=`du -sh $dir`;
-s summarizes the entire dir, -h returns the result in "human" units like MB and GB.
Edit: apologies, I missed that this was on WIndows. WIll leave the answer in case it helps someone searching for a similar problem. For windows, try this suggestion in the PHP manual
According to the docs for disk_total_space(), the value returned is for the filesystem the directory is located on. It doesn't count the space used in a directory + its subdirectories.
You could shell out to du or for a more portable solution:
$total = 0;
foreach (new RecursiveDirectoryIterator($dir) as $entry)
{
if ($entry->isFile())
$total += $entry->getSize();
}
You could use the function:
function size_directory($ruta)
{
$gestor = opendir($ruta);
$total = 0;
while (($archivo = readdir($gestor)) !== false) {
$ruta_completa = $ruta . "/" . $archivo;
if ($archivo != "." && $archivo != "..") {
$total += filesize($ruta_completa);
}
}
return round($total / 1024, 0);
}
Related
I have a directory with subdirectories in it, I am trying to loop over all of them and also loop on the filenames to count how many time there is a string inside it.
inside of a subdirectory: (i get this output)
../convo/96376/96376-200-2019-03-28-16-15-49.wav
../convo/96376/96376-200-2019-04-01-11-46-52.wav
../convo/96376/96376-200-2019-04-01-11-47-27.wav
../convo/96376/96376-263-2020-01-06-09-40-24.wav
../convo/96376/96376-263-2020-01-06-10-08-16.wav
Here I need to count how many files have (200) or (263) to make a report.
I already isolated the number i need and stored it in a variable ($poste). I just don't know how I am supposed to make a count here since i have nothing to compare. Here is what i got so far
200 and 263 are not hardcoded (I will never know the numbers in advance) and there could be alot more to count
$directory = '../convo/';
$count = 0;
$subDirectories = scandir($directory);
unset($subDirectories[0]);
unset($subDirectories[1]);
foreach ($subDirectories as $subDirectory) {
echo '<h2>' . $subDirectory . '</h2>';
foreach (glob($directory . $subDirectory . '/*') as $file) {
$poste_explode = explode('-', $file);
$poste = $poste_explode[1];
}
}
if you just need the count for 200 & 263, try this:
$directory = '../convo/';
$count = 0;
$subDirectories = scandir($directory);
unset($subDirectories[0]);
unset($subDirectories[1]);
foreach ($subDirectories as $subDirectory) {
echo '<h2>' . $subDirectory . '</h2>';
foreach (glob($directory . $subDirectory . '/*') as $file) {
$poste_explode = explode('-', $file);
$poste = $poste_explode[1];
if (in_array($poste,["200","263"])) {
$count++;
}
}
}
Just add a test for the values and put a counter here:
$posteCounter = 0;
foreach (glob($directory . $subDirectory . '/*') as $file) {
$poste_explode = explode('-', $file);
$poste = $poste_explode[1];
if(200 == $poste || 263 == $poste) {
$posteCounter++;
}
Or you could count each one so that you have separate values which can be totaled:
//set variables outside the loop to hold the values
$_200 = 0;
$_263 = 0;
if(200 == $poste) {
$_200++;
} elseif (263 == $poste) {
$_263++;
}
EDIT Based on comments provided by the OP:
In order to find all of the poste values and then count you will have to loop twice through your directory. The first loop will build an array:
foreach(glob($directory . $subDirectory . '/*') as $file) {
$poste_explode = explode('-', $file);
$postes[] = $poste_explode[1]; // create and populate $postes array
}
Now you can loop through the $postes array and count files with those values, setting up a variable variable (there are likely better ways, but a lack of coffee isn't bringing them to mind) for each of the poste numbers. Here is an EXAMPLE of an experiment in progress
$filenames = ['a-2-foo', 'b-2-bar', 'c-3-glorp'];
foreach($filenames as $filename){
$poste_explode = explode('-', $filename);
$postes[] = $poste_explode[1];
if(!isset(${'poste_' . $poste_explode[1]})){
${'poste_' . $poste_explode[1]} = 0; // set up variable variable
}
}
var_dump( get_defined_vars() );
print_r($postes);
foreach($postes as $poste){
echo $poste . "\n";
foreach($filenames as $filename){
$poste_explode = explode('-', $filename);
if($poste == $poste_explode[1]){
echo ${'poste_' . $poste} . "\n";
${'poste_' . $poste}++; // variable variable
}
}
}
I've looked at similar posts here but couldn't crack a solution. I'm getting the Strict Standards: Only variables should be passed by reference error here on the strtolower($file['name']))), line. Tried hours now looking for a solution but couldn't figure out how to correct. Can you highlight where I've gone wrong?
Note: Code Edited as per #Kolink's suggestion below:
<?php
require_once 'upload_config.php';
$mydirectory = myUploadDir();
$uploaded_file_counter = 0;
$UploadLimit = $_POST['counter'];
for ($i = 0; $i <= $UploadLimit; $i++) {
$file_tag = 'filename' . $i;
$filename = $_FILES[$file_tag]['name'];
if ($filename != null) {
$rand = time();
$str = "$rand$filename";
// set folder name in here.
$filedir = myUploadDir();
//change the string format.
$string = $filedir . $str;
$patterns[0] = "/ /";
$patterns[1] = "/ /";
$patterns[1] = "/ /";
$replacements[1] = "_";
$dirname = strtolower(preg_replace($patterns, $replacements, $string));
//end of changing string format
//checking the permitted file types
if ($check_file_extentions) {
$allowedExtensions = allowedfiles();
foreach ($_FILES as $file) {
if ($file['tmp_name'] > '') {
/*if (!in_array(end(explode(".", strtolower($file['name']))), $allowedExtensions)) */
if (!in_array(array_reverse(explode(".", strtolower($file['name'])))[0], $allowedExtensions)) {
$fileUploadPermission = 0;
} else {
$fileUploadPermission = 1;
}
}
}
} else {
$fileUploadPermission = 1;
}
//end of checking the permitted file types
if ($fileUploadPermission) {
if (move_uploaded_file($_FILES[$file_tag]['tmp_name'], $dirname)) {
echo "<p>"; ?>
<div><?php echo "<img style='height:100px;width:200px' src='$dirname'>"; ?></div> <?php
echo "</p>";
$uploaded_file_counter += 1;
}
}
}
}
if ($uploaded_file_counter == 0) {
echo "<br /> <b style='font-weight:bold;color:red'>Opss! Please select an image file<b>";
} else {
echo "<br /> <b>You request " . $i . " image files to upload and " . $uploaded_file_counter . " files uploaded sucessfully</b>";
}
?>
end takes its argument by reference, since it modifies the original array by moving its internal pointer.
Since you appear to be using PHP 5.4, you can do this instead to get the last one:
if( !in_array(array_reverse(explode(".",strtolower($file['name'])))[0],$allowedExtensions))
That said, it's probably better to do it in several steps for readability:
$parts = explode(".",strtolower($file['name']));
$extension = $parts[count($parts)-1];
if( !in_array($extension,$allowedExtensions)) {
I am trying to create an option of uploading an avatar to my site. What I am trying to achieve is this :
first avatar : 1.jpg
second avatar : 2.jpg
third avatar : 3.png
and so on..
How can I create an upload counter in php? My current code is this :
if(!empty($_FILES['cover']['tmp_name']))
{
$uploadfolder = "avatar/";
$file1 = rands().'.'.end(explode('.',$_FILES['cover']['name']));
$cover = $uploadfolder.$file1;
move_uploaded_file($_FILES['cover']['tmp_name'],$cover);
}
else
{
$cover = ''
}
The function rands() does not do anything, so please use it to demonstrate how I can achieve my goal.
If you store your users in database and there is integer user ID, you better use this user ID for file naming rather than separate incrementing counter.
Also you can look at existing files to find maximum existing number like this:
function getNextFileName ()
{
$a = 0;
$b = 2147483647;
while ($a < $b)
{
$c = floor (($a + $b) / 2);
if (file_exists ("$c.jpg")) $a = $c + 1;
else $b = $c;
}
return "$a.jpg";
}
function saveAvatar ($avatar)
{
for ($i = 0; $i < 16; $i++)
{
$name = getNextFileName ();
$fd = fopen ($name, 'x');
if ($fd !== FALSE)
{
fwrite ($fd, $avatar);
fclose ($fd);
return $name;
}
}
return FALSE;
}
for ($i = 0; $i < 20; $i++)
saveAvatar ("BlahBlahBlah$i");
It seem you have problem in genetaing random numbers you can try this:
$prefix = substr(str_shuffle("0123456789"), 0,3);
$file1 = $prefix.'.'.end(explode('.',$_FILES['cover']['name']));
the above $prefix will be like : any random 3 digits
Hope will help it!
/*
* currentDir - path - eg. c:/xampp/htdocs/movies/uploads (no end slash)
* $dir - points current working directory.
* $filename - name of the file.
*/
public static function getFileName($dir, $filename) {
$filePath = $dir . "/uploads/" . $filename;
$fileInfo = pathinfo($filePath);
$i = 1;
while(file_exists($filePath)) {
$filePath = $dir . "/uploads/" . $fileInfo['filename'] . "_" . $i . "." . $fileInfo['extension'];
$i++;
}
return $filePath;
}
move_uploaded_file($_FILES['cover']['tmp_name'],$filePath);
if same filename existing in your uploads folder. it will auto generate the
avatar_1.jpg,
avatar_2.jpg,
avatar_3.jpg, ans so on ..
If (and this is a big IF) your server supports file locking, you can reasonably ensure you have a unique incrementing ID with:
function get_avatar_id()
{
$lockfile = fopen("avatar_id_lock_file","a");
if(flock($lockfile, LOCK_EX)) // Get an exclusive lock to avoid race conditions
{
$avatar_id = intval(file_get_contents("avatar_id"); // Assumes you made it and put a number in it
$avatar_id++;
file_put_contents("avatar_id", $avatar_id);
flock($lockfile, LOCK_UN);
fclose($lockfile);
return $avatar_id;
}
else
{
//What do you want to do if you can't lock the file?
}
}
create an XML file and store the count in there
<? xml version="1.0" ?>
<MyRootNode>
<count>123</count>
</MyRootNode>
UPDATE
Update added after you added more code to your question.
Function Rands(FileExtension as string) as long
'1 open xml file
'2 read counter in
'3 increment counter
'4 save value to back xml file
'5 return incremented counter with the file extension passed attached on the end
'This is in case a BMP GIF or PNG has been and not JPG
' SAMPLE filename 123.GIF
End Function
I'm working on a slightly new project. I wanted to know how many files are in a certain directory.
<div id="header">
<?php
$dir = opendir('uploads/'); # This is the directory it will count from
$i = 0; # Integer starts at 0 before counting
# While false is not equal to the filedirectory
while (false !== ($file = readdir($dir))) {
if (!in_array($file, array('.', '..') and !is_dir($file)) $i++;
}
echo "There were $i files"; # Prints out how many were in the directory
?>
</div>
This is what I have so far (from searching). However, it is not appearing properly? I have added a few notes so feel free to remove them, they are just so I can understand it as best as I can.
If you require some more information or feel as if I haven't described this enough please feel free to state so.
You can simply do the following :
$fi = new FilesystemIterator(__DIR__, FilesystemIterator::SKIP_DOTS);
printf("There were %d Files", iterator_count($fi));
You can get the filecount like so:
$directory = "/path/to/dir/";
$filecount = count(glob($directory . "*"));
echo "There were $filecount files";
where the "*" is you can change that to a specific filetype if you want like "*.jpg" or you could do multiple filetypes like this:
glob($directory . "*.{jpg,png,gif}",GLOB_BRACE)
the GLOB_BRACE flag expands {a,b,c} to match 'a', 'b', or 'c'
Note that glob() skips Linux hidden files, or all files whose names are starting from a dot, i.e. .htaccess.
Try this.
// Directory
$directory = "/dir";
// Returns an array of files
$files = scandir($directory);
// Count the number of files and store them inside the variable..
// Removing 2 because we do not count '.' and '..'.
$num_files = count($files)-2;
You should have :
<div id="header">
<?php
// integer starts at 0 before counting
$i = 0;
$dir = 'uploads/';
if ($handle = opendir($dir)) {
while (($file = readdir($handle)) !== false){
if (!in_array($file, array('.', '..')) && !is_dir($dir.$file))
$i++;
}
}
// prints out how many were in the directory
echo "There were $i files";
?>
</div>
The best answer in my opinion:
$num = count(glob("/exact/path/to/files/" . "*"));
echo $num;
It doesnt counts . and ..
Its a one liner
Im proud of it
Since I needed this too, I was curious as to which alternative was the fastest.
I found that -- if all you want is a file count -- Baba's solution is a lot faster than the others. I was quite surprised.
Try it out for yourself:
<?php
define('MYDIR', '...');
foreach (array(1, 2, 3) as $i)
{
$t = microtime(true);
$count = run($i);
echo "$i: $count (".(microtime(true) - $t)." s)\n";
}
function run ($n)
{
$func = "countFiles$n";
$x = 0;
for ($f = 0; $f < 5000; $f++)
$x = $func();
return $x;
}
function countFiles1 ()
{
$dir = opendir(MYDIR);
$c = 0;
while (($file = readdir($dir)) !== false)
if (!in_array($file, array('.', '..')))
$c++;
closedir($dir);
return $c;
}
function countFiles2 ()
{
chdir(MYDIR);
return count(glob("*"));
}
function countFiles3 () // Fastest method
{
$f = new FilesystemIterator(MYDIR, FilesystemIterator::SKIP_DOTS);
return iterator_count($f);
}
?>
Test run: (obviously, glob() doesn't count dot-files)
1: 99 (0.4815571308136 s)
2: 98 (0.96104407310486 s)
3: 99 (0.26513481140137 s)
Working Demo
<?php
$directory = "../images/team/harry/"; // dir location
if (glob($directory . "*.*") != false)
{
$filecount = count(glob($directory . "*.*"));
echo $filecount;
}
else
{
echo 0;
}
?>
I use this:
count(glob("yourdir/*",GLOB_BRACE))
<?php echo(count(array_slice(scandir($directory),2))); ?>
array_slice works similary like substr function, only it works with arrays.
For example, this would chop out first two array keys from array:
$key_zero_one = array_slice($someArray, 0, 2);
And if You ommit the first parameter, like in first example, array will not contain first two key/value pairs *('.' and '..').
Based on the accepted answer, here is a way to count all files in a directory RECURSIVELY:
iterator_count(
new \RecursiveIteratorIterator(
new \RecursiveDirectoryIterator('/your/directory/here/', \FilesystemIterator::SKIP_DOTS)
)
)
$it = new filesystemiterator(dirname("Enter directory here"));
printf("There were %d Files", iterator_count($it));
echo("<br/>");
foreach ($it as $fileinfo) {
echo $fileinfo->getFilename() . "<br/>\n";
}
This should work
enter the directory in dirname. and let the magic happen.
Maybe usefull to someone. On a Windows system, you can let Windows do the job by calling the dir-command. I use an absolute path, like E:/mydir/mysubdir.
<?php
$mydir='E:/mydir/mysubdir';
$dir=str_replace('/','\\',$mydir);
$total = exec('dir '.$dir.' /b/a-d | find /v /c "::"');
$files = glob('uploads/*');
$count = 0;
$totalCount = 0;
$subFileCount = 0;
foreach ($files as $file)
{
global $count, $totalCount;
if(is_dir($file))
{
$totalCount += getFileCount($file);
}
if(is_file($file))
{
$count++;
}
}
function getFileCount($dir)
{
global $subFileCount;
if(is_dir($dir))
{
$subfiles = glob($dir.'/*');
if(count($subfiles))
{
foreach ($subfiles as $file)
{
getFileCount($file);
}
}
}
if(is_file($dir))
{
$subFileCount++;
}
return $subFileCount;
}
$totalFilesCount = $count + $totalCount;
echo 'Total Files Count ' . $totalFilesCount;
Here's a PHP Linux function that's considerably fast. A bit dirty, but it gets the job done!
$dir - path to directory
$type - f, d or false (by default)
f - returns only files count
d - returns only folders count
false - returns total files and folders count
function folderfiles($dir, $type=false) {
$f = escapeshellarg($dir);
if($type == 'f') {
$io = popen ( '/usr/bin/find ' . $f . ' -type f | wc -l', 'r' );
} elseif($type == 'd') {
$io = popen ( '/usr/bin/find ' . $f . ' -type d | wc -l', 'r' );
} else {
$io = popen ( '/usr/bin/find ' . $f . ' | wc -l', 'r' );
}
$size = fgets ( $io, 4096);
pclose ( $io );
return $size;
}
You can tweak to fit your needs.
Please note that this will not work on Windows.
simple code add for file .php then your folder which number of file to count its
$directory = "images/icons";
$files = scandir($directory);
for($i = 0 ; $i < count($files) ; $i++){
if($files[$i] !='.' && $files[$i] !='..')
{ echo $files[$i]; echo "<br>";
$file_new[] = $files[$i];
}
}
echo $num_files = count($file_new);
simple add its done ....
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
Any idea why the processor usage shoot up too high or 100% till the script execution is finish ? Can anything be done to optimize it? or is there any other alternative way to check folder and folders inside it 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;
}
The same idea as Janith Chinthana suggested.
With a few fixes:
Converts $path to realpath
Performs iteration only if path is valid and folder exists
Skips . and .. files
Optimized for performance
The following are other solutions offered elsewhere:
If on a Windows Host:
<?
$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, if on a Linux Host:
<?
$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;
?>
directory size using php filesize and RecursiveIteratorIterator.
This works with any platform which is having php 5 or higher version.
/**
* Get the directory size
* #param string $directory
* #return integer
*/
function dirSize($directory) {
$size = 0;
foreach(new RecursiveIteratorIterator(new RecursiveDirectoryIterator($directory)) as $file){
$size+=$file->getSize();
}
return $size;
}
A pure php example.
<?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];
}
?>
function get_dir_size($directory){
$size = 0;
$files = glob($directory.'/*');
foreach($files as $path){
is_file($path) && $size += filesize($path);
is_dir($path) && $size += get_dir_size($path);
}
return $size;
}
Thanks to Jonathan Sampson, Adam Pierce and Janith Chinthana I did this one checking for most performant way to get the directory size. Should work on Windows and Linux Hosts.
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);
}
}
Even though there are already many many answers to this post, I feel I have to add another option for unix hosts that only returns the sum of all file sizes in the directory (recursively).
If you look at Jonathan's answer he uses the du command. This command will return the total directory size but the pure PHP solutions posted by others here will return the sum of all file sizes. Big difference!
What to look out for
When running du on a newly created directory, it may return 4K instead of 0. This may even get more confusing after having deleted files from the directory in question, having du reporting a total directory size that does not correspond to the sum of the sizes of the files within it. Why? The command du returns a report based on some file settings, as Hermann Ingjaldsson commented on this post.
The solution
To form a solution that behaves like some of the PHP-only scripts posted here, you can use ls command and pipe it to awk like this:
ls -ltrR /path/to/dir |awk '{print \$5}'|awk 'BEGIN{sum=0} {sum=sum+\$1} END {print sum}'
As a PHP function you could use something like this:
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;
}
I found this approach to be shorter and more compatible. The Mac OS X version of "du" doesn't support the -b (or --bytes) option for some reason, so this sticks to the more-compatible -k option.
$file_directory = './directory/path';
$output = exec('du -sk ' . $file_directory);
$filesize = trim(str_replace($file_directory, '', $output)) * 1024;
Returns the $filesize in bytes.
Johnathan Sampson's Linux example didn't work so good for me. Here's an improved version:
function getDirSize($path)
{
$io = popen('/usr/bin/du -sb '.$path, 'r');
$size = intval(fgets($io,80));
pclose($io);
return $size;
}
It works perfectly fine .
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;
}
There are several things you could do to optimise the script - but maximum success would make it IO-bound rather than CPU-bound:
Calculate rtrim($path, '/') outside the loop.
make if ($t<>"." && $t<>"..") the outer test - it doesn't need to stat the path
Calculate rtrim($path, '/') . '/' . $t once per loop - inside 2) and taking 1) into account.
Calculate explode(' ','B KB MB GB TB PB'); once rather than each call?
PHP get directory size (with FTP access)
After hard work, this code works great!!!! and I want to share with the community (by 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);
Good code!
Fernando
Object Oriented Approach :
/**
* 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;
}
Fast and Furious Approach :
function dir_size2($dir)
{
$line = exec('du -sh ' . $dir);
$line = trim(str_replace($dir, '', $line));
return $line;
}
Code adjusted to access main directory and all sub folders within it. This would return the full directory size.
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;
}
if you are hosted on Linux:
passthru('du -h -s ' . $DIRECTORY_PATH)
It's better than foreach
Regarding Johnathan Sampson's Linux example, watch out when you are doing an intval on the outcome of the "du" function, if the size is >2GB, it will keep showing 2GB.
Replace:
$totalSize = intval(fgets($io, 80));
by:
strtok(fgets($io, 80), " ");
supposed your "du" function returns the size separated with space followed by the directory/file name.
Just another function using native php functions.
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;
}
NOTE: this function returns the files sizes, NOT the size on disk
Evolved from Nate Haugs answer I created a short function for my project:
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);
}
A one-liner solution. Result in bytes.
$size=array_sum(array_map('filesize', glob("{$dir}/*.*")));
Added bonus: you can simply change the file mask to whatever you like, and count only certain files (eg by extension).
This is the simplest possible algorithm to find out directory size irrespective of the programming language you are using.
For PHP specific implementation. go to: Calculate Directory Size in PHP | Explained with Algorithm | Working Code