Nyholm / psr7

A super lightweight PSR-7 implementation

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Request getSize() returns null for php://input stream

odan opened this issue · comments

Environment:

PHP Version: 8.2
Package Versions:

  • Nyholm/psr7-server: 1.1.0
  • Nyholm/psr7: 1.8.1

I have observed an issue with the getSize() method implementation when using the php://input stream.

https://github.com/Nyholm/psr7-server/blob/1.1.0/src/ServerRequestCreator.php#L71

Here are the steps to reproduce the problem:

use Nyholm\Psr7\Factory\Psr17Factory;
use Nyholm\Psr7\ServerRequest;
use Nyholm\Psr7Server\ServerRequestCreator;

// Create a Nyholm PSR-7 request
$factory = new Psr17Factory();
$serverRequestCreator = new ServerRequestCreator($factory, $factory, $factory, $factory);
$request = $serverRequestCreator->fromGlobals();

// Attempt to get the size of the request body
$requestSize = $request->getBody()->getSize(); // NULL

Expected result:

When I send a JSON (application/json) request via POST, the $requestSize is expected to contain the size of the request body.

The only exception is when POST'ing a multipart/form-data. This is a typical behavior in PHP, because
PHP already reads the input stream into the $_POST variable. In this case, the body size would always be 0 or null.

Actual Behavior:

The getSize() method returns null, indicating that it cannot determine the size of the php://input stream.

The reason is that php://input resource / stream does not provide support for fstat. See here:

Workaround

// This works
$contents = (string)$request->getBody();
$realSize = strlen($contents);

I have also tested this behavior with other PSR-7 implementations, such as slim/psr7, and encountered the same issue.

This behavior impacts any application that relies on the accurate measurement of request body size, and it appears to be a general issue with PSR-7 implementations when using the php://input stream.

I'm unsure if this is an intentional behavior or a bug, so I'm reporting it here for further investigation.

Update. A possible fix would be to read the php://input and copy it into a php://memory resource.
This is much more memory efficient than passing a string.

Before:

return $this->fromArrays($server, $headers, $_COOKIE, $_GET, $post, $_FILES, \fopen('php://input', 'r') ?: null);

After:

$body = \fopen('php://memory', 'r+') ?: null;
stream_copy_to_stream(\fopen('php://input', 'r'), $body);

return $this->fromArrays($server, $headers, $_COOKIE, $_GET, $post, $_FILES, $body);

https://github.com/Nyholm/psr7-server/blob/1.1.0/src/ServerRequestCreator.php#L71