Исходники на GitHub
Документация здесь
Guzzle
Guzzle - это PHP-HTTP-клиент, который упрощает отправку HTTP-запросов и интеграцию с веб-сервисами. Guzzle может отправлять как синхронные, так и асинхронные запросы, используя один и тот же интерфейс. Среди его плюсов: простой интерфейс работы со строкой запросов, использование HTTP-кук (cookies), загрузка данных. Если вы не хотите сами настраивать POST или GET запросы через cURL, то библиотека Guzzle как раз для вас.
Будем использовать Guzzle. Именно в этой версии есть поддержка стандарта PSR-7 — HTTP Message Interface
Установка Guzzle HTTP-клиент
Рекомендуемый способ установки Guzzle - с помощью Composer. В файле composer.json
{
"require": {
"guzzlehttp/guzzle": "^7.8"
}
}
Или из консоли (терминала):
php composer.phar require guzzlehttp/guzzle
Если нужна последняя нестабильная версия пакета:
{
"require": {
"guzzlehttp/guzzle": "^7.8@dev"
}
}
После установки вам понадобится автозагрузчик Composer:
require 'vendor/autoload.php';
Создание клиента
Можно делать запросы в Guzzle, используя объект GuzzleHttp\ClientInterface
:
$client = new Client([
// Базовый URI используется с относительными запросами
'base_uri' => 'http://httpbin.org',
// Вы можете установить любое количество параметров запроса по умолчанию.
'timeout' => 2.0,
]);
Клиент является неизменными в Guzzle 6, что означает, что вы не можете изменить значения по умолчанию, используемые клиентом после его создания.
Конструктор клиента принимает ассоциативный массив опций:
base_uri
(string|UriInterface) Базовый URI клиента, который объединен в относительные URI. Может быть строкой или экземпляром UriInterface. Когда клиенту предоставляется относительный URI, клиент объединяет базовый URI с относительным URI, используя правила, описанные в RFC 3986, section 2.
// Создать клиента с базовым URI
$client = new GuzzleHttp\Client(['base_uri' => 'https://foo.com/api/']);
// Отправить запрос на https://foo.com/api/test
$response = $client->request('GET', 'test');
// Отправить запрос на https://foo.com/root
$response = $client->request('GET', '/root');
Не хочется читать RFC 3986
? Вот несколько быстрых примеров того, как base_uri
разрешается с другим URI:
base_uri | URI | Результат |
---|---|---|
http://foo.com |
/bar |
http://foo.com/bar |
http://foo.com/foo |
/bar |
http://foo.com/bar |
http://foo.com/foo |
bar |
http://foo.com/bar |
http://foo.com/foo/ |
bar |
http://foo.com/foo/bar |
http://foo.com |
http://baz.com |
http://baz.com |
http://foo.com/?bar |
bar |
http://foo.com/bar |
handler
(callable) Функция, которая передает HTTP-запросы по сети. Функция вызывается с Psr7\Http\Message\RequestInterface
и массив опций передачи, и должен возвращать GuzzleHttp\Promise\PromiseInterface
который выполняется с Psr7\Http\Message\ResponseInterface
в случае успеха. handler
это опция только для конструктора, которая не может быть переопределена в параметрах per/request
.
…
(mixed) Все остальные параметры, передаваемые конструктору, используются в качестве параметров запроса по умолчанию для каждого запроса, создаваемого клиентом.
Отправка запросов
Магические методы на клиенте позволяют легко отправлять синхронные запросы:
$client = new GuzzleHttp\Client();
$response = $client->get('http://httpbin.org/get');
$response = $client->delete('http://httpbin.org/delete');
$response = $client->head('http://httpbin.org/get');
$response = $client->options('http://httpbin.org/get');
$response = $client->patch('http://httpbin.org/patch');
$response = $client->post('http://httpbin.org/post');
$response = $client->put('http://httpbin.org/put');
Вы можете создать запрос и затем отправить запрос клиенту, когда будете готовы:
use GuzzleHttp\Psr7\Request;
$request = new Request('PUT', 'http://httpbin.org/put');
$response = $client->send($request, ['timeout' => 2]);
Клиентские объекты обеспечивают большую гибкость в том, как передаются запросы, включая параметры запроса по умолчанию, промежуточное программное обеспечение стека обработчиков по умолчанию, которое используется каждым запросом, и базовый URI, который позволяет отправлять запросы с относительными URI.
Асинхронные запросы
Вы можете отправлять асинхронные запросы, используя магические методы, предоставляемые клиентом:
$client = new GuzzleHttp\Client();
$promise = $client->getAsync('http://httpbin.org/get');
$promise = $client->deleteAsync('http://httpbin.org/delete');
$promise = $client->headAsync('http://httpbin.org/get');
$promise = $client->optionsAsync('http://httpbin.org/get');
$promise = $client->patchAsync('http://httpbin.org/patch');
$promise = $client->postAsync('http://httpbin.org/post');
$promise = $client->putAsync('http://httpbin.org/put');
Вы также можете использовать методы sendAsync()
и requestAsync()
клиента:
// Создать объект запроса PSR-7 для отправки
$headers = ['X-Foo' => 'Bar'];
$body = 'Hello!';
$request = new Request('HEAD', 'http://httpbin.org/head', $headers, $body);
$promise = $client->sendAsync($request);
// Или, если вам не нужно передавать экземпляр запроса:
$promise = $client->requestAsync('GET', 'http://httpbin.org/get');
$promise
, возвращаемые этими методами, реализуют Promises/A+ spec, предоставленные библиотекой Guzzle promises. Это означает, что вы сможете связать цепочкой then()
вызовы promise
. Эти then
затем реализуют либо успешный результат с помощью Psr\Http\Message\ResponseInterface
, либо запрос отклоняется с выбросом исключения exception
:
use Psr\Http\Message\ResponseInterface;
use GuzzleHttp\Exception\RequestException;
$promise = $client->requestAsync('GET', 'http://httpbin.org/get');
$promise->then(
function (ResponseInterface $res) {
echo $res->getStatusCode() . "\n";
},
function (RequestException $e) {
echo $e->getMessage() . "\n";
echo $e->getRequest()->getMethod();
}
);
Параллельные запросы
Вы можете отправлять несколько запросов одновременно, используя Promise и асинхронные запросы:
use GuzzleHttp\Client;
use GuzzleHttp\Promise;
$client = new Client(['base_uri' => 'http://httpbin.org/']);
// Инициируем каждый запрос, но не блокируем
$promises = [
'image' => $client->getAsync('/image'),
'png' => $client->getAsync('/image/png'),
'jpeg' => $client->getAsync('/image/jpeg'),
'webp' => $client->getAsync('/image/webp')
];
// Дождаться завершения всех запросов. Выдает исключение ConnectException
// если какой-либо из запросов не выполнен
$results = Promise\unwrap($promises);
// Дождемся завершения запросов, даже если некоторые из них завершатся неудачно
$results = Promise\settle($promises)->wait();
// Можно получить доступ к каждому результату, используя key, предоставленный для функции развертки
echo $results['image']['value']->getHeader('Content-Length')[0]
echo $results['png']['value']->getHeader('Content-Length')[0]
Можно использовать GuzzleHttp\Pool
объект, когда у вас есть неопределенное количество запросов, которые вы хотите отправить:
use GuzzleHttp\Pool;
use GuzzleHttp\Client;
use GuzzleHttp\Psr7\Request;
$client = new Client();
$requests = function ($total) {
$uri = 'http://127.0.0.1:8126/guzzle-server/perf';
for ($i = 0; $i < $total; $i++) {
yield new Request('GET', $uri);
}
};
$pool = new Pool($client, $requests(100), [
'concurrency' => 5,
'fulfilled' => function ($response, $index) {
// Здесь обработка успешного запроса
},
'rejected' => function ($reason, $index) {
// Здесь обработка запроса, который завершился неудачей
},
]);
// Инициализируем трансферы и создаём promise
$promise = $pool->promise();
// Ожидаем ответ promise // Принудительно завершаем пул запросов
$promise->wait();
Или используя замыкание, которое вернет promise, как только пул вызовет замыкание:
$client = new Client();
$requests = function ($total) use ($client) {
$uri = 'http://127.0.0.1:8126/guzzle-server/perf';
for ($i = 0; $i < $total; $i++) {
yield function() use ($client, $uri) {
return $client->getAsync($uri);
};
}
};
$pool = new Pool($client, $requests(100));
Использование ответов
В предыдущих примерах мы получили $response
или мы получили ответ от promise
. Объект ответа реализует ответ PSR-7, Psr\Http\Message\ResponseInterface
, и содержит много полезной информации.
Вы можете получить код состояния и фразу ответа:
$code = $response->getStatusCode(); // 200
$reason = $response->getReasonPhrase(); // OK
Вы можете извлечь заголовки из ответа:
// Проверка, есть ли заголовок
if ($response->hasHeader('Content-Length')) {
echo "It exists";
}
// Получаем заголовок из ответа
echo $response->getHeader('Content-Length')[0];
// Получаем все заголовки ответа
foreach ($response->getHeaders() as $name => $values) {
echo $name . ': ' . implode(', ', $values) . "\r\n";
}
Тело ответа может быть получено с помощью метода getBody()
. Тело ответа может быть использовано как строка, приведено к строке или как объект, подобный потоку:
$body = $response->getBody();
// Неявно приводим тело ответа к строке и отображаем его
echo $body;
// Явное приведение тела к строке
$stringBody = (string) $body;
// Читаем первые 10 байт тела ответа
$tenBytes = $body->read(10);
// Прочитать оставшееся содержимое тела ответа как строку
$remainingBytes = $body->getContents();
Параметры строки запроса
Вы можете предоставить параметры строки запроса несколькими способами. Можно установить параметры строки запроса в URI запроса:
$response = $client->request('GET', 'http://httpbin.org?foo=bar');
Можно указать параметры строки запроса, используя query
как массив:
$client->request('GET', 'http://httpbin.org', [
'query' => ['foo' => 'bar']
]);
Предоставление опции в качестве массива будет использовать нативную функцию PHP http_build_query
для форматирования строки с параметрами.
И, наконец, можно предоставить query
в роли строки:
$client->request('GET', 'http://httpbin.org', ['query' => 'foo=bar']);
Загрузка данных
Guzzle предоставляет несколько способов загрузки данных.
Можно отправлять запросы, содержащие поток данных, передавая строку, ресурс возвращается из fopen
, или как экземпляр Psr\Http\Message\StreamInterface
в опцию запроса body
:
// Предоставляем тело запроса в виде строки
$r = $client->request('POST', 'http://httpbin.org/post', [
'body' => 'raw data'
]);
// Предоставляем fopen ресурс
$body = fopen('/path/to/file', 'r');
$r = $client->request('POST', 'http://httpbin.org/post', ['body' => $body]);
// Используем функцию stream_for() для создания потока PSR-7
$body = \GuzzleHttp\Psr7\stream_for('hello!');
$r = $client->request('POST', 'http://httpbin.org/post', ['body' => $body]);
Простой способ загрузить данные JSON и установить соответствующий заголовок — использовать опцию запроса json
:
$r = $client->request('PUT', 'http://httpbin.org/put', [
'json' => ['foo' => 'bar']
]);
POST/Form запросы
В дополнение к указанию необработанных данных запроса с использованием опции запроса body
, Guzzle предоставляет полезные абстракции при отправке данных POST
.
Отправка полей формы
Для отправки POST-запросов application/x-www-form-urlencoded
необходимо указать поля POST в виде массива в параметрах запроса form_params
:
$response = $client->request('POST', 'http://httpbin.org/post', [
'form_params' => [
'field_name' => 'abc',
'other_field' => '123',
'nested_field' => [
'nested' => 'hello'
]
]
]);
Отправка файлов форм
Можно отправлять файлы вместе с формой (POST-запросы multipart/form-data
), используя опцию запроса multipart
. Она принимает массив ассоциативных массивов, где каждый ассоциативный массив содержит следующие ключи:
name
: (required, string) имя ключа поля формы.contents
: (required, mixed) Укажите тут строку для отправки содержимого файла в виде строки, предоставьте ресурсfopen
для потоковой передачи содержимого из потока PHP или укажитеPsr\Http\Message\StreamInterface
для потоковой передачи содержимого из потока PSR-7.
$response = $client->request('POST', 'http://httpbin.org/post', [
'multipart' => [
[
'name' => 'field_name',
'contents' => 'abc'
],
[
'name' => 'file_name',
'contents' => fopen('/path/to/file', 'r')
],
[
'name' => 'other_file',
'contents' => 'hello',
'filename' => 'filename.txt',
'headers' => [
'X-Foo' => 'this is an extra header to include'
]
]
]
]);
Cookies
Guzzle может поддерживать для вас сеанс файлов cookie, если это указано с помощью параметра запроса файлов cookie. При отправке запроса параметр cookie должен быть установлен на экземпляр GuzzleHttp\Cookie\CookieJarInterface
:
// Использование конкретного cookie jar
$jar = new \GuzzleHttp\Cookie\CookieJar;
$r = $client->request('GET', 'http://httpbin.org/cookies', [
'cookies' => $jar
]);
Можно установить для cookie значение true
в конструкторе клиента, если хотите использовать общий файл cookie для всех запросов:
// Используем общий клиентский файл cookie
$client = new \GuzzleHttp\Client(['cookies' => true]);
$r = $client->request('GET', 'http://httpbin.org/cookies');
Редиректы (перенаправления)
Guzzle будет автоматически следовать за редиректами, только если чётко не указать этого не делать. Вы можете настроить поведение перенаправления, используя опцию запроса allow_redirects
:
- Установите значение
true
, чтобы включить нормальные перенаправления с максимальным количеством 5 перенаправлений. Это значение по умолчанию. - Установите в
false
, чтобы отключить перенаправления. - Передайте ассоциативный массив, содержащий ключ
max
, чтобы указать максимальное количество перенаправлений, и при необходимости укажите значение ключаstrict
, чтобы указать, следует ли использовать строгие перенаправления, совместимые с RFC (что означает запросы перенаправления POST со следующими запросами тоже типа POST, тогда как в обычном режиме большинство браузеров по умолчанию перенаправляют запросы POST со следующими запросами GET)./li>
$response = $client->request('GET', 'http://github.com');
echo $response->getStatusCode();
// 200
В следующем примере показано, как можно отключить редиректы:
$response = $client->request('GET', 'http://github.com', [
'allow_redirects' => false
]);
echo $response->getStatusCode();
// 301
Исключения при обработке ошибок
Guzzle генерирует исключения для ошибок, возникающих во время передачи:
В случае сетевой ошибки (тайм-аут соединения, ошибки DNS и т.д.) выдается сообщение GuzzleHttp\Exception\RequestException
. Это исключение распространяется на GuzzleHttp\Exception\TransferException
. Поймав это исключение, вы поймете любое исключение, которое может быть сгенерировано при передаче запросов.
use GuzzleHttp\Psr7;
use GuzzleHttp\Exception\RequestException;
try {
$client->request('GET', 'https://github.com/_abc_123_404');
} catch (RequestException $e) {
echo Psr7\str($e->getRequest());
if ($e->hasResponse()) {
echo Psr7\str($e->getResponse());
}
}
Исключение GuzzleHttp\Exception\ConnectException
выдается в случае сетевой ошибки. Это исключение происходит от GuzzleHttp\Exception\RequestException
.
GuzzleHttp\Exception\ClientException
выбрасывается для ошибок уровня 400, если для параметра запроса http_errors
установлено значение true
. Это исключение распространяется на GuzzleHttp\Exception\BadResponseException
и GuzzleHttp\Exception\BadResponseException
распространяется на GuzzleHttp\Exception\RequestException
.
use GuzzleHttp\Exception\ClientException;
try {
$client->request('GET', 'https://github.com/_abc_123_404');
} catch (ClientException $e) {
echo Psr7\str($e->getRequest());
echo Psr7\str($e->getResponse());
}
GuzzleHttp\Exception\ServerException
генерируется для ошибок уровня 500, если для параметра запроса http_errors
установлено значение true
. Это исключение происходит от GuzzleHttp\Exception\BadResponseException
.
GuzzleHttp\Exception\TooManyRedirectsException
генерируется, когда выполняется слишком много перенаправлений. Это исключение происходит от GuzzleHttp\Exception\RequestException
.
Все вышеперечисленные исключения происходят из GuzzleHttp\Exception\TransferException
.
Переменные окружения
Guzzle предоставляет несколько переменных среды, которые можно использовать для настройки поведения библиотеки:
GUZZLE_CURL_SELECT_TIMEOUT
Управляет продолжительностью в секундах, которую обработчик curl_multi_*
будет использовать при выборе обработчика curl
, используя curl_multi_select()
. Некоторые системы имеют проблемы с реализацией PHP curl_multi_select()
, где вызов этой функции всегда приводит к ожиданию максимальной продолжительности времени ожидания.
HTTP_PROXY
Определяет прокси для использования при отправке запросов по протоколу http
.
Поскольку переменная HTTP_PROXY может содержать произвольный пользовательский ввод в некоторых (CGI) средах, эта переменная используется только в CLI SAPI. Смотрите https://httpoxy.org для получения дополнительной информации.
HTTPS_PROXY
Определяет прокси для использования при отправке запросов по протоколу https
.
Соответствующие настройки php.ini
Guzzle может использовать настройки php.ini
при настройке клиентов:
openssl.cafile
Указывает путь на диске к файлу CA (сертификат SSL/TLS безопасности) в формате PEM, который будет использоваться при отправке запросов через «https». Подробнее: https://wiki.php.net/rfc/tls-peer-verification#phpini_defaults
Комментарии (0)
Пока еще не было комментариев ✍️