Guzzle: RuntimeException when providing Google Cloud Storage stream wrapper resource as sink option

Created on 18 Sep 2017  路  4Comments  路  Source: guzzle/guzzle

My PHP project is deployed on Google App Engine PHP Standard Environment. I am trying to download remote files and store them in Google Cloud Storage buckets. In order to support potentially very large files, I am providing a writable file stream resource to Guzzle in the 'sink' request option so that I don't have to keep the full file in memory before writing it to Google Cloud Storage. Local filesystem is not writable on Google App Engine Standard Environment. So I can't write the downloaded file to a temporary local file before copying it to Google Cloud Storage.

| Q | A
| ------------ | ---
| Bug? | yes
| New Feature? | no
| Version | 6.3.0

Actual Behavior

RuntimeException: Unable to seek to stream position 0 with whence 0

image

image

Expected Behavior

Downloaded file should be successfully written to Google Cloud Storage bucket without raising any exception.

Steps to Reproduce

  • Create a new composer project and add guzzle as dependency.
  • Create a new project on Google Cloud Platform.
  • Create a new Google Cloud Storage bucket in this project.
  • Paste the following code snippet in one of your PHP files, after replacing the with actual values.
use GuzzleHttp\Client;

$filePath = 'gs://<bucket name>/<object name to write>';
$resource = fopen($filePath, 'w');
$client->request('GET', '<URL of a publicly accessible file>', ['sink' => $resource]);
  • Deploy your project on a Google App Engine (PHP Standard Environment) instance in the same project so that it has access to the Cloud Storage bucket.
  • Access a URL in your deployment that will trigger the above provided code snippet.

Possible Cause and Solution

Here are my findings so far. The "gs://" stream wrapper provided by Google on App Engine to access Cloud Storage supports the "fseek" function only on files opened in read mode, as noted here. In my use case, I have to open the file in write mode so that Guzzle can write the downloaded file to it. That's why exception occurs at this line

Can someone please provide more insight into why we are seeking to position 0 of sink resource? What would be the best approach to achieve my desired behavior i.e. stream a remote file directly to a Google Cloud Storage object?

Also, if I check on the Cloud Storage console, the file is successfully stored there. File size is same as the source. So, while a more "correct" solution is figured out, is it safe for me to just comment out the problematic seek() call on line 216 of StreamHandler.php to avoid this exception?

lifecyclstale

All 4 comments

Looks like not as a bug, but as a feature "to rewind the destination stream to the beginning after copying". In the old code I see a proof of this.

BTW, I haven't found anything about this in the docs (web and phpDoc).

@mtdowling, @sagikazarmark, do you know why this ->seek(0) is there?

IMO I would deprecate this feature and remove it in 7.0.

ran into this as well, doing a simple POST to a web service and having RequestOptions::SINK => STDOUT. i am not sure what changed as it worked at some point and now does not, even though we did not update guzzle in between. maybe php versions?

anyways, rewrote to

$stream = $response->getBody();
while (!$stream->eof()) {
    $output->write($stream->read(100000));
}

which seems to work fine.

This issue has been automatically marked as stale because it has not had recent activity. It will be closed after 2 weeks if no further activity occurs. Thank you for your contributions.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

tbergeron picture tbergeron  路  4Comments

BentCoder picture BentCoder  路  3Comments

pionl picture pionl  路  4Comments

benswinburne picture benswinburne  路  3Comments

Anan5a picture Anan5a  路  4Comments