I created another dirsize() function which doesn't use recursion.
I gained a ~2-3% performance boost while it uses ~50% lesser memory!
<?php
function dirsize($dirname) {
if (!is_dir($dirname) || !is_readable($dirname)) {
return false;
}
$dirname_stack[] = $dirname;
$size = 0;
do {
$dirname = array_shift($dirname_stack);
$handle = opendir($dirname);
while (false !== ($file = readdir($handle))) {
if ($file != '.' && $file != '..' && is_readable($dirname . DIRECTORY_SEPARATOR . $file)) {
if (is_dir($dirname . DIRECTORY_SEPARATOR . $file)) {
$dirname_stack[] = $dirname . DIRECTORY_SEPARATOR . $file;
}
$size += filesize($dirname . DIRECTORY_SEPARATOR . $file);
}
}
closedir($handle);
} while (count($dirname_stack) > 0);
return $size;
}
?>
filesize
(PHP 4, PHP 5)
filesize — Gets file size
Description
int filesize ( string $filename )Returns the size of the file in bytes, or FALSE (and generates an error of level E_WARNING) in case of an error.
Note: Because PHP's integer type is signed and many platforms use 32bit integers, filesize() may return unexpected results for files which are larger than 2GB. For files between 2GB and 4GB in size this can usually be overcome by using sprintf("%u", filesize($file)).
Note: The results of this function are cached. See clearstatcache() for more details.
As of PHP 5.0.0 this function can also be used with some URL wrappers. Refer to Appendix O, List of Supported Protocols/Wrappers for a listing of which wrappers support stat() family of functionality.
Example 624. filesize() example
<?php
// outputs e.g. somefile.txt: 1024 bytes
$filename = 'somefile.txt';
echo $filename . ': ' . filesize($filename) . ' bytes';
?>
See also file_exists()
filesize
02-Jun-2007 01:02
01-Jun-2007 11:16
Just to notice: open_basedir is in effect on this function ;)
24-Apr-2007 10:54
simple addition to function remotefsize by Josh Finlay(http part):
(sometimes servers send headers in lower case)
if (($sch == "http") || ($sch == "https")) {
$headers = array_change_key_case(get_headers($url, 1),CASE_LOWER);
if ((!array_key_exists("content-length", $headers))) { return false; }
return $headers["content-length"];
}
25-Feb-2007 02:55
Note that functions written in PHP which get directory size recursively are much slower than just calling `du`.
I hope this short code snipet will help someone:)
<?php
function dirsize($path)
{
$old_path = getcwd();
if(!is_dir($old_path."/".$path)) return -1;
$size = trim(shell_exec("cd \"".$old_path."/".$path."\"; du -sb; cd \"".$old_path."\";"), "\x00..\x2F\x3A..\xFF");
return $size;
}
P.S. trim() remove here all nonprintable an non-digit chars which appear in the output of `du`
?>
30-Jan-2007 12:42
There is a lot of functions for size of dir. But drive operations are slow, so if you want use those functions many times in one script, it's too slow. You can use this small function instead:
<?php
function dirsize($dir,$buf=2)
{
static $buffer;
if(isset($buffer[$dir]))
return $buffer[$dir];
if(is_file($dir))
return filesize($dir);
if($dh=opendir($dir))
{
$size=0;
while(($file=readdir($dh))!==false)
{
if($file=='.' || $file=='..')
continue;
$size+=dirsize($dir.'/'.$file,$buf-1);
}
closedir($dh);
if($buf>0)
$buffer[$dir]=$size;
return $size;
}
return false;
}
?>
What does it do? It save size in static array to cache result. You can choose deep value (e.q. if you want cache only first dir, use dirsize($dirname,1);).
11-Jan-2007 10:37
9U's snippet actually returns an array for Content-Length.
To get the filesize in bytes you'd want to say
$filesize = $ary_header['Content-Length'][1];
12-Nov-2006 08:22
I know there has been alot of remote filesize snippets posted, but I'll post mine also.
It supports HTTP/HTTPS/FTP/FTPS and detects which type it should use. It needs --enable-ftp for the FTP/FTPS functions.
I hope this works for someone.
<?php
function remotefsize($url) {
$sch = parse_url($url, PHP_URL_SCHEME);
if (($sch != "http") && ($sch != "https") && ($sch != "ftp") && ($sch != "ftps")) {
return false;
}
if (($sch == "http") || ($sch == "https")) {
$headers = get_headers($url, 1);
if ((!array_key_exists("Content-Length", $headers))) { return false; }
return $headers["Content-Length"];
}
if (($sch == "ftp") || ($sch == "ftps")) {
$server = parse_url($url, PHP_URL_HOST);
$port = parse_url($url, PHP_URL_PORT);
$path = parse_url($url, PHP_URL_PATH);
$user = parse_url($url, PHP_URL_USER);
$pass = parse_url($url, PHP_URL_PASS);
if ((!$server) || (!$path)) { return false; }
if (!$port) { $port = 21; }
if (!$user) { $user = "anonymous"; }
if (!$pass) { $pass = "phpos@"; }
switch ($sch) {
case "ftp":
$ftpid = ftp_connect($server, $port);
break;
case "ftps":
$ftpid = ftp_ssl_connect($server, $port);
break;
}
if (!$ftpid) { return false; }
$login = ftp_login($ftpid, $user, $pass);
if (!$login) { return false; }
$ftpsize = ftp_size($ftpid, $path);
ftp_close($ftpid);
if ($ftpsize == -1) { return false; }
return $ftpsize;
}
}
?>
04-Sep-2006 09:25
the "remote file size" snippet below is cool but only works in php5 since get_headers() is not supported in php4.
24-Aug-2006 10:12
################################################
# Remote file size
$filename = 'http://www.url.com/image.jpg';
$ary_header = get_headers($filename, 1);
$filesize = $ary_header['Content-Length'];
$type = $ary_header['Content-Type'];
08-Aug-2006 07:41
To get the size of files above 2GB you can use the linux-command filesize like this:
<?php
function real_filesize_linux($file) {
@exec("filesize $file",$out,$ret);
if ( $ret <> '0' ) return FALSE;
else return($out[0]);
}
?>
18-Jul-2006 01:43
If you want to get the actual filesize for a size above 2 gb in Windows, you can use the COM-extensions in PHP.
An example is as follows:
<?
function knj_filesize($file){
if (file_exists($file)){
$fsobj = new COM("Scripting.FileSystemObject");
$file = $fsobj->GetFile($file);
$var = ($file->Size) + 1 - 1;
return $var;
}else{
echo "File does not exist.\n";
return false;
}
}
?>
This will return the corrent filesize. And it is very useful with PHP-GTK applications, where you want to use the filesize for larger files.
This example also works for files over a Windows-network. Try this example with the function:
<?
echo knj_filesize("//mycomputer/music/Track1.mp3");
?>
Happy hacking :)
14-Apr-2006 03:21
some notes and modifications to previous post.
refering to RFC, when using HTTP/1.1 your request (either GET or POST or HEAD) must contain Host header string, opposite to HTTP/1.1 where Host ain't required. but there's no sure how your remote server would treat the request so you can add Host anyway (it won't be an error for HTTP/1.0).
host value _must_ be a host name (not CNAME and not IP address).
this function catches response, containing Location header and recursively sends HEAD request to host where we are moved until final response is met.
(you can experience such redirections often when downloading something from php scripts or some hash links that use apache mod_rewrite. most all of dowloading masters handle 302 redirects correctly, so this code does it too (running recursively thru 302 redirections).)
[$counter302] specify how much times your allow this function to jump if redirections are met. If initial limit (5 is default) expired -- it returns 0 (should be modified for your purposes whatever).0
ReadHeader() function is listed in previous post
(param description is placed there too).
<?php
function remote_filesize_thru( $ipAddress, $url, $counter302 = 5 )
{
$socket = fsockopen( "10.233.225.2", 8080 );
if( !$socket )
{
// failed to open TCP socket connection
// do something sensible here besides exit();
echo "<br>failed to open socket for [$ipAddress]";
exit();
}
// just send HEAD request to server
$head = "HEAD $url HTTP/1.0\r\nConnection: Close\r\n\r\n";
// you may use HTTP/1.1 instead, then your request head string _must_ contain "Host: " header
fwrite( $socket, $head );
// read the response header
$header = ReadHeader( $socket );
if( !$header )
{
// handle empty response here the way you need...
Header( "HTTP/1.1 404 Not Found" );
exit();
}
fclose( $socket );
// check for "Location" header
$locationMarker = "Location: ";
$pos = strpos( $header, $locationMarker );
if( $pos > 0 )
{
$counter302--;
if( $counter302 < 0 )
{
// redirect limit (5 by default) expired -- return some warning or do something sensible here
echo "warning: too long redirection sequence";
return 0;
}
// Location is present -- we should determine target host and move there, like any downloading masters do...
// no need to use regex here
$end = strpos( $header, "\n", $pos );
$location = trim( substr( $header, $pos + strlen( $locationMarker ), $end - $pos - strlen( $locationMarker ) ), "\\r\\n" );
// extract pure host (without "http://")
$host = explode( "/", $location );
$ipa = gethostbyname( $host[2] );
// move to Location
return remote_filesize_thru( $ipa, $location, $counter302 );
}
// try to acquire Content-Length within the response
$regex = '/Content-Length:\s([0-9].+?)\s/';
$count = preg_match($regex, $header, $matches);
// if there was a Content-Length field, its value
// will now be in $matches[1]
if( isset( $matches[1] ) )
$size = $matches[1];
else
$size = 0;
return $size;
}
13-Apr-2006 12:46
core58 at mail dot ru, it did save me time!
One note though. I had to add the Host: header in order to get it working. The value should be the host name (DNS, not IP).
10-Apr-2006 12:09
this is "raw" version of remote_filesize() function.
according to RFC, HTTP servers MUST implement at least GET, POST and HEAD requests, so the function just opens TCP socket connection, sends HEAD request and receives response, parsing length of the resource.
[$ipAddress] is the ip address of remote server.
[$url] is the name of file which size you want to determine.
the code was tested under Apache 2.0.43 and IIS 6.0 and it works correctly in both cases.
i wish the code can save someone's time :)
example:
$ipa = gethostbyname( "www.someserver.com" );
$url = "/docs/somedocument.pdf";
$fsize = remote_filesize2( $ipa, $url );
==========================
<?php
function ReadHeader( $socket )
{
$i=0;
$header = "";
while( true && $i<20 )
{
// counter [$i] is used here to avoid deadlock while reading header string
// it's limited by [20] here cause i really haven't ever met headers with string counter greater than 20
// *
$s = fgets( $socket, 4096 );
$header .= $s;
if( strcmp( $s, "\r\n" ) == 0 || strcmp( $s, "\n" ) == 0 )
break;
$i++;
}
if( $i >= 20 )
{
// suspicious header strings count was read
// *
return false;
}
return $header;
}
function remote_filesize2( $ipAddress, $url )
{
$socket = fsockopen( $ipAddress, 80 );
if( !$socket )
{
// failed to open TCP socket connection
// do something sensible here besides exit();
// ...
exit();
}
// just send HEAD request to server
// *
fwrite( $socket, "HEAD $url HTTP/1.0\r\nConnection: Close\r\n\r\n" );
// read the response header
// *
$header = ReadHeader( $socket );
if( !$header )
{
Header( "HTTP/1.1 404 Not Found" );
exit();
}
// try to acquire Content-Length within the response
// *
$regex = '/Content-Length:\s([0-9].+?)\s/';
$count = preg_match($regex, $header, $matches);
// if there was a Content-Length field, its value
// will now be in $matches[1]
if( isset( $matches[1] ) )
{
$size = $matches[1];
}
else
{
$size = 0;
}
fclose( $socket );
return $size;
}
?>
12-Mar-2006 02:12
When read/writing binary files you often cannot rely on the feof() function being of much use, since it doesn't get triggered if the pointer is at the eof but hasn't tried to read one more byte. In this case you instead need to check if the file pointer is at filesize yet, but if you don't have the filename handy, you need to pluck it out fstat all the time. Two simple functions that would be nice to have natively in PHP:
<?php
function fpfilesize(&$fp) { $stat = fstat($fp); return $stat["size"]; }
function fpeof(&$fp) { return ftell($fp)==fpfilesize($fp); }
?>
10-Mar-2006 12:55
<?php
/* Recursive filesize, nothing new but a small one.
The $self var as a convenience if i want to change
functionname */
function filesize_r($path){
if(!file_exists($path)) return 0;
if(is_file($path)) return filesize($path);
$self = __FUNCTION__;
$ret = 0;
foreach(glob($path."/*") as $fn)
$ret += $self($fn);
return $ret;
}
?>
06-Mar-2006 04:02
here a piece of code to format a filesize:
<?php
function formatbytes($val, $digits = 3, $mode = "SI", $bB = "B"){ //$mode == "SI"|"IEC", $bB == "b"|"B"
$si = array("", "k", "M", "G", "T", "P", "E", "Z", "Y");
$iec = array("", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi", "Yi");
switch(strtoupper($mode)) {
case "SI" : $factor = 1000; $symbols = $si; break;
case "IEC" : $factor = 1024; $symbols = $iec; break;
default : $factor = 1000; $symbols = $si; break;
}
switch($bB) {
case "b" : $val *= 8; break;
default : $bB = "B"; break;
}
for($i=0;$i<count($symbols)-1 && $val>=$factor;$i++)
$val /= $factor;
$p = strpos($val, ".");
if($p !== false && $p > $digits) $val = round($val);
elseif($p !== false) $val = round($val, $digits-$p);
return round($val, $digits) . " " . $symbols[$i] . $bB;
}
//some test cases:
function test($i, $digits = 3, $mode = "SI", $bB = "B"){
echo $i . " = " . formatbytes($i, $digits, $mode, $bB) . "<br>\n";
}
test(1024);
test(1024*1024);
test(1024*1024, 4);
test(1024*1024, 3, "IEC");
test(1024, 3, "SI", "b");
test(32423);
test(323);
test(128, "3", "IEC", "b");
test(324235236362453);
test(32423535424236324362453, 3, "IEC");
//actual use:
echo formatbytes(file_size("myfile.php"));
?>
it formats to bit or bytes according to SI or IEC and rounded to a given number of digits.
04-Feb-2006 08:42
Simplified recursive size measurement. Will also take into account the size of the folders themselves.
function get_size($path)
{
if(!is_dir($path)) return filesize($path);
if ($handle = opendir($path)) {
$size = 0;
while (false !== ($file = readdir($handle))) {
if($file!='.' && $file!='..'){
$size += filesize($path.'/'.$file);
$size += get_size($path.'/'.$file);
}
}
closedir($handle);
return $size;
}
}
29-Jan-2006 12:08
If you are trying to find a way to get the filesize for files over 2GB, you can always use exec() and run a system command to return the value. The following works on my linux box:
$sizeInBytes = filesize($path);
if (!$sizeInBytes) {
$command = "ls -l \"$path\" | cut -d \" \" -f 6";
$sizeInBytes = exec($command);
}
31-Dec-2005 06:54
Recursive function, which returns size of folder or file.
<?php
function get_size($path)
{
if(!is_dir($path))return filesize($path);
$dir = opendir($path);
while($file = readdir($dir))
{
if(is_file($path."/".$file))$size+=filesize($path."/".$file);
if(is_dir($path."/".$file) && $file!="." && $file !="..")$size +=get_size($path."/".$file);
}
return $size;
}
?>
13-Jul-2005 04:01
This function uses a stack array to get the size of a directory.
http://aidanlister.com/repos/v/function.dirsize.php
You can convert this to a human readable size using:
http://aidanlister.com/repos/v/function.size_readable.php
For a faster (unix only) implementation, see function.disk-total-space, note #34100
http://www.php.net/manual/en/function.disk-total-space.php#34100
Also of interest is this wikipedia article, discussing the difference between a kilobyte (1000) and a kibibyte (1024).
http://en.wikipedia.org/wiki/Bytes
06-Mar-2005 02:52
Addition to my earlier post: I searched around and found the background in the notes for disk_total_space(): http://www.php.net/manual/en/function.disk-total-space.php
To give a short summary here - andudi pointed out that
a) the SIZE of a file and
b) the SPACE on disk it uses
aren't equal and shalless provided a function dskspace() which returns exactly (tested!) what "du" would.
19-Nov-2004 11:33
In addition to the handy function Kris posted, here is an upgraded version that does basic http authentication as well.
<?php
/*
* (mixed)remote_filesize($uri,$user='',$pw='')
* returns the size of a remote stream in bytes or
* the string 'unknown'. Also takes user and pw
* incase the site requires authentication to access
* the uri
*/
function remote_filesize($uri,$user='',$pw='')
{
// start output buffering
ob_start();
// initialize curl with given uri
$ch = curl_init($uri);
// make sure we get the header
curl_setopt($ch, CURLOPT_HEADER, 1);
// make it a http HEAD request
curl_setopt($ch, CURLOPT_NOBODY, 1);
// if auth is needed, do it here
if (!empty($user) && !empty($pw))
{
$headers = array('Authorization: Basic ' . base64_encode($user.':'.$pw));
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
}
$okay = curl_exec($ch);
curl_close($ch);
// get the output buffer
$head = ob_get_contents();
// clean the output buffer and return to previous
// buffer settings
ob_end_clean();
// gets you the numeric value from the Content-Length
// field in the http header
$regex = '/Content-Length:\s([0-9].+?)\s/';
$count = preg_match($regex, $head, $matches);
// if there was a Content-Length field, its value
// will now be in $matches[1]
if (isset($matches[1]))
{
$size = $matches[1];
}
else
{
$size = 'unknown';
}
return $size;
}
?>
