{"id":22547094,"url":"https://github.com/kiwilan/php-http-pool","last_synced_at":"2025-07-31T16:16:31.548Z","repository":{"id":186539527,"uuid":"675220939","full_name":"kiwilan/php-http-pool","owner":"kiwilan","description":"PHP package with easy-to-use GuzzleHttp pool wrapper to make concurrent requests.","archived":false,"fork":false,"pushed_at":"2024-11-21T14:40:42.000Z","size":227,"stargazers_count":2,"open_issues_count":1,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-05-30T06:41:46.557Z","etag":null,"topics":["concurrency","guzzle","http","kiwilan","php","pool","requests"],"latest_commit_sha":null,"homepage":"https://packagist.org/packages/kiwilan/php-http-pool","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kiwilan.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null},"funding":{"github":"kiwilan"}},"created_at":"2023-08-06T07:29:45.000Z","updated_at":"2025-02-12T13:00:28.000Z","dependencies_parsed_at":"2024-01-01T11:25:26.566Z","dependency_job_id":"e35f64c5-c36c-4946-9acf-76ff88824398","html_url":"https://github.com/kiwilan/php-http-pool","commit_stats":null,"previous_names":["kiwilan/php-http-pool"],"tags_count":15,"template":false,"template_full_name":"spatie/package-skeleton-php","purl":"pkg:github/kiwilan/php-http-pool","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kiwilan%2Fphp-http-pool","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kiwilan%2Fphp-http-pool/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kiwilan%2Fphp-http-pool/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kiwilan%2Fphp-http-pool/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kiwilan","download_url":"https://codeload.github.com/kiwilan/php-http-pool/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kiwilan%2Fphp-http-pool/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":268069509,"owners_count":24190737,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-31T02:00:08.723Z","response_time":66,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["concurrency","guzzle","http","kiwilan","php","pool","requests"],"created_at":"2024-12-07T15:10:07.143Z","updated_at":"2025-07-31T16:16:31.510Z","avatar_url":"https://github.com/kiwilan.png","language":"PHP","funding_links":["https://github.com/sponsors/kiwilan"],"categories":[],"sub_categories":[],"readme":"# PHP HTTP Pool\n\n![Banner with cards catalog picture in background and PHP XML Reader title](https://raw.githubusercontent.com/kiwilan/php-http-pool/main/docs/banner.jpg)\n\n[![php][php-version-src]][php-version-href]\n[![version][version-src]][version-href]\n[![downloads][downloads-src]][downloads-href]\n[![license][license-src]][license-href]\n[![tests][tests-src]][tests-href]\n[![codecov][codecov-src]][codecov-href]\n\nPHP package with easy-to-use [`GuzzleHttp`](https://docs.guzzlephp.org/en/stable/quickstart.html) pool wrapper, works with `GuzzleHttp\\Pool` and `GuzzleHttp\\Client` to make concurrent requests.\n\n\u003e [!NOTE]\\\n\u003e I love `GuzzleHttp\\Pool`, but I would to build a wrapper to make it easier to use and Laravel `Http\\Pool` is cool but not flexible enough for me. So `HttpPool` allow you to send an `array` or a `Collection` of requests and get a `Collection\u003cmixed, HttpPoolResponse\u003e` of with all `GuzzleHttp` features and more.\n\u003e\n\u003e Built to be more flexible that Laravel [`Http`](https://laravel.com/docs/10.x/http-client#customizing-concurrent-requests) Pool, if Laravel Pool is perfect for you, keep using it.\n\n## Features\n\n-   🚚 Works with very big pool of requests: requests chunked to avoid memory peak\n-   🗂️ Keep identifier of each request: easy to put response into original item (in case of `Collection` of `Model` with Laravel, for example)\n-   📦 `HttpPoolResponse` wrapper with some features to improve DX: original ID, body, metadata...\n-   🏡 Keep original `GuzzleHttp` response in `HttpPoolResponse`: you're in home\n-   🚨 Allow handle memory peak: if you have a lot of requests\n-   🗃️ Works with simple arrays, with associative arrays, with array of objects, with Laravel [`Collection`](https://laravel.com/docs/10.x/collections): just define where to get identifier and URL\n-   💬 Optional console output: you can disable it if you don't want to see progress\n-   🚀 Works with any PHP frameworks, `Illuminate\\Support\\Collection` is a dependency but you can use it without Laravel, `toArray()` method is available after pool execution if you don't want to use `Collection`\n\n## Installation\n\nYou can install the package via composer:\n\n```bash\ncomposer require kiwilan/php-http-pool\n```\n\n## Usage\n\n### Input\n\nWhen you want to use `HttpPool`, you have to pass an input, it could be: a simple array, an associative array, a Laravel `Collection` or an array of objects.\n\n#### With simple array\n\n```php\nuse Kiwilan\\HttpPool\\HttpPool;\n\n// Key is the identifier, value is the URL\n// Array could be associative or not\n$urls = [\n  2 =\u003e 'https://jsonplaceholder.typicode.com/posts',\n  5 =\u003e 'https://jsonplaceholder.typicode.com/comments',\n  10 =\u003e 'https://jsonplaceholder.typicode.com/albums',\n  16 =\u003e 'https://jsonplaceholder.typicode.com/photos',\n  24 =\u003e 'https://jsonplaceholder.typicode.com/todos',\n];\n\n// Create a pool with an array of URLs and some options\n$pool = HttpPool::make($urls)\n  -\u003esetMaxCurlHandles(100)\n  -\u003esetMaxRedirects(10)\n  -\u003esetTimeout(30)\n  -\u003esetConcurrencyMaximum(5)\n  -\u003esetPoolLimit(250)\n  -\u003esetHeaders([\n    'User-Agent' =\u003e 'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)',\n  ])\n;\n\n// Get original requests converted for `HttpPool`\n$requests = $pool-\u003egetRequests();\n$requestCount = $pool-\u003egetRequestCount();\n\n// Execute pool\n$res = $pool-\u003eexecute();\n\n// Get responses\n$responses = $res-\u003egetResponses();\n\n// Get responses as array\n$responsesArray = $res-\u003etoArray();\n\n// Get only fullfilled responses\n$fullfilled = $res-\u003egetFullfilledResponses();\n\n// Get only rejected responses\n$rejected = $res-\u003egetRejectedResponses();\n\n// Counts\n$fullfilledCount = $res-\u003egetFullfilledCount();\n$rejectedCount = $res-\u003egetRejectedCount();\n\n// Get execution time\n$executionTime = $res-\u003egetExecutionTime();\n\n// Get pool instance\n$pool = $res-\u003egetPool();\n```\n\n#### Associative array\n\n\u003e [!WARNING]\\\n\u003e Identifier and URL have to not be nested.\n\n```php\nuse Kiwilan\\HttpPool\\HttpPool;\n\n$urls = [\n  [\n      'uuid' =\u003e 100,\n      'name' =\u003e 'posts',\n      'api' =\u003e 'https://jsonplaceholder.typicode.com/posts',\n  ],\n  [\n      'uuid' =\u003e 125,\n      'name' =\u003e 'comments',\n      'api' =\u003e 'https://jsonplaceholder.typicode.com/comments',\n  ],\n];\n\n$res = HttpPool::make($urls)\n  -\u003esetIdentifierKey('uuid') // Default is 'id'\n  -\u003esetUrlKey('api') // Default is 'url'\n  -\u003eexecute()\n;\n\n$first = $res-\u003egetResponses()-\u003efirst(); // HttpPoolResponse\n$first-\u003egetId(); // 100, 125\n```\n\n#### Laravel models\n\nTake a Laravel model collection and send requests with `HttpPool`. Here `Book` is a Laravel model, we assume that `Book` has an `id` attribute and a `google_book_api` attribute.\n\n```php\nuse App\\Models\\Book;\nuse Kiwilan\\HttpPool\\HttpPool;\n\n$books = Book::all(); // `Illuminate\\Support\\Collection` of `Book`\n\n$pool = HttpPool::make($books)\n  -\u003esetUrlKey('google_book_api') // Default is 'url'\n  -\u003eexecute()\n;\n\n$first = $pool-\u003egetResponses()-\u003efirst(); // HttpPoolResponse\n$first-\u003egetId(); // 1, 2, 3... (Book ID)\n```\n\n#### Array of objects\n\nHere we take an array of objects, we assume that each object has an `uuid` attribute and an `url` attribute. You can just define getters like `getUuid()` and `getUrl()` or you can use `public` attributes, it's up to you.\n\n\u003e [!WARNING]\\\n\u003e If attributes are `private` or `protected`, you have to define getters with logic names: `getUuid()` and `getUrl()`. You can use `uuid()` and `url()` too as getters. But here, if you create a getter `getBookUuid()`, it will not work.\n\n```php\nuse Kiwilan\\HttpPool\\HttpPool;\n\n$urls = [\n  new Book(\n    uuid: 100,\n    name: 'posts',\n    url: 'https://jsonplaceholder.typicode.com/posts',\n  ),\n  new Book(\n    uuid: 125,\n    name: 'comments',\n    url: 'https://jsonplaceholder.typicode.com/comments',\n  ),\n];\n\n$res = HttpPool::make($urls)\n  -\u003esetIdentifierKey('uuid') // Default is 'id'\n  -\u003eexecute()\n;\n\n$first = $res-\u003egetResponses()-\u003efirst(); // HttpPoolResponse\n$first-\u003egetId(); // 100, 125\n```\n\n### Execution\n\nTo execute pool, you can use `execute()` method.\n\n```php\nuse Kiwilan\\HttpPool\\HttpPool;\n\n$pool = HttpPool::make($urls);\n$res = $pool-\u003eexecute();\n```\n\n`execute()` method returns a `HttpPoolFullfilled` object. You can get pool with `getPool()` method.\n\n```php\nuse Kiwilan\\HttpPool\\HttpPool;\n\n$pool = HttpPool::make($urls);\n$res = $pool-\u003eexecute();\n\n$pool = $res-\u003egetPool();\n```\n\nIn `HttpPoolFullfilled` object, you can get responses and more features. All methods `getResponses()`,`getFullfilled()`, `getRejected()` are `Illuminate\\Support\\Collection` of `HttpPoolResponse`.\n\n```php\nuse Kiwilan\\HttpPool\\HttpPool;\n\n$pool = HttpPool::make($urls);\n$res = $pool-\u003eexecute();\n\n// Get all responses (fullfilled and rejected)\n$responses = $res-\u003egetResponses();\n\n// Get only fullfilled responses\n$fullfilled = $res-\u003egetFullfilled();\n\n// Get only rejected responses\n$rejected = $res-\u003egetRejected();\n\n// Get responses count\n$responsesCount = $res-\u003egetResponsesCount();\n\n// Get fullfilled responses count\n$fullfilledCount = $res-\u003egetFullfilledCount();\n\n// Get rejected responses count\n$rejectedCount = $res-\u003egetRejectedCount();\n\n// Get execution time\n$executionTime = $res-\u003egetExecutionTime();\n\n// Get if pool is failed\n$isFailed = $res-\u003eisFailed();\n\n// Get errors\n$errors = $res-\u003egetErrors();\n```\n\n### Errors\n\nTo handle errors, you can just use `HttpPool::make()` method and errors will throw exceptions. But if you want to prevent errors, you can use `throwErrors` param.\n\n```php\nuse Kiwilan\\HttpPool\\HttpPool;\n\n$pool = HttpPool::make($urls, throwErrors: false);\n```\n\nAll errors can be found in `getErrors()` method, after pool execution.\n\n```php\n$res = $pool-\u003eexecute();\n$isFailed = $res-\u003eisFailed();\n$errors = $res-\u003egetErrors();\n```\n\n### Response\n\nAfter pool execution, you can get responses with `getResponses()` method. It returns a `Collection` of `HttpPoolResponse`.\n\n\u003e [!NOTE]\\\n\u003e The first item of `getResponses` could not be the first request you sent. It depends of the response time of each request. But you can retrieve the original request with `getMetadata()-\u003egetRequest()` method, the best way to find parent is to define an ID, that you could retrieve it with `getId()` method.\n\n```php\n$responses = $res-\u003egetResponses();\n$first = $responses-\u003efirst(); // HttpPoolResponse\n\n$first-\u003egetId(); // Get original ID\n$first-\u003egetMetadata(); // Get HttpPoolResponseMetadata\n$first-\u003egetGuzzle(); // Get original GuzzleHttp\\Psr7\\Response\n$first-\u003egetBody(); // Get HttpPoolResponseBody\n$first-\u003eisSuccess(); // Get if response is success\n$first-\u003eisBodyAvailable(); // Get if response body exists\n```\n\n### Metadata\n\n`HttpPoolResponse` has a `HttpPoolResponseMetadata` attribute, it contains some useful data. Here `$first` is a `HttpPoolResponse`.\n\n```php\n$metadata = $first-\u003egetMetadata();\n\n$statusCode = $metadata-\u003egetStatusCode(); // 200, 404, 500...\n$status = $metadata-\u003egetStatus(); // Guzzle pool status: fullfilled, rejected\n$reason = $metadata-\u003egetReason(); // OK, Not Found, Internal Server Error...\n$isSuccess = $metadata-\u003eisSuccess(); // 200 \u003c= $statusCode \u003c 300\n$isFailed = $metadata-\u003eisFailed(); // status code is not success\n$isJson = $metadata-\u003eisJson(); // is a valid JSON\n$isXml = $metadata-\u003eisXml(); // is a valid XML\n$server = $metadata-\u003egetServer(); // Server header\n$date = $metadata-\u003egetDate(); // Date header\n$contentType = $metadata-\u003egetContentType(); // Content-Type header\n$request = $metadata-\u003egetRequest(); // Original request\n$headers = $metadata-\u003egetHeaders(); // Original headers as array\u003cstring, string\u003e\n$header = $metadata-\u003egetHeader('Content-Type'); // Extract header (safe method)\n```\n\n### Body\n\n`HttpPoolResponseBody` is a wrapper of `GuzzleHttp\\Psr7\\Stream` with some useful methods. Here `$first` is a `HttpPoolResponse`.\n\n```php\n$body = $first-\u003egetBody();\n\n$isExists = $body-\u003eisExists(); // Get if body exists\n$contents = $body-\u003egetContents(); // Get body contents\n$json = $body-\u003egetJson(); // Get body as JSON\n$xml = $body-\u003egetXml(); // Get body as XML\n$isBinary = $body-\u003eisBinary(); // Get if body is binary\n$isJson = $body-\u003eisJson(); // Get if body is a valid JSON\n$isXml = $body-\u003eisXml(); // Get if body is a valid XML\n$isString = $body-\u003eisString(); // Get if body is a string\n$toArray = $body-\u003etoArray(); // Get body as array\n```\n\n### Advanced\n\nYou can use some advanced options to customize your pool.\n\nUse URL as identifier to replace ID.\n\n```php\nHttpPool::make($urls)\n  -\u003esetUrlAsIdentifier();\n```\n\nEnable console output.\n\n```php\nHttpPool::make($urls)\n  -\u003eallowPrintConsole();\n```\n\n#### Memory peak\n\nHandle memory peak is optional, but if you have a lot of requests, you can use `allowMemoryPeak` to avoid memory peak. New memory peak will be set inside `execute()` method.\n\nMemory peak is set to `2G` by default, you can change it with second param.\n\n```php\nHttpPool::make($urls)\n  -\u003eallowMemoryPeak('2G');\n```\n\n## Testing\n\n```bash\ncomposer test\n```\n\n## Changelog\n\nPlease see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.\n\n## Credits\n\n-   [Guzzle](https://docs.guzzlephp.org/en/stable/quickstart.html) for the awesome HTTP client\n-   [Laravel](https://laravel.com/docs/10.x/http-client) for `Illuminate\\Support\\Collection`\n-   [Symfony](https://symfony.com/) for `symfony/console`\n-   [Spatie](https://github.com/spatie/package-skeleton-php) for the package skeleton\n-   [Ewilan Rivière](https://github.com/kiwilan)\n-   [All Contributors](../../contributors)\n\n## License\n\nThe MIT License (MIT). Please see [License File](LICENSE.md) for more information.\n\n[\u003cimg src=\"https://user-images.githubusercontent.com/48261459/201463225-0a5a084e-df15-4b11-b1d2-40fafd3555cf.svg\" height=\"120rem\" width=\"100%\" /\u003e](https://github.com/kiwilan)\n\n[version-src]: https://img.shields.io/packagist/v/kiwilan/php-http-pool.svg?style=flat\u0026colorA=18181B\u0026colorB=777BB4\n[version-href]: https://packagist.org/packages/kiwilan/php-http-pool\n[php-version-src]: https://img.shields.io/static/v1?style=flat\u0026label=PHP\u0026message=v8.1\u0026color=777BB4\u0026logo=php\u0026logoColor=ffffff\u0026labelColor=18181b\n[php-version-href]: https://www.php.net/\n[downloads-src]: https://img.shields.io/packagist/dt/kiwilan/php-http-pool.svg?style=flat\u0026colorA=18181B\u0026colorB=777BB4\n[downloads-href]: https://packagist.org/packages/kiwilan/php-http-pool\n[license-src]: https://img.shields.io/github/license/kiwilan/php-http-pool.svg?style=flat\u0026colorA=18181B\u0026colorB=777BB4\n[license-href]: https://github.com/kiwilan/php-http-pool/blob/main/README.md\n[tests-src]: https://img.shields.io/github/actions/workflow/status/kiwilan/php-http-pool/run-tests.yml?branch=main\u0026label=tests\u0026style=flat\u0026colorA=18181B\n[tests-href]: https://packagist.org/packages/kiwilan/php-http-pool\n[codecov-src]: https://img.shields.io/codecov/c/gh/kiwilan/php-http-pool/main?style=flat\u0026colorA=18181B\u0026colorB=777BB4\n[codecov-href]: https://codecov.io/gh/kiwilan/php-http-pool\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkiwilan%2Fphp-http-pool","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkiwilan%2Fphp-http-pool","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkiwilan%2Fphp-http-pool/lists"}