Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Problem with files >2 GB #167

Closed
Ivan-Perez opened this issue Oct 16, 2017 · 7 comments
Closed

Problem with files >2 GB #167

Ivan-Perez opened this issue Oct 16, 2017 · 7 comments

Comments

@Ivan-Perez
Copy link

Stream::getSize function is not working when opening files over 2 GB in size. I get a negative number for files between 2 and 4 GB. I'm on a 32-bit machine, so PHP internally uses a 32 bit signed integer type. Is there any workaround to get the real size?

Thanks!

@g105b
Copy link

g105b commented Nov 6, 2017

Please take a look into the output of phpinfo(), most importantly upload_max_filesize and post_max_size. It might be that your php.ini is set to only process a certain maximum filesize.

Good to rule this out before looking into a Guzzle bug, and if you are looking to file a bug we will need to know more information from you, including how you can replicate the issue.

@sagikazarmark
Copy link
Member

@g105b thanks, but it has nothing to do with upload_max_filesize or post_max_size. In this case there is no upload, only download. The problem is (as outlined by the issue reporter) the 32 bit machine.

The biggest integer you can represent in 32 bits (in two's complements): 2147483647
2 GB in bytes: 2147483648

Sorry for not answering earlier, I don't have a clear answer at this time.

One rough idea: you could count the bytes read manually in a stream wrapper as you read from the stream. When you overflow the integer limit, PHP will automatically cast the value to float for you, so unless you cast it to integer manually, you should get the real value.

@l0gicgate
Copy link

The following method is for calculating file size bigger than 2gb on a 32-bit instance.

This could possibly be adapted to Stream::getSize().

<?php
/**
 * Filesize method that works with files >2GB on 32bit PHP
 * 
 * @link http://php.net/manual/en/function.filesize.php#113457
 * @param string $file Path to file
 * @return int|float Size of file
 */
function realFileSize($file)
{
    $fp = fopen($file, 'r');
    
    $pos = 0;
    $size = 1073741824;
    fseek($fp, 0, SEEK_SET);
    while ($size > 1)
    {
        fseek($fp, $size, SEEK_CUR);
        if (fgetc($fp) === false)
        {
            fseek($fp, -$size, SEEK_CUR);
            $size = (int)($size / 2);
        }
        else
        {
            fseek($fp, -1, SEEK_CUR);
            $pos += $size;
        }
    }
    
    while (fgetc($fp) !== false)  $pos++;
    
    fclose($fp);
    
    return $pos;
}

@sagikazarmark
Copy link
Member

Sorry, but this solution is rather a workaround and I would rather not add it to the core library. But the problem is searchable, so you can find it on the issue tracker. It's also trivial to turn this into a Stream decorator for easier usage.

@Tobion
Copy link
Member

Tobion commented Jun 6, 2019

Also according to PSR-7 https://www.php-fig.org/psr/psr-7/ getSize must return an int. So we cannot return a float on 32 bit machines as it would conflict with the contract.

@Ivan-Perez
Copy link
Author

Ivan-Perez commented Jun 6, 2019

    /**
     * Get the size of the stream if known.
     *
     * @return int|null Returns the size in bytes if known, or null if unknown.
     */
    public function getSize();

Yep, it should return an int. What about returning null in this case, as the size is unknown (not computable)? At least you wouldn't get a wrong size.

@Tobion
Copy link
Member

Tobion commented Jun 6, 2019

Yes makes sense, Would be happy to see a PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants