Seb Bizeul
Seb Bizeul

Reputation: 1006

Emit a response with PSR-7

I'm trying to understand how PSR-7 works and I get stuck! Here is my code:

$app->get('/', function () {
    $stream = new Stream('php://memory', 'rw');
    $stream->write('Foo');
    $response = (new Response())
        ->withHeader('Content-Type', 'text/html')
        ->withBody($stream);
});

My Response object is build but now I want to send it... How PSR-7 send response? Do I need serialization? I probably missed one thing...

Upvotes: 6

Views: 4282

Answers (2)

user7941334
user7941334

Reputation:

Just as a completion, even if the question is more than two years old:

A response is a HTTP message sent by a server to a client, as result of a request from the client to the server.

The client expects a string as message, composed of:

  • a "status line" (in the form HTTP/<protocol-version> <status-code> <reason-phrase>);
  • a list of headers (each in the form "<header-name>: <comma-separ.-header-values>");
  • an empty line;
  • a message body (a string).

And it looks like this (see PSR-7):

HTTP/1.1 200 OK
Content-Type: text/html
vary: Accept-Encoding

This is the response body

In order to emit a response, one must actually perform three operations:

  1. Send the "status line" to the client (using the header() PHP function).
  2. Send the headers list to the client (dito).
  3. Output the message body.

The tricky part is represented by the third operation. An instance of a class implementing the ResponseInterface contains a stream object as the message body. And this object must be converted to a string and printed. The task can be easily accomplished, because the stream is an instance of a class implementing StreamInterface, which, in turn, enforces the definition of a magical method __toString().

So, by performing the first two steps and applying an output function (echo, print_r, etc) to the result of the getBody() method of the response instance, the emitting process is complete.

<?php
if (headers_sent()) {
    throw new RuntimeException('Headers were already sent. The response could not be emitted!');
}

// Step 1: Send the "status line".
$statusLine = sprintf('HTTP/%s %s %s'
        , $response->getProtocolVersion()
        , $response->getStatusCode()
        , $response->getReasonPhrase()
);
header($statusLine, TRUE); /* The header replaces a previous similar header. */

// Step 2: Send the response headers from the headers list.
foreach ($response->getHeaders() as $name => $values) {
    $responseHeader = sprintf('%s: %s'
            , $name
            , $response->getHeaderLine($name)
    );
    header($responseHeader, FALSE); /* The header doesn't replace a previous similar header. */
}

// Step 3: Output the message body.
echo $response->getBody();
exit();

P.S: For large amounts of data it's better to use the php://temp stream instead of php://memory. Here is the reason.

Upvotes: 9

marcosh
marcosh

Reputation: 9008

Psr-7 just models http messages. It does not have functionalities to send responses. You need to use another library that consumes PSR-7 messages. You could have a look at zend stratigility or something of the like

Upvotes: 6

Related Questions