6

I have been struggeling on how to get the valid filesize of a file that is >= 2 GB in PHP.

Example
Here I am checking the filesize of a file that is 3,827,394,560 bytes large with the filesize() function:

echo "The file is " . filesize('C:\MyFile.rar') . " bytes.";

Result
This is what it returns:

The file is -467572736 bytes.

Background
PHP uses signed integers, which means that the maximum number it can represent is 2,147,483,647 (+/- 2 GB).
This is where it is limited.

René Sackers
  • 1,983
  • 1
  • 22
  • 39
  • Possible duplicate of [PHP x86 How to get filesize of >2GB file without external program?](http://stackoverflow.com/questions/5501451/php-x86-how-to-get-filesize-of-2gb-file-without-external-program) – bummi Feb 05 '16 at 21:47

7 Answers7

6

The solution I tried and apparently works is to use the "Size" property of the COM FileObject. I am not entirely sure what type it uses.

This is my code:

function real_filesize($file_path)
{
    $fs = new COM("Scripting.FileSystemObject");
    return $fs->GetFile($file_path)->Size;
}

It's simply called as following:

$file = 'C:\MyFile.rar';
$size = real_filesize($file);
echo "The size of the file is: $size";

Result

The size of the file is: 3,827,394,560 bytes

René Sackers
  • 1,983
  • 1
  • 22
  • 39
  • 6
    fyi COM Objects mean windows only – Mike B Feb 19 '12 at 02:33
  • 2
    The question talk about a file in "C:\" so he assume that the environment was Windows. – Juanma Feb 19 '12 at 02:47
  • 3
    @Juanma Assumed? The same person who asked the question posted this answer seconds later. But if you're having this problem and happen to stumble on this page you're much better using the OS-agnostic solution for obvious reasons. – Mike B Feb 19 '12 at 02:52
  • @MikeB Entirely correct, a cross-platform solution like Borealid pointed out might be preferable, but I personally think this method might be slightly more optimized. The reason I posted it seconds later is because I had already found an answer to it, but wanted to see some more opinions on it, and share my solution for Windows platforms. I did not see this solution anywhere else on the web. – René Sackers Feb 19 '12 at 20:28
  • 1
    @RenéSackers Both your solution and the one presented by Borealid are in the manual under `filesize()`. http://www.php.net/manual/en/function.filesize.php#104101 and http://us.php.net/manual/en/function.filesize.php#102135 – Mike B Feb 19 '12 at 20:46
  • My appologies! I did not see that before, it's indeed exactly the same. Atleast it's easier to find now that it's on StackOverflow ;) – René Sackers Feb 20 '12 at 00:41
5

http://us.php.net/manual/en/function.filesize.php#102135 gives a complete and correct means for finding the size of a file larger than 2GB in PHP, without relying on OS-specific interfaces.

The gist of it is that you first use filesize to get the "low" bits, then open+seek the file to determine how many multiples of 2GB it contains (the "high" bits).

Borealid
  • 86,367
  • 8
  • 101
  • 120
2

I was using a different approach, saving precious server-resources, have a look at my GitHub repository github.com/eladkarako/download.eladkarako.com.

It is a plain, and complete, download-dashboard, that overcome the (*rare) cases of   filesize   error using client-side head-request, granted, it will not be embedded into the page's HTML source, but rendered (*fixed) some time later, so it is more suitable for hmm..., lets say, relaxed scenarios..

To make this solution available, an Apache .htaccess (or header in PHP) should be added allowing client-side usage of Content-Length value.

Essentially you can slim down the .htaccess to just allowing Content-Length removing other CORS rules.. making the website more secure.

no jQuery was used and whole thing was written in my Samsung text-editor and uploaded by FTP from my smartphone, in a 1.5-hour train-ride in my MILUIM.. and yet, still impeccable ;)

1

I have one "hacky" solution what works well.

Look please THIS function how I do it and you need also include this class to function can works well or change by your need.

example:

include_once 'class.os.php';
include_once 'function.filesize.32bit.php';

// Must be real path to file
$file = "/home/username/some-folder/yourfile.zip";
echo get_filesize($file);

This function is not ideal solution but here is how works:

  1. First check if shell_exec is enabled into PHP. If is enabled, it will check via shell command real filesize.
  2. If shell fail and OS is 64bit will return normal filesize() information
  3. If is 32bit will go into "chunking" method and calculate filesize reading buytes.

NOTE!

Alfter reading keep results in string format to can easly calculate because PHP can calculate strings but if you transfrorm results over 2GB into integer you will have same problem as before.

WARNING!

Chunking is realy slow and if you want to loop this, you will have memory leak or script can take minutes to finish reading all the files. If you use this function on server where you have shell_exec enabled, you will have super fast reading.

P.S.

If you have some idea for changes here and improvemants feel free to commit.

Ivijan Stefan Stipić
  • 4,828
  • 5
  • 35
  • 69
1

I know this is an oldie, but I'm using PHP x64 5.5.38 (for now) and don't want to upgrade to the latest 7.x version yet.

I did read all these posts about finding file sizes that are larger than 2GB, but all solutions where very slow for large amount of files.

So, yesterday I've created C/C++ PHP Extension "php_filesize.dll", that is using the power of C/C++ to find file sizes with a few methods I've found, it's also UTF-8 compatible and very fast.

You can try it: http://www.jobnik.net/files/PHP/php_filesize.zip

Usage:

methods:

0 - using GetFileAttributesEx

1 - using CreateFile

2 - using FindFirstFile

-1 - using stat64 (default and optional)

$fsize = php_filesize("filepath", $method_optional);

  • Returns file size in string type up to 9 PetaByte

Credits:

FileSize methods: Check the file-size without opening file in C++?

UTF-8 support: https://github.com/kenjiuno/php-wfio

jobnik
  • 11
  • 1
  • 3
1

For anyone who happens to be on a linux host, the easiest solution I found is to use:

exec("stat --format=\"%s\" \"$file\"");

This assumes no quotation marks or newlines in the file name and technically returns a string instead of a number I suppose, but it works well with this method to get a human readable file size.

The largest file I tested this with was about 3.6 GB.

Rapti
  • 1,760
  • 2
  • 14
  • 23
-1

To get the correct file size I often use this piece of code written by myself some months ago. My code uses: exec/com/stat where available. I know its limits, but it's a good starting point. The best idea is using filesize() on 64bit architecture.

<?php
  ######################################################################
  # Human size for files smaller or bigger than 2 GB on 32 bit Systems #
  # size.php - 1.3 - 21.09.2015 - Alessandro Marinuzzi - www.alecos.it #
  ######################################################################
  function showsize($file) {
    if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN') {
      if (class_exists("COM")) {
        $fsobj = new COM('Scripting.FileSystemObject');
        $f = $fsobj->GetFile(realpath($file));
        $size = $f->Size;
      } else {
        $size = trim(@exec("for %F in (\"" . $file . "\") do @echo %~zF"));
      }
    } elseif (PHP_OS == 'Darwin') {
      $size = trim(@exec("stat -f %z " . $file));
    } else {
      $size = trim(@exec("stat -c %s " . $file));
    }
    if ((!is_numeric($size)) || ($size < 0)) {
      $size = filesize($file);
    }
    if ($size < 1024) {
      echo $size . ' Byte';
    } elseif ($size < 1048576) {
      echo number_format(round($size / 1024, 2), 2) . ' KB';
    } elseif ($size < 1073741824) {
      echo number_format(round($size / 1048576, 2), 2) . ' MB';
    } elseif ($size < 1099511627776) {
      echo number_format(round($size / 1073741824, 2), 2) . ' GB';
    } elseif ($size < 1125899906842624) {
      echo number_format(round($size / 1099511627776, 2), 2) . ' TB';
    } elseif ($size < 1152921504606846976) {
      echo number_format(round($size / 1125899906842624, 2), 2) . ' PB';
    } elseif ($size < 1180591620717411303424) {
      echo number_format(round($size / 1152921504606846976, 2), 2) . ' EB';
    } elseif ($size < 1208925819614629174706176) {
      echo number_format(round($size / 1180591620717411303424, 2), 2) . ' ZB';
    } else {
      echo number_format(round($size / 1208925819614629174706176, 2), 2) . ' YB';
    }
  }
?>

<?php include("php/size.php"); ?>

<?php showsize("files/VeryBigFile.tar"); ?>

I hope this helps.

Alessandro
  • 771
  • 8
  • 21