0

I have an issue when building a slim (slim 4) response with a streamed content (a huge xlsx file content).

$fileHandler = \fopen(getenv('SHARED_FILES_PATH') . $filename, 'r');
if (!$fileHandler) {
    throw new \Exception('Unable to open file ' . getenv('SHARED_FILES_PATH') . $filename . ' for reading.');
}

$stream = GuzzleHttp\Psr7\Utils::streamFor($fileHandler);

// $this->response is Psr\Http\Message\ResponseInterface
$response = $this->response;
$response = $response->withHeader('Content-Disposition', 'attachment; filename="' . $filename . '"');
$response = $response->withHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
$response = $response->withBody($stream);

return $response;

The error: Fatal error: Uncaught RuntimeException: Unable to read from stream in /home/vincent/workspace/opco2i_applis/opco2i_portail/server/vendor/guzzlehttp/psr7/src/Stream.php on line 232

I have made some check and the file exists and is readable. If i do the following after the fopen call:

$contents = '';
while (!feof($fileHandler)) {
    $contents .= fread($fileHandler, 8192);
    break;
}
fclose($fileHandler);

var_dump($contents);die();

, i can read some content of my file.

Can you help me to find why guzzle stream cannot work in this case ?

chaillouvincent
  • 197
  • 1
  • 3
  • 17
  • Test printing the content of the stream, first. So, after the line `$stream = GuzzleHttp\Psr7\Utils::streamFor($fileHandler);`, add the lines `$streamContent = (string) $stream; var_dump($streamContent);` (or similar) and execute. It should call `GuzzleHttp\Psr7\Stream::__toString()` and correctly display the file content. If it doesn't, then I suppose its a problem with the file, or with the implementation of `GuzzleHttp\Psr7\Stream::__toString()` :-) If it does, then the problem lies in the next code lines involving the PSR-7 response. – PajuranCodes Mar 09 '21 at 18:03
  • Also, at least for testing purposes in the matter described by you, I would suggest to try the package [laminas-diactoros](https://docs.laminas.dev/laminas-diactoros/) instead of Guzzle. – PajuranCodes Mar 09 '21 at 18:05
  • According @dakis suggestions, i have dumped the streamed content and the content is correct (i can see the right content dumped). The issue occurs when i call $response->withBody($stream). The $response object is a GuzzleHttp\Psr7\Response instance. If i call var_dump($response);die(); before the return $response, the issue is not triggered. Maybe, i need to add some another headers to the response or specific options to stream ? – chaillouvincent Mar 09 '21 at 18:47
  • Please tell us - by updating your SO question, not in a comment - what exactly are you expecting to see on the client side when you're implementing the code snippet posted in the SO question. Also, it's not clear yet: You are "calling" a certain code line which raises the described error. Please update your SO question with: **a)** that code line; **b)** the whole error trace. PS: Just a supposition: the (next part of the) problem resides in the part of Guzzle code, where the `$response` is printed, e.g. emitted. – PajuranCodes Mar 09 '21 at 19:25

1 Answers1

0

After some tests, i have found the solution. I must use $response->getBody()->write($stream) instead of $response->withBody($stream);

$stream = GuzzleHttp\Psr7\Utils::streamFor($fileHandler);

// $this->response is Psr\Http\Message\ResponseInterface
$response = $this->response;
$response = $response->withHeader('Content-Disposition', 'attachment; filename="' . $filename . '"');
$response = $response->withHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
$response = $response->getBody()->write($stream);

return $response;
chaillouvincent
  • 197
  • 1
  • 3
  • 17