2015-03-21 19:30:11 -07:00
|
|
|
===============
|
|
|
|
Guzzle and PSR7
|
|
|
|
===============
|
|
|
|
|
|
|
|
|
|
|
|
HTTP Messages
|
|
|
|
-------------
|
2014-02-16 17:10:57 -08:00
|
|
|
|
|
|
|
Guzzle is an HTTP client that sends HTTP requests to a server and receives HTTP
|
|
|
|
responses. Both requests and responses are referred to as messages.
|
|
|
|
|
2015-03-21 19:30:11 -07:00
|
|
|
|
2014-02-16 17:10:57 -08:00
|
|
|
Headers
|
|
|
|
=======
|
|
|
|
|
2014-02-20 22:04:44 -08:00
|
|
|
Both request and response messages contain HTTP headers.
|
|
|
|
|
2015-03-21 19:30:11 -07:00
|
|
|
|
2014-02-20 22:04:44 -08:00
|
|
|
Complex Headers
|
|
|
|
---------------
|
|
|
|
|
|
|
|
Some headers contain additional key value pair information. For example, Link
|
|
|
|
headers contain a link and several key value pairs:
|
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
<http://foo.com>; rel="thing"; type="image/jpeg"
|
|
|
|
|
|
|
|
Guzzle provides a convenience feature that can be used to parse these types of
|
|
|
|
headers:
|
|
|
|
|
|
|
|
.. code-block:: php
|
|
|
|
|
|
|
|
use GuzzleHttp\Message\Request;
|
|
|
|
|
|
|
|
$request = new Request('GET', '/', [
|
|
|
|
'Link' => '<http:/.../front.jpeg>; rel="front"; type="image/jpeg"'
|
|
|
|
]);
|
|
|
|
|
|
|
|
$parsed = Request::parseHeader($request, 'Link');
|
2014-10-08 19:18:45 -07:00
|
|
|
var_export($parsed);
|
2014-02-20 22:04:44 -08:00
|
|
|
|
2014-10-08 19:18:45 -07:00
|
|
|
Will output:
|
|
|
|
|
|
|
|
.. code-block:: php
|
2014-02-20 22:04:44 -08:00
|
|
|
|
2014-10-08 19:18:45 -07:00
|
|
|
array (
|
|
|
|
0 =>
|
|
|
|
array (
|
|
|
|
0 => '<http:/.../front.jpeg>',
|
|
|
|
'rel' => 'front',
|
|
|
|
'type' => 'image/jpeg',
|
|
|
|
),
|
|
|
|
)
|
2014-02-20 22:04:44 -08:00
|
|
|
|
|
|
|
The result contains a hash of key value pairs. Header values that have no key
|
|
|
|
(i.e., the link) are indexed numerically while headers parts that form a key
|
|
|
|
value pair are added as a key value pair.
|
|
|
|
|
|
|
|
See :ref:`headers` for information on how the headers of a request and response
|
|
|
|
can be accessed and modified.
|
2014-02-16 17:10:57 -08:00
|
|
|
|
2015-03-21 19:30:11 -07:00
|
|
|
|
2014-02-16 17:10:57 -08:00
|
|
|
Body
|
|
|
|
====
|
|
|
|
|
|
|
|
Both request and response messages can contain a body.
|
|
|
|
|
|
|
|
You can check to see if a request or response has a body using the
|
|
|
|
``getBody()`` method:
|
|
|
|
|
|
|
|
.. code-block:: php
|
|
|
|
|
2014-02-16 20:10:19 -08:00
|
|
|
$response = GuzzleHttp\get('http://httpbin.org/get');
|
2014-02-16 17:10:57 -08:00
|
|
|
if ($response->getBody()) {
|
|
|
|
echo $response->getBody();
|
|
|
|
// JSON string: { ... }
|
|
|
|
}
|
|
|
|
|
|
|
|
The body used in request and response objects is a
|
|
|
|
``GuzzleHttp\Stream\StreamInterface``. This stream is used for both uploading
|
|
|
|
data and downloading data. Guzzle will, by default, store the body of a message
|
2014-05-04 17:06:53 -04:00
|
|
|
in a stream that uses PHP temp streams. When the size of the body exceeds
|
2014-02-16 17:10:57 -08:00
|
|
|
2 MB, the stream will automatically switch to storing data on disk rather than
|
|
|
|
in memory (protecting your application from memory exhaustion).
|
|
|
|
|
|
|
|
You can change the body used in a request or response using the ``setBody()``
|
|
|
|
method:
|
|
|
|
|
|
|
|
.. code-block:: php
|
|
|
|
|
|
|
|
use GuzzleHttp\Stream\Stream;
|
|
|
|
$request = $client->createRequest('PUT', 'http://httpbin.org/put');
|
|
|
|
$request->setBody(Stream::factory('foo'));
|
|
|
|
|
|
|
|
The easiest way to create a body for a request is using the static
|
|
|
|
``GuzzleHttp\Stream\Stream::factory()`` method. This method accepts various
|
|
|
|
inputs like strings, resources returned from ``fopen()``, and other
|
|
|
|
``GuzzleHttp\Stream\StreamInterface`` objects.
|
|
|
|
|
|
|
|
The body of a request or response can be cast to a string or you can read and
|
|
|
|
write bytes off of the stream as needed.
|
|
|
|
|
|
|
|
.. code-block:: php
|
|
|
|
|
|
|
|
use GuzzleHttp\Stream\Stream;
|
|
|
|
$request = $client->createRequest('PUT', 'http://httpbin.org/put', ['body' => 'testing...']);
|
|
|
|
|
|
|
|
echo $request->getBody()->read(4);
|
|
|
|
// test
|
|
|
|
echo $request->getBody()->read(4);
|
|
|
|
// ing.
|
|
|
|
echo $request->getBody()->read(1024);
|
|
|
|
// ..
|
|
|
|
var_export($request->eof());
|
|
|
|
// true
|
|
|
|
|
|
|
|
You can find out more about Guzzle stream objects in :doc:`streams`.
|
|
|
|
|
2015-03-21 19:30:11 -07:00
|
|
|
|
2014-02-16 17:10:57 -08:00
|
|
|
Requests
|
|
|
|
========
|
|
|
|
|
|
|
|
Requests are sent from a client to a server. Requests include the method to
|
|
|
|
be applied to a resource, the identifier of the resource, and the protocol
|
|
|
|
version to use.
|
|
|
|
|
|
|
|
Clients are used to create request messages. More precisely, clients use
|
|
|
|
a ``GuzzleHttp\Message\MessageFactoryInterface`` to create request messages.
|
|
|
|
You create requests with a client using the ``createRequest()`` method.
|
|
|
|
|
|
|
|
.. code-block:: php
|
|
|
|
|
2014-09-04 17:48:58 +03:00
|
|
|
// Create a request but don't send it immediately
|
2014-02-16 17:10:57 -08:00
|
|
|
$request = $client->createRequest('GET', 'http://httpbin.org/get');
|
|
|
|
|
2015-03-21 19:30:11 -07:00
|
|
|
|
2014-02-16 17:10:57 -08:00
|
|
|
Request Methods
|
|
|
|
---------------
|
|
|
|
|
|
|
|
When creating a request, you are expected to provide the HTTP method you wish
|
2014-05-04 17:06:53 -04:00
|
|
|
to perform. You can specify any method you'd like, including a custom method
|
2014-10-08 19:18:45 -07:00
|
|
|
that might not be part of RFC 7231 (like "MOVE").
|
2014-02-16 17:10:57 -08:00
|
|
|
|
|
|
|
.. code-block:: php
|
|
|
|
|
2014-02-17 17:37:20 -08:00
|
|
|
// Create a request using a completely custom HTTP method
|
2014-02-16 17:10:57 -08:00
|
|
|
$request = $client->createRequest('MOVE', 'http://httpbin.org/move', ['exceptions' => false]);
|
|
|
|
|
|
|
|
echo $request->getMethod();
|
|
|
|
// MOVE
|
|
|
|
|
|
|
|
$response = $client->send($request);
|
|
|
|
echo $response->getStatusCode();
|
|
|
|
// 405
|
|
|
|
|
|
|
|
You can create and send a request using methods on a client that map to the
|
|
|
|
HTTP method you wish to use.
|
|
|
|
|
2014-02-17 17:37:20 -08:00
|
|
|
:GET: ``$client->get('http://httpbin.org/get', [/** options **/])``
|
|
|
|
:POST: ``$client->post('http://httpbin.org/post', [/** options **/])``
|
|
|
|
:HEAD: ``$client->head('http://httpbin.org/get', [/** options **/])``
|
|
|
|
:PUT: ``$client->put('http://httpbin.org/put', [/** options **/])``
|
|
|
|
:DELETE: ``$client->delete('http://httpbin.org/delete', [/** options **/])``
|
|
|
|
:OPTIONS: ``$client->options('http://httpbin.org/get', [/** options **/])``
|
2014-03-13 10:58:32 -07:00
|
|
|
:PATCH: ``$client->patch('http://httpbin.org/put', [/** options **/])``
|
2014-02-16 17:10:57 -08:00
|
|
|
|
|
|
|
.. code-block:: php
|
|
|
|
|
|
|
|
$response = $client->patch('http://httpbin.org/patch', ['body' => 'content']);
|
|
|
|
|
2015-03-21 19:30:11 -07:00
|
|
|
|
2014-02-16 17:10:57 -08:00
|
|
|
Request URI
|
|
|
|
-----------
|
|
|
|
|
|
|
|
The resource you are requesting with an HTTP request is identified by the
|
|
|
|
path of the request, the query string, and the "Host" header of the request.
|
|
|
|
|
|
|
|
When creating a request, you can provide the entire resource URI as a URL.
|
|
|
|
|
|
|
|
.. code-block:: php
|
|
|
|
|
|
|
|
$response = $client->get('http://httbin.org/get?q=foo');
|
|
|
|
|
|
|
|
Using the above code, you will send a request that uses ``httpbin.org`` as
|
|
|
|
the Host header, sends the request over port 80, uses ``/get`` as the path,
|
|
|
|
and sends ``?q=foo`` as the query string. All of this is parsed automatically
|
|
|
|
from the provided URI.
|
|
|
|
|
|
|
|
Sometimes you don't know what the entire request will be when it is created.
|
|
|
|
In these cases, you can modify the request as needed before sending it using
|
|
|
|
the ``createRequest()`` method of the client and methods on the request that
|
|
|
|
allow you to change it.
|
|
|
|
|
|
|
|
.. code-block:: php
|
|
|
|
|
|
|
|
$request = $client->createRequest('GET', 'http://httbin.org');
|
|
|
|
|
|
|
|
You can change the path of the request using ``setPath()``:
|
|
|
|
|
|
|
|
.. code-block:: php
|
|
|
|
|
|
|
|
$request->setPath('/get');
|
|
|
|
echo $request->getPath();
|
|
|
|
// /get
|
|
|
|
echo $request->getUrl();
|
|
|
|
// http://httpbin.com/get
|
|
|
|
|
2015-03-21 19:30:11 -07:00
|
|
|
|
2014-02-16 17:10:57 -08:00
|
|
|
Scheme
|
|
|
|
~~~~~~
|
|
|
|
|
|
|
|
The `scheme <http://tools.ietf.org/html/rfc3986#section-3.1>`_ of a request
|
|
|
|
specifies the protocol to use when sending the request. When using Guzzle, the
|
|
|
|
scheme can be set to "http" or "https".
|
|
|
|
|
|
|
|
You can change the scheme of the request using the ``setScheme()`` method:
|
|
|
|
|
|
|
|
.. code-block:: php
|
|
|
|
|
2014-03-13 10:58:32 -07:00
|
|
|
$request = $client->createRequest('GET', 'http://httbin.org');
|
2014-02-16 17:10:57 -08:00
|
|
|
$request->setScheme('https');
|
|
|
|
echo $request->getScheme();
|
|
|
|
// https
|
|
|
|
echo $request->getUrl();
|
|
|
|
// https://httpbin.com/get
|
|
|
|
|
2015-03-21 19:30:11 -07:00
|
|
|
|
2014-02-16 17:10:57 -08:00
|
|
|
Port
|
|
|
|
~~~~
|
|
|
|
|
|
|
|
No port is necessary when using the "http" or "https" schemes, but you can
|
|
|
|
override the port using ``setPort()``. If you need to modify the port used with
|
|
|
|
the specified scheme from the default setting, then you must use the
|
|
|
|
``setPort()`` method.
|
|
|
|
|
|
|
|
.. code-block:: php
|
|
|
|
|
2014-03-13 10:58:32 -07:00
|
|
|
$request = $client->createRequest('GET', 'http://httbin.org');
|
2014-02-16 17:10:57 -08:00
|
|
|
$request->setPort(8080);
|
|
|
|
echo $request->getPort();
|
|
|
|
// 8080
|
|
|
|
echo $request->getUrl();
|
|
|
|
// https://httpbin.com:8080/get
|
|
|
|
|
|
|
|
// Set the port back to the default value for the scheme
|
|
|
|
$request->setPort(443);
|
|
|
|
echo $request->getUrl();
|
|
|
|
// https://httpbin.com/get
|
|
|
|
|
|
|
|
Query string
|
|
|
|
~~~~~~~~~~~~
|
|
|
|
|
2014-03-13 10:58:32 -07:00
|
|
|
|
|
|
|
|
2014-02-16 17:10:57 -08:00
|
|
|
|
|
|
|
Host
|
|
|
|
~~~~
|
|
|
|
|
|
|
|
You can change the host header of the request in a predictable way using the
|
|
|
|
``setHost()`` method of a request:
|
|
|
|
|
|
|
|
.. code-block:: php
|
|
|
|
|
|
|
|
$request->setHost('www.google.com');
|
|
|
|
echo $request->getHost();
|
|
|
|
// www.google.com
|
|
|
|
echo $request->getUrl();
|
|
|
|
// https://www.google.com/get?foo=bar&baz=bam
|
|
|
|
|
|
|
|
.. note::
|
|
|
|
|
|
|
|
The Host header can also be changed by modifying the Host header of a
|
|
|
|
request directly, but modifying the Host header directly could result in
|
|
|
|
sending a request to a different Host than what is specified in the Host
|
|
|
|
header (sometimes this is actually the desired behavior).
|
|
|
|
|
2015-03-21 19:30:11 -07:00
|
|
|
|
2014-02-16 17:10:57 -08:00
|
|
|
Resource
|
|
|
|
~~~~~~~~
|
|
|
|
|
|
|
|
You can use the ``getResource()`` method of a request to return the path and
|
|
|
|
query string of a request in a single string.
|
|
|
|
|
|
|
|
.. code-block:: php
|
|
|
|
|
|
|
|
$request = $client->createRequest('GET', 'http://httpbin.org/get?baz=bar');
|
|
|
|
echo $request->getResource();
|
|
|
|
// /get?baz=bar
|
|
|
|
|
2015-03-21 19:30:11 -07:00
|
|
|
|
2014-02-16 17:10:57 -08:00
|
|
|
Request Config
|
|
|
|
--------------
|
|
|
|
|
|
|
|
Request messages contain a configuration collection that can be used by
|
2014-10-12 18:27:08 -07:00
|
|
|
event listeners and HTTP handlers to modify how a request behaves or is
|
2014-02-16 17:10:57 -08:00
|
|
|
transferred over the wire. For example, many of the request options that are
|
|
|
|
specified when creating a request are actually set as config options that are
|
2014-10-12 18:27:08 -07:00
|
|
|
only acted upon by handlers and listeners when the request is sent.
|
2014-02-16 17:10:57 -08:00
|
|
|
|
|
|
|
You can get access to the request's config object using the ``getConfig()``
|
|
|
|
method of a request.
|
|
|
|
|
|
|
|
.. code-block:: php
|
|
|
|
|
|
|
|
$request = $client->createRequest('GET', '/');
|
|
|
|
$config = $request->getConfig();
|
|
|
|
|
2014-11-17 23:17:15 +00:00
|
|
|
The config object is a ``GuzzleHttp\Collection`` object that acts like
|
2014-02-16 17:10:57 -08:00
|
|
|
an associative array. You can grab values from the collection using array like
|
|
|
|
access. You can also modify and remove values using array like access.
|
|
|
|
|
|
|
|
.. code-block:: php
|
|
|
|
|
|
|
|
$config['foo'] = 'bar';
|
|
|
|
echo $config['foo'];
|
|
|
|
// bar
|
|
|
|
|
|
|
|
var_export(isset($config['foo']));
|
|
|
|
// true
|
|
|
|
|
|
|
|
unset($config['foo']);
|
|
|
|
var_export(isset($config['foo']));
|
|
|
|
// false
|
|
|
|
|
|
|
|
var_export($config['foo']);
|
|
|
|
// NULL
|
|
|
|
|
2014-10-12 18:27:08 -07:00
|
|
|
HTTP handlers and event listeners can expose additional customization options
|
2014-02-16 17:10:57 -08:00
|
|
|
through request config settings. For example, in order to specify custom cURL
|
2014-10-12 18:27:08 -07:00
|
|
|
options to the cURL handler, you need to specify an associative array in the
|
2014-02-16 17:10:57 -08:00
|
|
|
``curl`` ``config`` request option.
|
|
|
|
|
|
|
|
.. code-block:: php
|
|
|
|
|
|
|
|
$client->get('/', [
|
|
|
|
'config' => [
|
|
|
|
'curl' => [
|
|
|
|
CURLOPT_HTTPAUTH => CURLAUTH_NTLM,
|
|
|
|
CURLOPT_USERPWD => 'username:password'
|
|
|
|
]
|
|
|
|
]
|
|
|
|
]);
|
|
|
|
|
2014-10-12 18:27:08 -07:00
|
|
|
Consult the HTTP handlers and event listeners you are using to see if they
|
2014-02-16 17:10:57 -08:00
|
|
|
allow customization through request configuration options.
|
|
|
|
|
2015-03-21 19:30:11 -07:00
|
|
|
|
2014-02-16 17:10:57 -08:00
|
|
|
Event Emitter
|
|
|
|
-------------
|
|
|
|
|
2014-11-17 23:17:15 +00:00
|
|
|
Request objects implement ``GuzzleHttp\Event\HasEmitterInterface``, so they
|
2014-02-16 17:10:57 -08:00
|
|
|
have a method called ``getEmitter()`` that can be used to get an event emitter
|
|
|
|
used by the request. Any listener or subscriber attached to a request will only
|
|
|
|
be triggered for the lifecycle events of a specific request. Conversely, adding
|
|
|
|
an event listener or subscriber to a client will listen to all lifecycle events
|
|
|
|
of all requests created by the client.
|
|
|
|
|
|
|
|
See :doc:`events` for more information.
|
|
|
|
|
2015-03-21 19:30:11 -07:00
|
|
|
|
2014-02-16 17:10:57 -08:00
|
|
|
Responses
|
|
|
|
=========
|
|
|
|
|
|
|
|
Responses are the HTTP messages a client receives from a server after sending
|
|
|
|
an HTTP request message.
|
|
|
|
|
2015-03-21 19:30:11 -07:00
|
|
|
|
2014-02-16 17:10:57 -08:00
|
|
|
Start-Line
|
|
|
|
----------
|
|
|
|
|
|
|
|
The start-line of a response contains the protocol and protocol version,
|
|
|
|
status code, and reason phrase.
|
|
|
|
|
|
|
|
.. code-block:: php
|
|
|
|
|
2014-02-16 20:10:19 -08:00
|
|
|
$response = GuzzleHttp\get('http://httpbin.org/get');
|
2014-02-16 17:10:57 -08:00
|
|
|
echo $response->getStatusCode();
|
|
|
|
// 200
|
|
|
|
echo $response->getReasonPhrase();
|
|
|
|
// OK
|
|
|
|
echo $response->getProtocolVersion();
|
|
|
|
// 1.1
|
|
|
|
|
2015-03-21 19:30:11 -07:00
|
|
|
|
2014-02-16 17:10:57 -08:00
|
|
|
Body
|
|
|
|
----
|
|
|
|
|
|
|
|
As described earlier, you can get the body of a response using the
|
|
|
|
``getBody()`` method.
|
|
|
|
|
|
|
|
.. code-block:: php
|
|
|
|
|
|
|
|
if ($body = $response->getBody()) {
|
|
|
|
echo $body;
|
|
|
|
// Cast to a string: { ... }
|
|
|
|
$body->seek(0);
|
|
|
|
// Rewind the body
|
|
|
|
$body->read(1024);
|
|
|
|
// Read bytes of the body
|
|
|
|
}
|
|
|
|
|
|
|
|
When working with JSON responses, you can use the ``json()`` method of a
|
|
|
|
response:
|
|
|
|
|
|
|
|
.. code-block:: php
|
|
|
|
|
|
|
|
$json = $response->json();
|
|
|
|
|
|
|
|
.. note::
|
|
|
|
|
|
|
|
Guzzle uses the ``json_decode()`` method of PHP and uses arrays rather than
|
|
|
|
``stdClass`` objects for objects.
|
|
|
|
|
|
|
|
You can use the ``xml()`` method when working with XML data.
|
|
|
|
|
|
|
|
.. code-block:: php
|
|
|
|
|
|
|
|
$xml = $response->xml();
|
|
|
|
|
|
|
|
.. note::
|
|
|
|
|
|
|
|
Guzzle uses the ``SimpleXMLElement`` objects when converting response
|
|
|
|
bodies to XML.
|
|
|
|
|
2015-03-21 19:30:11 -07:00
|
|
|
|
|
|
|
Streams
|
|
|
|
-------
|
|
|
|
|
|
|
|
Guzzle uses stream objects to represent request and response message bodies.
|
|
|
|
These stream objects allow you to work with various types of data all using a
|
|
|
|
common interface.
|
|
|
|
|
|
|
|
HTTP messages consist of a start-line, headers, and a body. The body of an HTTP
|
|
|
|
message can be very small or extremely large. Attempting to represent the body
|
|
|
|
of a message as a string can easily consume more memory than intended because
|
|
|
|
the body must be stored completely in memory. Attempting to store the body of a
|
|
|
|
request or response in memory would preclude the use of that implementation from
|
|
|
|
being able to work with large message bodies. The StreamInterface is used in
|
|
|
|
order to hide the implementation details of where a stream of data is read from
|
|
|
|
or written to.
|
|
|
|
|
|
|
|
Guzzle's StreamInterface exposes several methods that enable streams to be read
|
|
|
|
from, written to, and traversed effectively.
|
|
|
|
|
|
|
|
Streams expose their capabilities using three methods: ``isReadable()``,
|
|
|
|
``isWritable()``, and ``isSeekable()``. These methods can be used by stream
|
|
|
|
collaborators to determine if a stream is capable of their requirements.
|
|
|
|
|
|
|
|
Each stream instance has various capabilities: they can be read-only,
|
|
|
|
write-only, read-write, allow arbitrary random access (seeking forwards or
|
|
|
|
backwards to any location), or only allow sequential access (for example in the
|
|
|
|
case of a socket or pipe).
|
|
|
|
|
|
|
|
|
|
|
|
Creating Streams
|
|
|
|
================
|
|
|
|
|
|
|
|
The best way to create a stream is using the static factory method,
|
|
|
|
``GuzzleHttp\Stream\Stream::factory()``. This factory accepts strings,
|
|
|
|
resources returned from ``fopen()``, an object that implements
|
|
|
|
``__toString()``, and an object that implements
|
|
|
|
``GuzzleHttp\Stream\StreamInterface``.
|
|
|
|
|
|
|
|
.. code-block:: php
|
|
|
|
|
|
|
|
use GuzzleHttp\Stream\Stream;
|
|
|
|
|
|
|
|
$stream = Stream::factory('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
|
|
|
|
|
|
|
|
|
|
|
|
Metadata
|
|
|
|
========
|
|
|
|
|
|
|
|
Guzzle streams expose stream metadata through the ``getMetadata()`` method.
|
|
|
|
This method provides the data you would retrieve when calling PHP's
|
|
|
|
`stream_get_meta_data() function <http://php.net/manual/en/function.stream-get-meta-data.php>`_,
|
|
|
|
and can optionally expose other custom data.
|
|
|
|
|
|
|
|
.. code-block:: php
|
|
|
|
|
|
|
|
use GuzzleHttp\Stream\Stream;
|
|
|
|
|
|
|
|
$resource = fopen('/path/to/file', 'r');
|
|
|
|
$stream = Stream::factory($resource);
|
|
|
|
echo $stream->getMetadata('uri');
|
|
|
|
// /path/to/file
|
|
|
|
var_export($stream->isReadable());
|
|
|
|
// true
|
|
|
|
var_export($stream->isWritable());
|
|
|
|
// false
|
|
|
|
var_export($stream->isSeekable());
|
|
|
|
// true
|
|
|
|
|
|
|
|
|
|
|
|
Stream Decorators
|
|
|
|
=================
|
|
|
|
|
|
|
|
With the small and focused interface, add custom functionality to streams is
|
|
|
|
very simple with stream decorators. Guzzle provides several built-in decorators
|
|
|
|
that provide additional stream functionality.
|
|
|
|
|
|
|
|
|
|
|
|
CachingStream
|
2014-02-16 17:10:57 -08:00
|
|
|
-------------
|
|
|
|
|
2015-03-21 19:30:11 -07:00
|
|
|
The CachingStream is used to allow seeking over previously read bytes on
|
|
|
|
non-seekable streams. This can be useful when transferring a non-seekable
|
|
|
|
entity body fails due to needing to rewind the stream (for example, resulting
|
|
|
|
from a redirect). Data that is read from the remote stream will be buffered in
|
|
|
|
a PHP temp stream so that previously read bytes are cached first in memory,
|
|
|
|
then on disk.
|
2014-02-16 17:10:57 -08:00
|
|
|
|
|
|
|
.. code-block:: php
|
|
|
|
|
2015-03-21 19:30:11 -07:00
|
|
|
use GuzzleHttp\Stream\Stream;
|
|
|
|
use GuzzleHttp\Stream\CachingStream;
|
|
|
|
|
|
|
|
$original = Stream::factory(fopen('http://www.google.com', 'r'));
|
|
|
|
$stream = new CachingStream($original);
|
|
|
|
|
|
|
|
$stream->read(1024);
|
|
|
|
echo $stream->tell();
|
|
|
|
// 1024
|
|
|
|
|
|
|
|
$stream->seek(0);
|
|
|
|
echo $stream->tell();
|
|
|
|
// 0
|
|
|
|
|
|
|
|
|
|
|
|
LimitStream
|
|
|
|
-----------
|
|
|
|
|
|
|
|
LimitStream can be used to read a subset or slice of an existing stream object.
|
|
|
|
This can be useful for breaking a large file into smaller pieces to be sent in
|
|
|
|
chunks (e.g. Amazon S3's multipart upload API).
|
|
|
|
|
|
|
|
.. code-block:: php
|
|
|
|
|
|
|
|
use GuzzleHttp\Stream\Stream;
|
|
|
|
use GuzzleHttp\Stream\LimitStream;
|
|
|
|
|
|
|
|
$original = Stream::factory(fopen('/tmp/test.txt', 'r+'));
|
|
|
|
echo $original->getSize();
|
|
|
|
// >>> 1048576
|
|
|
|
|
|
|
|
// Limit the size of the body to 1024 bytes and start reading from byte 2048
|
|
|
|
$stream = new LimitStream($original, 1024, 2048);
|
|
|
|
echo $stream->getSize();
|
|
|
|
// >>> 1024
|
|
|
|
echo $stream->tell();
|
|
|
|
// >>> 0
|
|
|
|
|
|
|
|
|
|
|
|
NoSeekStream
|
|
|
|
------------
|
|
|
|
|
|
|
|
NoSeekStream wraps a stream and does not allow seeking.
|
|
|
|
|
|
|
|
.. code-block:: php
|
|
|
|
|
|
|
|
use GuzzleHttp\Stream\Stream;
|
|
|
|
use GuzzleHttp\Stream\LimitStream;
|
|
|
|
|
|
|
|
$original = Stream::factory('foo');
|
|
|
|
$noSeek = new NoSeekStream($original);
|
|
|
|
|
|
|
|
echo $noSeek->read(3);
|
|
|
|
// foo
|
|
|
|
var_export($noSeek->isSeekable());
|
|
|
|
// false
|
|
|
|
$noSeek->seek(0);
|
|
|
|
var_export($noSeek->read(3));
|
|
|
|
// NULL
|
|
|
|
|
|
|
|
|
|
|
|
Creating Custom Decorators
|
|
|
|
--------------------------
|
|
|
|
|
|
|
|
Creating a stream decorator is very easy thanks to the
|
|
|
|
``GuzzleHttp\Stream\StreamDecoratorTrait``. This trait provides methods that
|
|
|
|
implement ``GuzzleHttp\Stream\StreamInterface`` by proxying to an underlying
|
|
|
|
stream. Just ``use`` the ``StreamDecoratorTrait`` and implement your custom
|
|
|
|
methods.
|
|
|
|
|
|
|
|
For example, let's say we wanted to call a specific function each time the last
|
|
|
|
byte is read from a stream. This could be implemented by overriding the
|
|
|
|
``read()`` method.
|
|
|
|
|
|
|
|
.. code-block:: php
|
|
|
|
|
|
|
|
use GuzzleHttp\Stream\StreamDecoratorTrait;
|
|
|
|
|
|
|
|
class EofCallbackStream implements StreamInterface
|
|
|
|
{
|
|
|
|
use StreamDecoratorTrait;
|
|
|
|
|
|
|
|
private $callback;
|
|
|
|
|
|
|
|
public function __construct(StreamInterface $stream, callable $callback)
|
|
|
|
{
|
|
|
|
$this->stream = $stream;
|
|
|
|
$this->callback = $callback;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function read($length)
|
|
|
|
{
|
|
|
|
$result = $this->stream->read($length);
|
|
|
|
|
|
|
|
// Invoke the callback when EOF is hit.
|
|
|
|
if ($this->eof()) {
|
|
|
|
call_user_func($this->callback);
|
|
|
|
}
|
|
|
|
|
|
|
|
return $result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
This decorator could be added to any existing stream and used like so:
|
|
|
|
|
|
|
|
.. code-block:: php
|
|
|
|
|
|
|
|
use GuzzleHttp\Stream\Stream;
|
2014-02-16 17:10:57 -08:00
|
|
|
|
2015-03-21 19:30:11 -07:00
|
|
|
$original = Stream::factory('foo');
|
|
|
|
$eofStream = new EofCallbackStream($original, function () {
|
|
|
|
echo 'EOF!';
|
|
|
|
});
|
|
|
|
|
|
|
|
$eofStream->read(2);
|
|
|
|
$eofStream->read(1);
|
|
|
|
// echoes "EOF!"
|
|
|
|
$eofStream->seek(0);
|
|
|
|
$eofStream->read(3);
|
|
|
|
// echoes "EOF!"
|