I am writing an application that can stream videos. It requires the filesize of the video, so I use this code:
$filesize = sprintf("%u", filesize($file));
However, when streaming a six gig movie, it fails.
Is is possible to get a bigger interger value in PHP? I don't care if I have to use third party libraries, if it is slow, all I care about is that it can get the filesize properly.
FYI, $filesize is currently 3017575487 which is really really really really far from 6000000000, which is roughly correct.
I am running PHP on a 64 bit operating system.
Thanks for any suggestions!
-
If you're using 64-bit PHP on a 64-bit operating systemMark Baker– Mark Baker2014年08月02日 17:40:45 +00:00Commented Aug 2, 2014 at 17:40
-
@MarkBaker Yes I am using a 64 bit operating system.Nathan– Nathan2014年08月02日 17:42:33 +00:00Commented Aug 2, 2014 at 17:42
-
@MarkBaker It says when I run phpinfo that it is using 86x architecture. I am running XAMPP.Nathan– Nathan2014年08月02日 17:44:11 +00:00Commented Aug 2, 2014 at 17:44
-
Check the value of the PHP_INT_MAX or PHP_INT_SIZE constantsMark Baker– Mark Baker2014年08月02日 17:45:57 +00:00Commented Aug 2, 2014 at 17:45
-
1Or switch from using xampp (which shouldn't be used in production anyway) to a 64-bit Windows PHP binary.... if this isn't a production system, why worry about "experimental"Mark Baker– Mark Baker2014年08月02日 18:05:39 +00:00Commented Aug 2, 2014 at 18:05
2 Answers 2
The issue here is two-fold.
Problem 1
The filesize function returns a signed integer, with a maximum value of PHP_INT_MAX. On 32-bit PHP, this value is 2147483647 or about 2GB. On 64-bit PHP can you go higher, up to 9223372036854775807. Based on the comments from the PHP filesize page, I created a function that will use a fseek loop to find the size of the file, and return it as a float, which can count higher that a 32-bit unisgned integer.
function filesize_float($filename)
{
$f = fopen($filename, 'r');
$p = 0;
$b = 1073741824;
fseek($f, 0, SEEK_SET);
while($b > 1)
{
fseek($f, $b, SEEK_CUR);
if(fgetc($f) === false)
{
fseek($f, -$b, SEEK_CUR);
$b = (int)($b / 2);
}
else
{
fseek($f, -1, SEEK_CUR);
$p += $b;
}
}
while(fgetc($f) !== false)
{
++$p;
}
fclose($f);
return $p;
}
To get the file size of the file as a float using the above function, you would call it like this.
$filesize = filesize_float($file);
Problem 2
Using %u in the sprintf function will cause it to interpret the argument as an unsigned integer, thus limiting the maximum possible value to 4294967295 on 32-bit PHP, before overflowing. Therefore, if we were to do the following, it would return the wrong number.
sprintf("%u", filesize_float($file));
You could interpret the value as a float using %F, using the following, but it will result in trailing decimals.
sprintf("%F", filesize_float($file));
For example, the above will return something like 6442450944.000000, rather than 6442450944.
A workaround would be to have sprintf interpret the float as a string, and let PHP cast the float to a string.
$filesize = sprintf("%s", filesize_float($file));
This will set $filesize to the value of something like 6442450944, without trailing decimals.
The Final Solution
If you add the filesize_float function above to your code, you can simply use the following line of code to read the actual file size into the sprintf statement.
$filesize = sprintf("%s", filesize_float($file));
2 Comments
As per PHP docuemnation for 64 bit platforms, this seems quite reliable for getting the filesize of files> 4GB
<?php
$a = fopen($filename, 'r');
fseek($a, 0, SEEK_END);
$filesize = ftell($a);
fclose($a);
?>