yes, this function is well known and great
- but if there are values <=0, then you'll get
"warning: division by zero ...".
happens if filesize() returns false on error.
so better use something like this:
<?php
function byte_convert($bytes)
{
$symbol = array('B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB');
$exp = 0;
$converted_value = 0;
if( $bytes > 0 )
{
$exp = floor( log($bytes)/log(1024) );
$converted_value = ( $bytes/pow(1024,floor($exp)) );
}
return sprintf( '%.2f '.$symbol[$exp], $converted_value );
}
?>
it returns "0" in our problem cases. you may add "false" for backend-usage also. ;O)
filesize
(PHP 4, PHP 5)
filesize — ファイルのサイズを取得する
説明
int filesize
( string $filename
)
指定したファイルのサイズを取得します。
パラメータ
- filename
-
ファイルへのパス。
返り値
ファイルのサイズを返し、エラーの場合は FALSE を返します (また E_WARNING レベルのエラーを発生させます) 。
注意: PHP の数値型は符号付整数であり、 多くのプラットフォームでは 32 ビットの整数を取るため、 filesize() は 2GB より大きなファイルについては期待とは違う値を返すことがあります。 2GB から 4GB のサイズのファイルについては sprintf("%u", filesize($file)) を使うことで打開されます。
例
例1 filesize() の例
<?php
// 出力例 somefile.txt: 1024 bytes
$filename = 'somefile.txt';
echo $filename . ': ' . filesize($filename) . ' bytes';
?>
注意
注意: この関数の結果は キャッシュされます。詳細は、clearstatcache() を参照してください。
ヒント
PHP 5.0.0 以降、この関数は、 何らかの URL ラッパーと組合せて使用することができます。 どのラッパーが stat() ファミリーをサポートしているか のリストについては、サポートされるプロトコル/ラッパー を参照してください。
filesize
d.abromeit
02-Sep-2008 04:55
02-Sep-2008 04:55
olafurw at gmail.com
15-Aug-2008 09:47
15-Aug-2008 09:47
No loops needed for this. Should be the fastest way.
<?php
function byteConvert($bytes)
{
$s = array('B', 'Kb', 'MB', 'GB', 'TB', 'PB');
$e = floor(log($bytes)/log(1024));
return sprintf('%.2f '.$s[$e], ($bytes/pow(1024, floor($e))));
}
?>
felix
15-Aug-2008 06:02
15-Aug-2008 06:02
Warning: filesize() [function.filesize]: stat failed for (...)
$path='example.txt';
try filesize('./'.$path) instead of filesize($path)
it worked for me
mic
06-Aug-2008 03:04
06-Aug-2008 03:04
Be aware to use this function on files/dirs which are NOT writeable: you will get a warning like:
Warning: filesize() [function.filesize]: stat failed for /var/www/xxx/yyy.php in /var/www/xxx/yyy.php on line 123
php-manual at gone dot nl
23-Jul-2008 11:36
23-Jul-2008 11:36
Based on Maikels function.
Improved performance (10 - 15%) and added Doc-block
<?php
/**
* Present a size (in bytes) as a human-readable value
*
* @param int $size size (in bytes)
* @param int $precision number of digits after the decimal point
* @return string
*/
function bytestostring($size, $precision = 0) {
$sizes = array('YB', 'ZB', 'EB', 'PB', 'TB', 'GB', 'MB', 'kB', 'B');
$total = count($sizes);
while($total-- && $size > 1024) $size /= 1024;
return round($size, $precision).$sizes[$total];
}
?>
Supermagnus
30-Jun-2008 12:38
30-Jun-2008 12:38
function getSizeFile($url) {
if (substr($url,0,4)=='http') {
$x = array_change_key_case(get_headers($url, 1),CASE_LOWER);
if ( strcasecmp($x[0], 'HTTP/1.1 200 OK') != 0 ) { $x = $x['content-length'][1]; }
else { $x = $x['content-length']; }
}
else { $x = @filesize($url); }
return $x;
}
In case of you have a redirection in the server (like Redirect Permanent in the .htaccess)
In this case we have for exemple:
[content-length] => Array
(
[0] => 294 // Size requested file
[1] => 357556 // Real Size redirected file
)
Maikel
25-Jun-2008 07:06
25-Jun-2008 07:06
Even better!
<?php
function format_size($size, $round = 0) {
//Size must be bytes!
$sizes = array('B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB');
$total = count($sizes);
for ($i=0; $size > 1024 && $i < $total; $i++) $size /= 1024;
return round($size,$round).$sizes[$i];
}
?>
Anyway, the previous post was to show how isset is better than count in performance
Maikel
15-Jun-2008 04:19
15-Jun-2008 04:19
php at wormss dot net function, A little bit better in performance:
<?php
function format_size($size, $round = 0) {
//Size must be bytes!
$sizes = array('B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB');
for ($i=0; $size > 1024 && isset($sizes[$i+1]); $i++) $size /= 1024;
return round($size,$round).$sizes[$i];
}
?>
chris [AT] cmbuckley [DOT] co [DOT] uk
21-May-2008 03:36
21-May-2008 03:36
Slight bug in the script below, the power should be incremented after the string assignment:
<?php
do {
if (1024 > ($byte /= 1024)) {
$str = ($pow < strlen($postfixes) ? $postfixes[$pow] . 'iB' : '× 2<sup>' . ($pow * 10) . '</sup> B');
}
$pow++;
} while ($byte >= 1024);
?>
chris [AT] cmbuckley [DOT] co [DOT] uk
20-May-2008 11:39
20-May-2008 11:39
Yet another function for size readability:
<?php
function filesize_format($byte = 0, $format = null) {
$postfixes = 'KMGTPEZY'; $pow = 0;
do {
$pow++;
if (1024 > ($byte /= 1024)) {
$str = ($pow < strlen($postfixes) ? $postfixes[$pow] . 'iB' : '× 2<sup>' . ($pow * 10) . '</sup> B');
}
} while ($byte >= 1024);
$arr = array($byte, $str);
return (is_null($format) ? $arr : vsprintf("$format %s", $arr));
}
// array(2) { [0]=> float(10.8623046875) [1]=> string(3) "MiB" }
var_dump(filesize_format(11123));
// string(8) "10.86 MiB"
var_dump(filesize_format(11123, '%01.2f'));
// string(27) "82 × 2<sup>80</sup> B"
var_dump(filesize_format(99999999999999999999999999, '%d'));
?>
kroccamen, gmail
29-Mar-2008 02:54
29-Mar-2008 02:54
Format filesize in one line:
(line-breaks added only for readability)
<?php
$file_size = array_reduce (
array (" B", " KB", " MB"), create_function (
'$a,$b', 'return is_numeric($a)?($a>=1024?$a/1024:number_format($a,2).$b):$a;'
), filesize ($file_path)
);
?>
Enjoi!
php at wormss dot net
25-Mar-2008 03:01
25-Mar-2008 03:01
Just a small bit added in-case someone doesn't want it to go up to 'TB' and deletes 'TB' onwards but the file size is larger than 1024GB this checks to see if you have outreached the size of $sizes
<?php
function format_size($size, $round = 0) {
//Size must be bytes!
$sizes = array('B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB');
for ($i=0; $size > 1024 && $i < count($sizes) - 1; $i++) $size /= 1024;
return round($size,$round).$sizes[$i];
}
?>
achilles
21-Mar-2008 03:14
21-Mar-2008 03:14
Here a function for better formatting of a filesize:
function filesize_format($filesize) {
if($filesize < pow(1024, 1)) return $filesize. " Bytes";
elseif($filesize < pow(1024, 2)) return round($filesize/pow(1024, 1), 3)." KiB";
elseif($filesize < pow(1024, 3)) return round($filesize/pow(1024, 2), 3)." MiB";
elseif($filesize < pow(1024, 4)) return round($filesize/pow(1024, 3), 3)." GiB";
elseif($filesize < pow(1024, 5)) return round($filesize/pow(1024, 4), 3)." TiB";
elseif($filesize < pow(1024, 6)) return round($filesize/pow(1024, 5), 3)." PiB";
elseif($filesize < pow(1024, 7)) return round($filesize/pow(1024, 6), 3)." EiB";
elseif($filesize < pow(1024, 8)) return round($filesize/pow(1024, 7), 3)." ZiB";
else return round($filesize/pow(1024, 8), 3)." YiB"; }
bifor at free dot fr
19-Mar-2008 12:01
19-Mar-2008 12:01
A simple function for return the length of a link, or a file.
<?php
function urlfilesize($url,$thereturn) {
if (substr($url,0,4)=='http') {
$x = array_change_key_case(get_headers($url, 1),CASE_LOWER);
$x = $x['content-length'];
}
else { $x = @filesize($url); }
if (!$thereturn) { return $x ; }
elseif($thereturn == 'mb') { return round($x / (1024*1024),2) ; }
elseif($thereturn == 'kb') { return round($x / (1024),2) ; }
}
?>
The example :
<?php
echo urlfilesize('http://www.tayo.fr/remote-irc-tutoriel.php','mb')
?>
ronnie at logicalt dot com
03-Mar-2008 03:02
03-Mar-2008 03:02
Another workaround for the >2GB "stat failed" in Linux is to call the systems stat as follows:
$size = exec ('stat -c %s '. escapeshellarg ($file_path));
Yure666
10-Feb-2008 05:48
10-Feb-2008 05:48
This is a shorter (but not faster) code for the getsize function, will work for files and folders.
<?php
function getsize($path){
if (!is_dir($path))
return filesize($path);
$size=0;
foreach (scandir($path) as $file){
if ($file=='.' or $file=='..')
continue;
$size+=getsize($path.'/'.$file);
}
return $size;
}
?>
jason dot whitehead dot tas at gmail dot com
08-Feb-2008 12:14
08-Feb-2008 12:14
I have created a handy function, using parts of code from kaspernj at gmail dot com and md2perpe at gmail dot com, which should get file sizes > 4GB on Windows, Linux and Mac (at least).
function getSize($file) {
$size = filesize($file);
if ($size < 0)
if (!(strtoupper(substr(PHP_OS, 0, 3)) == 'WIN'))
$size = trim(`stat -c%s $file`);
else{
$fsobj = new COM("Scripting.FileSystemObject");
$f = $fsobj->GetFile($file);
$size = $file->Size;
}
return $size;
}
maskoflight at centrum dot cz
11-Jan-2008 07:33
11-Jan-2008 07:33
I found a mistake in note from "RobKohrPhp at remail dot robkohr dot com, 04-Feb-2006 09:42".
His simplified function isn't working correct:
<?php
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); // this line affects that size of file is added two times
$size += get_size($path.'/'.$file);
}
}
closedir($handle);
return $size;
}
}
?>
marked line affects that size of file is added two times, because function get_size is called on the next line, which adds a size correctly (if $file is dir, it will be add only with get_size calling, if $file is a file, it will be add with both functions filesize and get_size)
Here is a correction:
<?php
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!='..') {
// function filesize has been deleted
$size += get_size($path.'/'.$file);
}
}
closedir($handle);
return $size;
}
}
?>
marcel at marcel-hergerdt dot de
08-Jan-2008 03:10
08-Jan-2008 03:10
This script checks whether the file is large enough for the next unit and calculates them.
Example:
29249 bytes => 28.56 KB
10083695 bytes => 9.62 MB
function get_size($size) {
$bytes = array('B','KB','MB','GB','TB');
foreach($bytes as $val) {
if($size > 1024){
$size = $size / 1024;
}else{
break;
}
}
return round($size, 2)." ".$val;
}
webmaster at eclipse org
07-Nov-2007 04:30
07-Nov-2007 04:30
On 64-bit platforms, this seems quite reliable for getting the filesize of files > 4GB
$a = fopen($filename, 'r');
fseek($a, 0, SEEK_END);
$filesize = ftell($a);
fclose($a);
MagicalTux at gmail dot com
16-Oct-2007 07:58
16-Oct-2007 07:58
filesize() acts differently between platforms and distributions.
I tried manually compiling PHP on a 32bit platform. Filesize() would fail on files >2G.
Then I compiled again, adding CFLAGS=`getconf LFS_CFLAGS` in front of configure.
Then filesize() would success, but the result would be converted to a 32bit signed integer...
However on 64bit systems, PHP's integers are 64bit signed, and this would work just well...
So now the question is : should linux distributions (Debian, etc) define LFS_CFLAGS or not ? Doing so makes PHP be able to open/seek such files, but makes its behaviour buggy (stat() is supposed to fail if file size is >32bit and appl does not support such integers)...
exelsus at gmail dot com
30-Sep-2007 07:30
30-Sep-2007 07:30
That works for a folder size, but perhaps you should check this:
http://www.php.net/manual/en/function.disk-total-space.php
hkpark99 at dreamwiz dot com
19-Sep-2007 10:09
19-Sep-2007 10:09
How to get folder size? Here is an answer.
===========================================
function foldersize($path) {
$total_size = 0;
$files = scandir($path);
foreach($files as $t) {
if (is_dir($t)) { // In case of folder
if ($t<>"." && $t<>"..") { // Exclude self and parent folder
$size = foldersize($path . "/" . $t);
// print("Dir - $path/$t = $size<br>\n");
$total_size += $size;
}
}
else { // In case of file
$size = filesize($path . "/" . $t);
// print("File - $path/$t = $size<br>\n");
$total_size += $size;
}
}
return $total_size;
}
trask768 at yahoo dot com
02-Sep-2007 01:30
02-Sep-2007 01:30
Updated function to return human readable file size:
function size_readable ($size, $retstring = null) {
// adapted from code at http://aidanlister.com/repos/v/function.size_readable.php
$sizes = array('B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB');
if ($retstring === null) { $retstring = '%01.2f %s'; }
$lastsizestring = end($sizes);
foreach ($sizes as $sizestring) {
if ($size < 1024) { break; }
if ($sizestring != $lastsizestring) { $size /= 1024; }
}
if ($sizestring == $sizes[0]) { $retstring = '%01d %s'; } // Bytes aren't normally fractional
return sprintf($retstring, $size, $sizestring);
}
Michael MH
30-Aug-2007 03:28
30-Aug-2007 03:28
I just noticed, that filesize(), filemtime() etc. only work correctly on Mac OS X if the file's directory is executable for the PHP process. Otherwise it will report "stat failed for <filepathandname>".
emailfire at gmail dot com
12-Aug-2007 01:34
12-Aug-2007 01:34
Though probably slower, strlen(file_get_contents("file.txt")) might give the same results.
Radon8472
10-Aug-2007 01:03
10-Aug-2007 01:03
the fastest way to get the correct filesize in windows an linux would be this:
<?php
echo sprintf("%u", filesize($file));
?>
It prints the result of filesize as UNSIGNED INT so it can be until 4GB.
The reason is, SIGNED INT runs until 2GB and flips to -2GB watch following:
file<2GB = SIGNED: 1048576512 UNSIGNED: 1048576512
file>2GB = SIGNED: -2100140103 UNSIGNED: 2194827193
file<4GB = SIGNED: -100662784 UNSIGNED: 4194304512
p.s. I found this at: http://www.php.net/manual/en/function.filesize.php
md2perpe at gmail dot com
17-Jul-2007 11:29
17-Jul-2007 11:29
Another way to get a filesize > 2GB on Linux:
<?php
$size = trim(`stat -c%s $file_path`);
?>
coolmax1 at poczta dot fm
29-Jun-2007 11:55
29-Jun-2007 11:55
@l0co at wp dot pl:
fopen with w+:
Open for reading and writing; place the file pointer at the beginning of the file and truncate the file to zero length. If the file does not exist, attempt to create it.
in the second case, it will be:
<?php
$f = fopen($filename, 'w+'); // Now file specified in the $filename will be zero byte length
echo filesize($filename); //now filesize return zero
fclose($f);
?>
Did you mean that or something other?
BIZARREdotBG[at]GMAILdotCOM
29-Jun-2007 12:18
29-Jun-2007 12:18
Here is a simple addition to the original example that i have made.
First of all i must mention that i need to list all files in a dir and i do know all files names.
Because the filenames contains an INT at the same place in every file's name i use $n++ to generate the file names.
The code:
<?php
// outputs e.g. bits_01.jpg: 0.05 kb
//lets asign a value of 1 so we can start with file bits_01.jpg
$n = 1;
//the last file is bits_09.jpg so i call the WHILE until $n gets a value of 9
while ($n < 10) {
//using $n in each file's name
$filename = 'bits_0'.$n.'.jpg';
//getting the file size - from original example
$size = filesize($filename);
//while i don't wan't the result in bytes instead i divide by 1024 to print it out in kilo bytes (if you need it in MB then divide it by 1048576
//at the same line we round the result to the fourth sign after the comma
$sizemb = round(($size/1024),4);
//printing the result
//filename : size MB and brake to print next on the next line
echo $filename . ': ' . $sizemb . ' kb<br />';
//now after i've printed the first file and it's size, we proceed to the next one
$n++;
}
?>
Hope it is useful to someone.
P.S
Please excuse my bad English :-)
Robin Leffmann
26-Jun-2007 02:49
26-Jun-2007 02:49
Here's a dodgy little snippet I made to find out how much disk space (in 1K-blocks) any chosen node - file or directory - occupies in the file system..
function nodesize( $node )
{
if( !is_readable($node) ) return false;
$blah = exec( "/usr/bin/du -sk $node" );
return substr( $blah, 0, strpos($blah, 9) );
}
The character I search for with strpos() is a tab, as this is what 'du' on OpenBSD uses to separate size and node in the output - this might be whitespaces in other *nixes/distributions.
medhefgo at googlemail dot com
02-Jun-2007 03:02
02-Jun-2007 03:02
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;
}
?>
stirol at gmail dot com
01-Jun-2007 01:16
01-Jun-2007 01:16
Just to notice: open_basedir is in effect on this function ;)
plyyyy [AT] gmail [DOT] com
25-Apr-2007 12:54
25-Apr-2007 12: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"];
}
ibitgsm at gmail dot com
25-Feb-2007 03:55
25-Feb-2007 03: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`
?>
wielkiegie at gmail dot com
30-Jan-2007 01:42
30-Jan-2007 01: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);).
Randy Tayler
11-Jan-2007 11:37
11-Jan-2007 11: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];
Josh Finlay <josh at glamourcastle dot com>
12-Nov-2006 09:22
12-Nov-2006 09: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;
}
}
?>
ming
04-Sep-2006 11:25
04-Sep-2006 11:25
the "remote file size" snippet below is cool but only works in php5 since get_headers() is not supported in php4.
9U
25-Aug-2006 12:12
25-Aug-2006 12: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'];
rico at ws5 dot org
08-Aug-2006 09:41
08-Aug-2006 09: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]);
}
?>
kaspernj at gmail dot com
18-Jul-2006 03:43
18-Jul-2006 03: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 :)
core58 at mail dot ru
14-Apr-2006 05:21
14-Apr-2006 05: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;
}
fabio at nospam dot please dot nitrodev dot com
13-Apr-2006 02:46
13-Apr-2006 02: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).
core58 at mail dot ru
10-Apr-2006 02:09
10-Apr-2006 02: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;
}
?>
mkamerma at science dot uva dot nl
12-Mar-2006 03:12
12-Mar-2006 03: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); }
?>
Jonas Sweden
10-Mar-2006 01:55
10-Mar-2006 01: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;
}
?>
jiquera at yahoo dot com
06-Mar-2006 05:02
06-Mar-2006 05: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(