Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP x86 How to get filesize of > 2 GB file without external program?

Tags:

I need to get the file size of a file over 2 GB in size. (testing on 4.6 GB file). Is there any way to do this without an external program?

Current status:

  • filesize(), stat() and fseek() fails
  • fread() and feof() works

There is a possibility to get the file size by reading the file content (extremely slow!).

$size = (float) 0; $chunksize = 1024 * 1024; while (!feof($fp)) {     fread($fp, $chunksize);     $size += (float) $chunksize; } return $size; 

I know how to get it on 64-bit platforms (using fseek($fp, 0, SEEK_END) and ftell()), but I need solution for 32-bit platform.


Solution: I've started open-source project for this.

Big File Tools

Big File Tools is a collection of hacks that are needed to manipulate files over 2 GB in PHP (even on 32-bit systems).

  • answer: https://stackoverflow.com/a/35233556/631369
  • github: https://github.com/jkuchar/BigFileTools
like image 560
Honza Kuchař Avatar asked Mar 31 '11 14:03

Honza Kuchař


2 Answers

Here's one possible method:

It first attempts to use a platform-appropriate shell command (Windows shell substitution modifiers or *nix/Mac stat command). If that fails, it tries COM (if on Windows), and finally falls back to filesize().

/*  * This software may be modified and distributed under the terms  * of the MIT license.  */  function filesize64($file) {     static $iswin;     if (!isset($iswin)) {         $iswin = (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN');     }      static $exec_works;     if (!isset($exec_works)) {         $exec_works = (function_exists('exec') && !ini_get('safe_mode') && @exec('echo EXEC') == 'EXEC');     }      // try a shell command     if ($exec_works) {         $cmd = ($iswin) ? "for %F in (\"$file\") do @echo %~zF" : "stat -c%s \"$file\"";         @exec($cmd, $output);         if (is_array($output) && ctype_digit($size = trim(implode("\n", $output)))) {             return $size;         }     }      // try the Windows COM interface     if ($iswin && class_exists("COM")) {         try {             $fsobj = new COM('Scripting.FileSystemObject');             $f = $fsobj->GetFile( realpath($file) );             $size = $f->Size;         } catch (Exception $e) {             $size = null;         }         if (ctype_digit($size)) {             return $size;         }     }      // if all else fails     return filesize($file); } 
like image 185
Unsigned Avatar answered Oct 17 '22 17:10

Unsigned


I've started project called Big File Tools. It is proven to work on Linux, Mac and Windows (even 32-bit variants). It provides byte-precise results even for huge files (>4GB). Internally it uses brick/math - arbitrary-precision arithmetic library.

Install it using composer.

composer install jkuchar/BigFileTools 

and use it:

<?php $file = BigFileTools\BigFileTools::createDefault()->getFile(__FILE__); echo $file->getSize() . " bytes\n"; 

Result is BigInteger so you can compute with results

$sizeInBytes = $file->getSize(); $sizeInMegabytes = $sizeInBytes->toBigDecimal()->dividedBy(1024*1024, 2, \Brick\Math\RoundingMode::HALF_DOWN);     echo "Size is $sizeInMegabytes megabytes\n"; 

Big File Tools internally uses drivers to reliably determine exact file size on all platforms. Here is list of available drivers (updated 2016-02-05)

| Driver           | Time (s) ↓          | Runtime requirements | Platform  | ---------------  | ------------------- | --------------       | --------- | CurlDriver       | 0.00045299530029297 | CURL extension       | - | NativeSeekDriver | 0.00052094459533691 | -                    | - | ComDriver        | 0.0031449794769287  | COM+.NET extension   | Windows only | ExecDriver       | 0.042937040328979   | exec() enabled       | Windows, Linux, OS X | NativeRead       | 2.7670161724091     | -                    | - 

You can use BigFileTools with any of these or fastest available is chosen by default (BigFileTools::createDefault())

 use BigFileTools\BigFileTools;  use BigFileTools\Driver;  $bigFileTools = new BigFileTools(new Driver\CurlDriver()); 
like image 28
Honza Kuchař Avatar answered Oct 17 '22 17:10

Honza Kuchař