guzzlehttp/guzzle
Guzzle is a PHP HTTP client for sending sync or async requests with an easy API. Built on PSR-7 and PSR-18, supports middleware, cookies, streaming uploads/downloads, and JSON. Transport-agnostic for flexible integrations.
## Getting Started
### Minimal Setup
1. **Installation**:
```bash
composer require guzzlehttp/guzzle:^7.14
Ensure your composer.json targets Guzzle 7.14.x (latest stable) with PHP 8.1+ for full compatibility. The package now strictly enforces guzzlehttp/psr7:^2.12.5.
First Request (Unchanged):
use GuzzleHttp\Client;
$client = new Client();
$response = $client->get('https://api.example.com/data');
$data = json_decode($response->getBody(), true);
Key Entry Points (Updated):
Client: Core class with stricter multiplexing/connection validation.stream => true on cap-configured handlers.Where to Look First:
$response = $client->request('GET', '/users', [
'query' => ['role' => 'admin'],
'headers' => ['Accept' => 'application/json'],
]);
$stack->push(Middleware::tap(function ($request) {
// Credentials in URIs (e.g., `http://user:pass@...`) are now **always redacted** in logs.
logger()->debug('Request URI:', ['uri' => (string)$request->getUri()]);
}));
$client = new Client([
'proxy' => 'http://proxy.example.com:8080',
'proxy_credentials' => 'user:pass', // Now normalized before reuse checks.
]);
$promises = [];
foreach ($urls as $url) {
$promises[] = $client->getAsync($url);
}
// Use `settle()` to avoid double-settling issues:
$results = \GuzzleHttp\Promise\Utils::settle($promises)->wait();
// ❌ Throws `InvalidArgumentException`:
$client->get('https://example.com/large_file', [
'stream' => true,
'handler' => new \GuzzleHttp\Handler\CurlMultiHandler(['capabilities' => ['stream' => true]]),
]);
StreamHandler without caps or disable streaming:
$client->get('https://example.com/large_file', ['sink' => 'file.zip']);
$client = new Client([
'curl' => [
CURLOPT_HTTPAUTH => CURLAUTH_ANY, // ❌ Rejected if NTLM is permitted.
CURLOPT_PIPELINING => CURLPIPE_MULTIPLEX, // Must be integer.
],
'multiplex' => true,
]);
// ❌ Throws `InvalidArgumentException`:
$client = new Client(['proxy' => 'http://user:pass@proxy:8080@invalid']);
$app->singleton(GuzzleHttp\Client::class, function ($app) {
return new Client([
'base_uri' => config('services.api.base_url'),
'timeout' => config('services.api.timeout'),
'proxy' => env('HTTP_PROXY'), // Now normalized.
]);
});
Proxy Credential Normalization:
@ (e.g., user:pass@proxy@domain) now fail closed if unparseable.user:[email protected] format. Validate with:
if (strpos($proxy, '@@') !== false) {
throw new \InvalidArgumentException('Invalid proxy credentials');
}
Multiplexing Conflicts:
multiplex => true with:
CURLMOPT_PIPELINING.CURLOPT_HTTPAUTH allowing NTLM.CURLOPT_PROXYAUTH.$client = new Client([
'multiplex' => true,
'curl' => [
CURLOPT_PIPELINING => 1, // Integer required.
CURLOPT_HTTPAUTH => CURLAUTH_BASIC, // Avoid NTLM.
],
]);
Streaming Restrictions:
stream => true is rejected on handlers with capabilities (e.g., CurlMultiHandler).sink for downloads or disable caps:
$handler = new \GuzzleHttp\Handler\CurlHandler(); // No caps.
$client = new Client(['handler' => $handler]);
Credential Redaction:
http://user:pass@...) are always redacted in logs/middleware.$client->get('https://api.example.com', [
'auth' => ['user', 'pass'], // Preferred over URI credentials.
]);
Async Promise Race Conditions:
settle() or all():
\GuzzleHttp\Promise\Utils::settle($promises)->wait();
Case-Insensitive Matching:
$client->request('GET', '/', [
'headers' => ['Authorization' => 'Bearer ' . $token], // ASCII-safe.
]);
Proxy Validation Errors:
$client = new Client(['debug' => true]);
// Logs: "Proxy credential 'user:pass@proxy@domain' is invalid."
Multiplexing Warnings:
CURLOPT_* options:
try {
$client->request('GET', '/');
} catch (\InvalidArgumentException $e) {
echo $e->getMessage(); // "Multiplexing conflict: NTLM auth not allowed."
}
Streaming Handler Errors:
on_trailers callbacks are only used with CurlHandler:
// ❌ Throws on StreamHandler:
$client->request('GET', '/', [
'on_trailers' => function ($trailers) { /* ... */ },
]);
Connection Reuse Signatures:
Multiplexing Safety:
$client = new Client([
'multiplex' => true,
'curl' => [CURLOPT_PIPELINING => 1],
]);
Async Event Loop:
ReactPHP with fixed cURL multi blocking:
$loop = React\EventLoop\Factory::create();
$client = new Client([
'handler' => new \GuzzleHttp\Handler\React\EventLoopHandler($loop),
]);
How can I help you explore Laravel packages today?