Glob no longer working with Nginx - php

Edit
There is nothing wrong with my code so feel free to use it as it is, if ever you need to search your file system from within PHP then echo the results.
I created a class to search through files using glob. It worked perfectly but now that I have migrated from Apache to Nginx, it always returns 0 results.
Here is my code:
public static function search($path, $find, $caseSensitive = false)
{
if ($path[strlen($path) - 1] !== '/')
$path .= '/';
$path = '../'.$path;
$pathLen = strlen($path);
$path .= '*';
if ($caseSensitive)
$files = self::globRecursive($path.$find);
else
{
$findLen = strlen($find);
for ($i = 0; $i < $findLen; $i++)
$find1 .= '['.strtolower($find[$i]).strtoupper($find[$i]).']';
$files = self::globRecursive($path.$find1);
}
$message = '';
$count = count($files);
if ($count === 0)
return '"'.$find.'" not found.';
foreach ($files as $file)
$message .= substr($file, $pathLen).'<br />';
return '"'.$find.'" found in '.$count.' files:<br />'.$message;
}
private static function globRecursive($pattern, $flags = 0)
{
$files = glob($pattern, $flags);
foreach (glob(dirname($pattern).'/*', GLOB_ONLYDIR|GLOB_NOSORT) as $dir)
$files = array_merge($files, self::globRecursive($dir.'/'.basename($pattern), $flags));
return $files;
}

The problem was due to changing my root directy. Simply prepending ../ to my search query fixed the problem.

Related

Problem with getting file URLs of folders inside multiple directories

Here is my code to get a list of the file URLs inside a specific directory:
PHP
<?php
function getDirContents($directories, &$results = array()){
$files = array_diff(scandir($directories), array('..', '.'));;
foreach($files as $key => $value){
$path = $directories.DIRECTORY_SEPARATOR.$value;
if(is_dir($path)) {
getDirContents($path, $results);
} else {
$directory_path = basename($_SERVER['REQUEST_URI']);
$results[] = 'https://' . $_SERVER['SERVER_NAME'] . str_replace($directory_path, "", $_SERVER['REQUEST_URI']) .$path;
}
}
return $results;
}
$directories = "directory_A";
echo json_encode(getDirContents($directories));
The result for directory_A:
https://example.com/directory_A/voice1.mp3
https://example.com/directory_A/Media/inside_media_1/voice2.mp3
https://example.com/directory_A/Media/inside_media_1/voice3.mp3
What if we want to get URLs from multiple directories?
I tried to loop through those directories using a for loop like this:
<?php
function getDirContents($directories, &$results = array()){
$length = count($directories);
for ($i = 0; $i < $length; $i++) {
$files = array_diff(scandir($directories[$i]), array('..', '.'));;
foreach($files as $key => $value){
$path = $directories[$i].DIRECTORY_SEPARATOR.$value;
if(is_dir($path)) {
getDirContents($path, $results);
} else {
$directory_path = basename($_SERVER['REQUEST_URI']);
$results[] = 'https://' . $_SERVER['SERVER_NAME'] . str_replace($directory_path, "", $_SERVER['REQUEST_URI']) .$path;
}
}
}
return $results;
}
$directories = array("directory_A", "directory_B");
echo json_encode(getDirContents($directories));
But I only get the files inside those directories and code dosn't go to the folders inside each directory so I only get this for directory_A:
https://example.com/directory_A/voice1.mp3
What I'm missing and how to fix this?
You are passing an array and a string to the function. You have two options. You can always send in an array, or you can look for a string and convert it to an array.
class GoDir
{
/**
* Execute the console command.
*
* #return mixed
*/
public function handle()
{
$directories = array("storage", "config");
echo json_encode($this->getDirContents($directories));
}
public function getDirContents($directories, &$results = array())
{
// See if we got a string and convert to array
if ( is_string($directories) ) {
$directories = [$directories];
}
$length = count($directories);
for ($i = 0; $i < $length; $i++) {
$files = array_diff(scandir($directories[$i]), array('..', '.'));;
foreach($files as $key => $value){
$path = $directories[$i].DIRECTORY_SEPARATOR.$value;
if(is_dir($path)) {
$this->getDirContents($path, $results);
} else {
$directory_path = '/';
$results[] = $directory_path . $path;
}
}
}
return $results;
}
// Here is an alternative solution:
public function getDirContents($directories, &$results = array())
{
$length = count($directories);
for ($i = 0; $i < $length; $i++) {
$files = array_diff(scandir($directories[$i]), array('..', '.'));;
foreach($files as $key => $value){
$path = $directories[$i].DIRECTORY_SEPARATOR.$value;
if(is_dir($path)) {
// Turn the param into an array
$this->getDirContents([$path], $results);
} else {
$directory_path = '/';
$results[] = $directory_path . $path;
}
}
}
return $results;
}
}

Retreiving files based on a particular pattern

I am using this function to retreive files from directory and sub-directories.
How can I display only files with _lang.php within this directory and sub-directories?
function getDirContents($dir, &$results = array()){
$files = scandir($dir);
foreach($files as $key => $value){
$path = realpath($dir.DIRECTORY_SEPARATOR.$value);
if(!is_dir($path)) {
$results[] = $path;
} else if($value != "." && $value != "..") {
getDirContents($path, $results);
$results[] = $path;
}
}
return $results;
}
$dir = './test/';
var_dump(getDirContents($dir));
answered a question like this earlier, try using Iterator Classes
<?php
function getDirContents($directory, $pattern)
{
$result = array();
$objRecursiveDirectoryIterator = new RecursiveDirectoryIterator($directory, RecursiveDirectoryIterator::SKIP_DOTS);
$objRecursiveIteratorIterator = new RecursiveIteratorIterator($objRecursiveDirectoryIterator);
// use RegexIterator() to grab only files that match $pattern
$objRegexIterator = new RegexIterator($objRecursiveIteratorIterator, $pattern, RecursiveRegexIterator::GET_MATCH);
// iterate through all the results
foreach ($objRegexIterator as $arrMatches) {
$result[] = $arrMatches[0];
}
return $result;
}
$dir = './test/';
$arrDirContents = getDirContents($dir, "~^.+_lang\.php$~i");
var_dump($arrDirContents);

PHP FTP recursive directory listing

I'm trying to make a recursive function to get all the directories and sub directories from my ftp server in an array.
I tried a lot of functions I've found on the web. The one that works best for me is this one:
public function getAllSubDirFiles() {
$dir = array(".");
$a = count($dir);
$i = 0;
$depth = 20;
$b = 0;
while (($a != $b) && ($i < $depth)) {
$i++;
$a = count($dir);
foreach ($dir as $d) {
$ftp_dir = $d . "/";
$newdir = ftp_nlist($this->connectionId, $ftp_dir);
foreach ($newdir as $key => $x) {
if ((strpos($x, ".")) || (strpos($x, ".") === 0)) {
unset($newdir[$key]);
} elseif (!in_array($x, $dir)) {
$dir[] = $x;
}
}
}
$b = count($dir);
}
return $dir ;
}
The problem with this function is it wont allow the directory to have a "." in it's name and every file that is located in the root directory will be considered a directory as well. So I adjusted the function and got this:
public function getAllSubDirFiles($ip, $id, $pw) {
$dir = array(".");
$a = count($dir);
$i = 0;
$depth = 20;
$b =0;
while (($a != $b) && ($i < $depth)) {
$i++;
$a = count($dir);
foreach ($dir as $d) {
$ftp_dir = $d . "/";
$newdir = ftp_nlist($this->connectionId, $ftp_dir);
foreach ($newdir as $key => $x) {
if (!is_dir('ftp://'.$id.':'.$pw.'#'.$ip.'/'.$x)) {
unset($newdir[$key]);
} elseif (!in_array($x, $dir)) {
$dir[] = $x;
}
}
}
$b = count($dir);
}
return $dir ;
}
This works pretty good but and gives the result I want. but it's so slow it's unusable.
I also tried working with ftp_rawlist but it has the same drawback of being horribly slow.
public function getAllSubDirFiles() {
$dir = array(".");
$a = count($dir);
$i = 0;
$depth = 20;
$b = 0;
while (($a != $b) && ($i < $depth)) {
$i++;
$a = count($dir);
foreach ($dir as $d) {
$ftp_dir = $d . "/";
$newdir = $this->getFtp_rawlist('/' . $ftp_dir);
foreach ($newdir as $key => $x) {
$firstChar = substr($newdir[$key][0], 0, 1);
$a = 8;
while ($a < count($newdir[$key])) {
if ($a == 8) {
$fileName = $ftp_dir . '/' . $newdir[$key][$a];
} else {
$fileName = $fileName . ' ' . $newdir[$key][$a];
}
$a++;
}
if ($firstChar != 'd') {
unset($newdir[$key]);
} elseif (!in_array($fileName, $dir)) {
$dir[] = $fileName;
}
}
}
$b = count($dir);
}
return $dir;
}
public function getFtp_rawlist($dir) {
$newArr = array();
$arr = ftp_rawlist($this->connectionId, $dir);
foreach ($arr as $value) {
$stringArr = explode(" ", $value);
$newArr[] = array_values(array_filter($stringArr));
}
return $newArr;
}
I've been stuck on this problem for the last couple of days and I'am getting desperate. If any one has any suggestion please let me know
If your server supports MLSD command and you have PHP 7.2 or newer, you can use ftp_mlsd function:
function ftp_mlsd_recursive($ftp_stream, $directory)
{
$result = [];
$files = ftp_mlsd($ftp_stream, $directory);
if ($files === false)
{
die("Cannot list $directory");
}
foreach ($files as $file)
{
$name = $file["name"];
$filepath = $directory . "/" . $name;
if (($file["type"] == "cdir") || ($file["type"] == "pdir"))
{
// noop
}
else if ($file["type"] == "dir")
{
$result = array_merge($result, ftp_mlsd_recursive($ftp_stream, $filepath));
}
else
{
$result[] = $filepath;
}
}
return $result;
}
If you do not have PHP 7.2, you can try to implement the MLSD command on your own. For a start, see user comment of the ftp_rawlist command:
https://www.php.net/manual/en/function.ftp-rawlist.php#101071
If you cannot use MLSD, you will particularly have problems telling if an entry is a file or folder. While you can use the ftp_size trick, calling ftp_size for each entry can take ages.
But if you need to work against one specific FTP server only, you can use ftp_rawlist to retrieve a file listing in a platform-specific format and parse that.
The following code assumes a common *nix format.
function ftp_nlst_recursive($ftp_stream, $directory)
{
$result = [];
$lines = ftp_rawlist($ftp_stream, $directory);
if ($lines === false)
{
die("Cannot list $directory");
}
foreach ($lines as $line)
{
$tokens = preg_split("/\s+/", $line, 9);
$name = $tokens[8];
$type = $tokens[0][0];
$filepath = $directory . "/" . $name;
if ($type == 'd')
{
$result = array_merge($result, ftp_nlst_recursive($ftp_stream, $filepath));
}
else
{
$result[] = $filepath;
}
}
return $result;
}
For DOS format, see: Get directory structure from FTP using PHP.
I've build an OOP FTP Client library that's can help you on this a lot, using just this code you can retrieve a list of only the directories with addition useful information like (chmod, last modified time, size ...).
The code :
// Connection
$connection = new FtpConnection("localhost", "foo", "12345");
$connection->open();
// FtpConfig
$config = new FtpConfig($connection);
$config->setPassive(true);
$client = new FtpClient($connection);
$allFolders =
// directory, recursive, filter
$client->listDirectoryDetails('/', true, FtpClient::DIR_TYPE);
// Do whatever you want with the folders
This code a variation of Martin Prikryl one. It is slower but do not have any failures with whitespaces. Use this code only if you have any problems with the code above.
function ftp_list_files_recursive($ftp_stream, $path){
$lines = ftp_nlist($ftp_stream, $path);
$result = array();
foreach ($lines as $line) {
if (ftp_size($ftp_stream, $line) == -1) {
$result = array_merge($result, ftp_list_files_recursive($ftp_stream, $line));
}
else{
$result[] = $line;
}
}
return $result;
}

Count how many files in directory PHP

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 ....

How to get directory size in 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
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

Categories