Guzzle и PSR-7

Guzzle използва PSR-7 като интерфейс за HTTP съобщения. Това позволява на Guzzle да работи с всяка друга библиотека, която използва интерфейси за съобщения PSR-7.

Guzzle е HTTP клиент, който изпраща HTTP заявки към сървър и получава HTTP отговори. И заявките, и отговорите се наричат съобщения.

Guzzle разчита на пакета guzzlehttp/psr7 Composer за своята имплементация на PSR-7 за съобщения.

Можете да създадете заявка, като използвате класа 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);

Можете да създадете отговор, като използвате класа 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);

Заглавия

Съобщенията за заявка и отговор съдържат HTTP заглавия.

Достъп до заглавията

Можете да проверите дали дадена заявка или отговор има определен хедър, като използвате метода hasHeader().

use GuzzleHttp\Psr7;

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

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

Можете да извлечете всички стойности на заглавието като масив от низове, като използвате getHeader().

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

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

Можете да прегледате заглавията на дадено съобщение, като използвате метода getHeaders().

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

Сложни заглавия

Някои заглавия съдържат допълнителна информация за двойка ключове и стойности. Например заглавията Link съдържат връзка и няколко двойки ключове и стойности:

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

Guzzle предоставя удобна функция, която може да се използва за анализ на тези типове заглавия:

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);

Ще произвежда:

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

Резултатът съдържа хеш от двойки ключове и стойности. Стойности на заглавието, които нямат ключ (т.е. връзката), се индексират цифрово, докато частите на заглавията, които образуват ключ стойност, се добавят като двойка ключ-стойност.

Body

Съобщенията за заявка и отговор могат да съдържат тяло.

Можете да извлечете тялото на съобщението, като използвате метода getBody():

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

Тялото, което се използва в обектите за заявка и отговор, е Psr\Http\Message\StreamInterface. Този поток се използва както за качване на данни, така и за изтегляне на данни. По подразбиране Guzzle ще съхранява тялото на в поток, който използва временните потоци на PHP. Когато размерът на тялото надхвърля 2 MB, потокът автоматично ще премине към съхраняване на данни на диска а не в паметта (предпазвайки приложението ви от изчерпване на паметта).

Най-лесният начин за създаване на тяло на съобщение е с помощта на streamFor от класа GuzzleHttp\Psr7\Utils -- Utils::streamFor. Този метод приема низове, ресурси, итератори, други streamables и връща инстанция на Psr\Http\Message\StreamInterface.

Тялото на заявката или отговора може да бъде превърнато в низ или можете да четете и записвате байтове от потока, както е необходимо.

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());

Искания

Заявките се изпращат от клиент към сървър. Заявките включват метода да бъде приложен към даден ресурс, идентификатор на ресурса и протокол. версия, която да се използва.

Методи за заявка

Когато създавате заявка, от вас се очаква да посочите желания HTTP метод. да бъде изпълнен. Можете да посочите всеки метод, който желаете, включително потребителски метод който може да не е част от RFC 7231 (например "MOVE").

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

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

Можете да създадете и изпратите заявка, като използвате методи на клиента, които съответстват на HTTP метода, който искате да използвате.

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 **/])
ВАРИАНТИ
$client->options('http://httpbin.org/get', [/** options **/])
PATCH
$client->patch('http://httpbin.org/put', [/** options **/])

Например:

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

URI на заявката

URI на заявката се представя от обект Psr\Http\Message\UriInterface. Guzzle предоставя имплементация на този интерфейс, използвайки GuzzleHttp\Psr7\Uri клас.

Когато създавате заявка, можете да предоставите URI като низ или като инстанция на Psr\Http\Message\UriInterface.

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

Схема

схемата на заявката указва протокола, който да се използва при изпращането на заявката. Когато използвате Guzzle, схемата може да бъде зададена като "http" или "https".

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

Домакин

Хостът е достъпен чрез URI, принадлежащ на заявката, или чрез достъп до заглавието Host.

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

Port

При използване на схемите "http" или "https" не е необходим порт.

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

Path

Пътят на заявката е достъпен чрез обекта URI.

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

Съдържанието на пътя ще бъде автоматично филтрирано, за да се гарантира, че само разрешени символи в пътя. Всички неразрешени символи в пътя, ще бъдат кодирани в проценти съгласно RFC 3986, раздел 3.3.

Запитващ низ

До низът на заявката може да се получи достъп с помощта на getQuery() на URI обекта, притежаван от заявката.

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

Съдържанието на низ от заявки ще бъде автоматично филтрирано, за да се гарантира, че в низът на заявката да присъстват само разрешени символи. Всички символи, които не са разрешени в низа на заявката, ще бъдат процентно кодирани според RFC 3986, раздел 3.4.

Отговори

Отговорите са HTTP съобщенията, които клиентът получава от сървъра след изпращане на съобщение за HTTP заявка.

Начална линия

Началният ред на отговора съдържа протокола и версията на протокола, кода на състоянието и фразата за причината.

$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

Както беше описано по-рано, можете да получите тялото на отговора, като използвате метода getBody().

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

Потоци

Guzzle използва поточни обекти PSR-7 за представяне на съобщения за заявка и отговор тела. Тези поточни обекти ви позволяват да работите с различни типове данни. използвайки общ интерфейс.

HTTP съобщенията се състоят от начален ред, заглавия и тяло. Тялото на HTTP може да бъде много малко или изключително голямо. Опитът да се представи тялото на съобщението като низ може лесно да отнеме повече памет от предвиденото, защото тялото трябва да се съхранява изцяло в паметта. Опитът да се съхрани тялото на на заявка или отговор в паметта ще попречи на използването на тази реализация от да може да работи с големи тела на съобщения. Интерфейсът StreamInterface се използва в за да се скрият подробностите за реализацията на това, откъде се чете поток от данни или се записва.

Интерфейсът PSR-7 Psr\Http\Message\StreamInterface разкрива няколко метода, които позволяват ефективно четене, записване и обхождане на потоци.

Потоците разкриват своите възможности чрез три метода: isReadable(), isWritable(), и isSeekable(). Тези методи могат да се използват от поток за да определят дали даден поток е в състояние да изпълни техните изисквания.

Всяка инстанция на поток има различни възможности: тя може да бъде само за четене, само за запис, за четене и запис, позволяват произволен случаен достъп (търсене напред или назад до всяко място) или да позволяват само последователен достъп (например в в случай на сокет или тръба).

Guzzle използва пакета guzzlehttp/psr7, за да осигури поддръжка на потоци. Още информация за използване на потоци, създаване на потоци, конвертиране на потоци в PHP ресурс на потока и декоратори на потоци можете да намерите в Guzzle PSR-7 документация.

Създаване на потоци

Най-добрият начин за създаване на поток е да използвате GuzzleHttp\Psr7\Utils::streamFor метод. Този метод приема низове, ресурси, върнати от fopen(), обект, който имплементира __toString(), итератори, callables и екземпляри на 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

Можете да създавате потоци от итератори. Итераторът може да дава произволен брой байта на итерация. Всички излишни байтове, върнати от итератора, които не са поискани от потребител на поток, ще бъдат буферирани до следващо четене.

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); // ...

Метаданни

Потоците разкриват метаданни за потока чрез метода getMetadata(). Този предоставя данните, които бихте извлекли при извикване на PHP функцията stream_get_meta_data(), и по желание може да разкрива други потребителски данни.

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

Декоратори на потоци

Добавянето на персонализирана функционалност към потоците е много лесно с помощта на декораторите на потоци. Guzzle предоставя няколко вградени декоратора, които осигуряват допълнителни потоци функционалност.