Guzzle y PSR-7

Guzzle utiliza PSR-7 como interfaz de mensajes HTTP. Esto permite a Guzzle trabajar con cualquier otra biblioteca que utilice interfaces de mensajes PSR-7.

Guzzle es un cliente HTTP que envía peticiones HTTP a un servidor y recibe respuestas HTTP. Tanto las peticiones como las respuestas se denominan mensajes.

Guzzle depende del paquete guzzlehttp/psr7 Composer para su implementación de mensajes de PSR-7.

Puedes crear una petición usando la clase GuzzleHttp\Psr7\Request:

use GuzzleHttp\Psr7\Request;

$request = new Request('GET', 'http://httpbin.org/get');

// You can provide other optional constructor arguments.
$headers = ['X-Foo' => 'Bar'];
$body = 'hello!';
$request = new Request('PUT', 'http://httpbin.org/put', $headers, $body);

Puedes crear una respuesta usando la clase GuzzleHttp\Psr7\Response:

use GuzzleHttp\Psr7\Response;

// The constructor requires no arguments.
$response = new Response();
echo $response->getStatusCode(); // 200
echo $response->getProtocolVersion(); // 1.1

// You can supply any number of optional arguments.
$status = 200;
$headers = ['X-Foo' => 'Bar'];
$body = 'hello!';
$protocol = '1.1';
$response = new Response($status, $headers, $body, $protocol);

Encabezados

Tanto los mensajes de solicitud como los de respuesta contienen cabeceras HTTP.

Acceso a los encabezados

Puedes comprobar si una petición o respuesta tiene una cabecera específica utilizando el método hasHeader().

use GuzzleHttp\Psr7;

$request = new Psr7\Request('GET', '/', ['X-Foo' => 'bar']);

if ($request->hasHeader('X-Foo')) {
    echo 'It is there';
}

Puedes recuperar todos los valores de la cabecera como una matriz de cadenas utilizando getHeader().

$request->getHeader('X-Foo'); // ['bar']

// Retrieving a missing header returns an empty array.
$request->getHeader('X-Bar'); // []

Puedes iterar sobre las cabeceras de un mensaje utilizando el método getHeaders().

foreach ($request->getHeaders() as $name => $values) {
    echo $name . ': ' . implode(', ', $values) . "\r\n";
}

Encabezados complejos

Algunas cabeceras contienen información adicional de pares de valores clave. Por ejemplo, las cabeceras Link contienen un enlace y varios pares de valores clave:

<http://foo.com>; rel="thing"; type="image/jpeg"

Guzzle proporciona una función práctica que puede utilizarse para analizar este tipo de cabeceras:

use GuzzleHttp\Psr7;

$request = new Psr7\Request('GET', '/', [
    'Link' => '<http:/.../front.jpeg>; rel="front"; type="image/jpeg"'
]);

$parsed = Psr7\Header::parse($request->getHeader('Link'));
var_export($parsed);

La salida de la voluntad:

array (
  0 =>
  array (
    0 => '<http:/.../front.jpeg>',
    'rel' => 'front',
    'type' => 'image/jpeg',
  ),
)

El resultado contiene un hash de pares clave-valor. Los valores de las cabeceras que no tienen clave (es decir, el enlace) se indexan numéricamente mientras que las partes de las cabeceras que forman un par clave se añaden como un par clave-valor.

Body

Tanto los mensajes de solicitud como los de respuesta pueden contener un cuerpo.

Puedes recuperar el cuerpo de un mensaje utilizando el método getBody():

$response = GuzzleHttp\get('http://httpbin.org/get');
echo $response->getBody();
// JSON string: { ... }

El cuerpo utilizado en los objetos de petición y respuesta es un Psr\Http\Message\StreamInterface. Este flujo se utiliza tanto para subir datos como para descargarlos. Guzzle, por defecto, almacenará el cuerpo de un mensaje en un flujo que utiliza los flujos temporales de PHP. Cuando el tamaño del cuerpo supera los 2 MB, el flujo cambiará automáticamente para almacenar los datos en el disco en lugar de en la memoria (protegiendo su aplicación del agotamiento de la memoria).

La forma más sencilla de crear un cuerpo para un mensaje es utilizando el método streamFor de la clase GuzzleHttp\Psr7\Utils -- Utils::streamFor. Este método acepta cadenas, recursos callables, iteradores, otros streamables, y devuelve una instancia de Psr\Http\Message\StreamInterface.

El cuerpo de una solicitud o de una respuesta se puede convertir en una cadena o se pueden leer y escribir bytes del flujo según sea necesario.

use GuzzleHttp\Stream\Stream;
$response = $client->request('GET', 'http://httpbin.org/get');

echo $response->getBody()->read(4);
echo $response->getBody()->read(4);
echo $response->getBody()->read(1024);
var_export($response->eof());

Peticiones

Las solicitudes se envían desde un cliente a un servidor. Las solicitudes incluyen el método que aplicar a un recurso, el identificador del recurso y la versión del protocolo a utilizar.

Métodos de solicitud

Al crear una solicitud, se espera que proporcione el método HTTP que desea para realizarla. Puede especificar cualquier método que desee, incluyendo un método personalizado que no forme parte del RFC 7231 (como "MOVE").

// Create a request using a completely custom HTTP method
$request = new \GuzzleHttp\Psr7\Request('MOVE', 'http://httpbin.org/move');

echo $request->getMethod();
// MOVE

Puede crear y enviar una solicitud utilizando métodos en un cliente que se asignan al método HTTP que desea utilizar.

GET
$client->get('http://httpbin.org/get', [/** options **/])
POST
$client->post('http://httpbin.org/post', [/** options **/])
CABEZA
$client->head('http://httpbin.org/get', [/** options **/])
PUT
$client->put('http://httpbin.org/put', [/** options **/])
DELETE
$client->delete('http://httpbin.org/delete', [/** options **/])
OPCIONES
$client->options('http://httpbin.org/get', [/** options **/])
PATCH
$client->patch('http://httpbin.org/put', [/** options **/])

Por ejemplo:

$response = $client->patch('http://httpbin.org/patch', ['body' => 'content']);

URI de solicitud

El URI de la petición está representado por un objeto Psr\Http\Message\UriInterface. Guzzle proporciona una implementación de esta interfaz utilizando el objeto GuzzleHttp\Psr7\Uri.

Al crear una solicitud, puede proporcionar el URI como una cadena o una instancia de Psr\Http\Message\UriInterface.

$response = $client->request('GET', 'http://httpbin.org/get?q=foo');

Esquema

El esquema de una solicitud especifica el protocolo a utilizar cuando se envía la solicitud. Cuando se utiliza Guzzle, el esquema puede establecerse como "http" o "https".

$request = new Request('GET', 'http://httpbin.org');
echo $request->getUri()->getScheme(); // http
echo $request->getUri(); // http://httpbin.org

Host

El host es accesible mediante la URI que posee la solicitud o accediendo a la cabecera Host.

$request = new Request('GET', 'http://httpbin.org');
echo $request->getUri()->getHost(); // httpbin.org
echo $request->getHeader('Host'); // httpbin.org

Port

No es necesario ningún puerto cuando se utilizan los esquemas "http" o "https".

$request = new Request('GET', 'http://httpbin.org:8080');
echo $request->getUri()->getPort(); // 8080
echo $request->getUri(); // http://httpbin.org:8080

Path

La ruta de una solicitud es accesible a través del objeto URI.

$request = new Request('GET', 'http://httpbin.org/get');
echo $request->getUri()->getPath(); // /get

El contenido de la ruta se filtrará automáticamente para garantizar que sólo caracteres permitidos estén presentes en la ruta. Los caracteres no permitidos en la ruta se codificará porcentualmente de acuerdo con RFC 3986 sección 3.3

Cadena de consulta

Se puede acceder a la cadena de consulta de una solicitud mediante la función getQuery() del objeto URI que posee la solicitud.

$request = new Request('GET', 'http://httpbin.org/?foo=bar');
echo $request->getUri()->getQuery(); // foo=bar

El contenido de la cadena de consulta se filtrará automáticamente para garantizar que sólo estén presentes los caracteres permitidos en la cadena de consulta. Cualquier carácter que no están permitidos en la cadena de consulta serán codificados en porcentaje de acuerdo con RFC 3986 sección 3.4

Respuestas

Las respuestas son los mensajes HTTP que un cliente recibe de un servidor después de enviar un mensaje de solicitud HTTP.

Línea de inicio

La línea de inicio de una respuesta contiene el protocolo y la versión del protocolo, el código de estado y la frase de motivo.

$client = new \GuzzleHttp\Client();
$response = $client->request('GET', 'http://httpbin.org/get');

echo $response->getStatusCode(); // 200
echo $response->getReasonPhrase(); // OK
echo $response->getProtocolVersion(); // 1.1

Body

Como se ha descrito anteriormente, puedes obtener el cuerpo de una respuesta utilizando el método getBody().

$body = $response->getBody();
echo $body;
// Cast to a string: { ... }
$body->seek(0);
// Rewind the body
$body->read(1024);
// Read bytes of the body

Corrientes

Guzzle utiliza objetos de flujo PSR-7 para representar los cuerpos de los mensajes de solicitud y respuesta respuesta. Estos objetos de flujo le permiten trabajar con varios tipos de datos, todos utilizando una interfaz común.

Los mensajes HTTP constan de una línea de inicio, cabeceras y un cuerpo. El cuerpo de un mensaje HTTP puede ser muy pequeño o extremadamente grande. Intentar representar el cuerpo de un mensaje como una cadena puede consumir fácilmente más memoria de la prevista porque el cuerpo debe ser almacenado completamente en la memoria. El intento de almacenar el cuerpo de una solicitud o respuesta en memoria impediría el uso de esa implementación de poder trabajar con cuerpos de mensajes grandes. La StreamInterface se utiliza para para ocultar los detalles de implementación de dónde se lee o escribe un flujo de datos. o se escribe en él.

El PSR-7 Psr\Http\Message\StreamInterface expone varios métodos que permiten leer, escribir y recorrer flujos de forma efectiva.

Los flujos exponen sus capacidades mediante tres métodos: isReadable(), isWritable(), y isSeekable(). Estos métodos pueden ser utilizados por los colaboradores del flujo para determinar si un flujo es capaz de cumplir sus requisitos.

Cada instancia de flujo tiene varias capacidades: pueden ser de sólo lectura de sólo escritura, de lectura-escritura, permitir un acceso aleatorio arbitrario (buscar hacia adelante o hacia atrás a cualquier lugar), o permitir sólo el acceso secuencial (por ejemplo en el caso de un socket o una tubería).

Guzzle utiliza el paquete guzzlehttp/psr7 para proporcionar soporte de flujos. Más información en información sobre el uso de flujos, la creación de flujos, la conversión de flujos a recursos PHP y los decoradores de flujos se puede encontrar en la página Documentación de Guzzle PSR-7.

Creación de Streams

La mejor manera de crear un flujo es usando el método GuzzleHttp\Psr7\Utils::streamFor ...>. Este método acepta cadenas, recursos devueltos por fopen(), un objeto que implemente __toString(), iteradores, callables e instancias de Psr\Http\Message\StreamInterface.

use GuzzleHttp\Psr7;

$stream = Psr7\Utils::streamFor('string data');
echo $stream;
// string data
echo $stream->read(3);
// str
echo $stream->getContents();
// ing data
var_export($stream->eof());
// true
var_export($stream->tell());
// 11

Se pueden crear flujos a partir de iteradores. El iterador puede producir cualquier número de bytes por iteración. Cualquier exceso de bytes devueltos por el iterador que no hayan sido solicitado por un consumidor de flujos será almacenado en el buffer hasta una lectura posterior.

use GuzzleHttp\Psr7;

$generator = function ($bytes) {
    for ($i = 0; $i < $bytes; $i++) {
        yield '.';
    }
};

$iter = $generator(1024);
$stream = Psr7\Utils::streamFor($iter);
echo $stream->read(3); // ...

Metadatos

Los flujos exponen los metadatos del flujo a través del método getMetadata(). Este método proporciona los datos que usted recuperaría al llamar al método de PHP función stream_get_meta_data(), y opcionalmente puede exponer otros datos personalizados.

use GuzzleHttp\Psr7;

$resource = Psr7\Utils::tryFopen('/path/to/file', 'r');
$stream = Psr7\Utils::streamFor($resource);
echo $stream->getMetadata('uri');
// /path/to/file
var_export($stream->isReadable());
// true
var_export($stream->isWritable());
// false
var_export($stream->isSeekable());
// true

Decoradores de arroyos

Añadir funcionalidad personalizada a los flujos es muy sencillo con los decoradores de flujos. Guzzle proporciona varios decoradores incorporados que proporcionan funcionalidad adicional a los flujos adicionales.