PHPackages                             n5s/http-cli - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Testing &amp; Quality](/categories/testing)
4. /
5. n5s/http-cli

ActiveLibrary[Testing &amp; Quality](/categories/testing)

n5s/http-cli
============

Serverless HTTP client - make requests to PHP scripts on the command line

1.1.1(2w ago)27.8kMITPHPPHP ^8.2CI passing

Since Jan 2Pushed 2w agoCompare

[ Source](https://github.com/nlemoine/http-cli)[ Packagist](https://packagist.org/packages/n5s/http-cli)[ RSS](/packages/n5s-http-cli/feed)WikiDiscussions main Synced today

READMEChangelog (3)Dependencies (39)Versions (4)Used By (0)

HTTP CLI
========

[](#http-cli)

Serverless HTTP client - make requests to PHP scripts on the CLI.

This library lets you make HTTP requests to PHP applications without running a web server. Instead of Apache or nginx, it executes your PHP scripts directly via the command line while emulating the full HTTP environment (`$_GET`, `$_POST`, `$_SERVER`, `$_SESSION`, headers, cookies, etc.).

Perfect for testing, CI pipelines, unreleased deployment or any scenario where spinning up a web server is overkill or not possible.

Installation
------------

[](#installation)

```
composer require n5s/http-cli
```

Usage
-----

[](#usage)

```
use n5s\HttpCli\Client;
use n5s\HttpCli\RequestOptions;

$client = new Client('/path/to/your/app');

// Simple GET request
$response = $client->request('GET', 'https://example.com/api/users');
echo $response->getContent();

// POST with JSON
$response = $client->request('POST', '/api/users',
    RequestOptions::create()
        ->json(['name' => 'John', 'email' => 'john@example.com'])
        ->build()
);

// POST with form data
$response = $client->request('POST', '/login',
    RequestOptions::create()
        ->formParams(['username' => 'admin', 'password' => 'secret'])
        ->build()
);
```

How It Works
------------

[](#how-it-works)

When you make a request, the library:

1. Spawns a PHP CLI process targeting your script
2. Injects a bootstrap that populates `$_GET`, `$_POST`, `$_SERVER`, `$_COOKIE`, and `$_SESSION`
3. Provides polyfills for specific HTTP context functions: `header()`, `headers_sent()`, `http_response_code()`, etc.
4. Captures the output and headers, returning a `Response` object

Your PHP scripts run exactly as they would under a web server, but without one.

Framework Adapters
------------------

[](#framework-adapters)

Use your favorite HTTP client library - just swap in our handler.

### Guzzle

[](#guzzle)

```
composer require guzzlehttp/guzzle
```

```
use GuzzleHttp\Client;
use GuzzleHttp\HandlerStack;
use n5s\HttpCli\Guzzle\CliHandler;
use n5s\HttpCli\Client;

$cliClient = new Client('/path/to/your/app');
$handler = new CliHandler($cliClient);

$client = new Client([
    'handler' => HandlerStack::create($handler),
]);

// Use Guzzle as normal
$response = $client->get('/api/users');
$response = $client->post('/api/users', [
    'json' => ['name' => 'John'],
]);
```

### Symfony HttpClient

[](#symfony-httpclient)

```
composer require symfony/http-client
```

```
use n5s\HttpCli\Symfony\CliClient;
use n5s\HttpCli\Client;

$cliClient = new Client('/path/to/your/app');
$client = new CliClient($cliClient);

// Use Symfony HttpClient as normal
$response = $client->request('GET', '/api/users');
$data = $response->toArray();
```

### WordPress Requests

[](#wordpress-requests)

```
composer require rmccue/requests
```

```
use WpOrg\Requests\Requests;
use n5s\HttpCli\WordPress\Cli;
use n5s\HttpCli\Client;

$cliClient = new Client('/path/to/your/app');

Requests::set_transport([Cli::class]);
Cli::setClient($cliClient);

// Use WordPress Requests as normal
$response = Requests::get('/api/users');
```

Request Options
---------------

[](#request-options)

Build requests with a fluent API:

```
use n5s\HttpCli\RequestOptions;

$options = RequestOptions::create()
    // Body
    ->json(['key' => 'value'])           // JSON payload
    ->formParams(['field' => 'value'])   // Form data (application/x-www-form-urlencoded)
    ->body('raw content')                // Raw body
    ->multipart([                        // Multipart form data
        ['name' => 'file', 'contents' => 'data', 'filename' => 'test.txt'],
    ])

    // Headers & Auth
    ->headers(['X-Custom' => 'value'])
    ->basicAuth('user', 'pass')
    ->bearerToken('token')
    ->cookies(['session' => 'abc123'])

    // Other
    ->query(['page' => 1, 'limit' => 10])
    ->timeout(30.0)
    ->build();

$response = $client->request('POST', '/api/endpoint', $options);
```

Response
--------

[](#response)

```
$response = $client->request('GET', '/api/users');

$response->getStatusCode();  // 200
$response->getHeaders();     // ['Content-Type: application/json', ...]
$response->getContent();     // Response body as string
$response->getSession();     // Session data array
$response->getProcess();     // Symfony Process instance (for debugging)
```

Configuration
-------------

[](#configuration)

```
$client = new Client(
    documentRoot: '/path/to/your/app',   // Required: your app's root directory
    file: 'index.php',                   // Entry point (default: index.php)
    globalsHandler: null,                // GlobalsHandler to customize superglobals
    phpExecutable: null,                 // PHP binary path (auto-detected)
);
```

### Globals Handler

[](#globals-handler)

By default, the child PHP process receives a clean set of superglobals built from the HTTP request only. If your application depends on environment variables from the parent process (e.g. `APP_ENV`, `DATABASE_URL`), you can use the built-in `InheritEnvGlobalsHandler`:

```
use n5s\HttpCli\Client;
use n5s\HttpCli\InheritEnvGlobalsHandler;

$client = new Client(
    documentRoot: '/path/to/your/app',
    globalsHandler: new InheritEnvGlobalsHandler(),
);
```

This merges the parent's `$_SERVER` and `$_ENV` into the child process. Request-specific variables take precedence over inherited ones.

You can also implement the `GlobalsHandler` interface to customize superglobals however you need:

```
use n5s\HttpCli\GlobalsHandler;

final class MyGlobalsHandler implements GlobalsHandler
{
    public function handle(array &$globals): void
    {
        $globals['_SERVER']['APP_ENV'] = 'testing';
        $globals['_ENV']['CUSTOM_VAR'] = 'value';
    }
}
```

Adapter Options Support
-----------------------

[](#adapter-options-support)

### Guzzle

[](#guzzle-1)

OptionSupported`timeout`✅`headers`✅`query`✅`body`✅`json`✅`form_params`✅`multipart`✅`auth`✅`cookies`✅`allow_redirects`✅`http_errors`✅`decode_content`✅`version`✅`sink`✅`on_headers`✅ (callback)`on_stats`✅ (callback)`connect_timeout`❌ ignored`verify`❌ ignored`cert`❌ ignored`proxy`❌ ignored`ssl_key`❌`progress`❌`debug`❌### Symfony HttpClient

[](#symfony-httpclient-1)

OptionSupported`timeout`✅`headers`✅`query`✅`body`✅`json`✅`auth_basic`✅`auth_bearer`✅`max_redirects`✅`verify_peer`❌ ignored`verify_host`❌ ignored`cafile`❌ ignored`proxy`❌ ignored`http_version`❌`on_progress`❌`resolve`❌`local_cert`❌`local_pk`❌`ciphers`❌### WordPress Requests

[](#wordpress-requests-1)

OptionSupported`timeout`✅`useragent`✅`redirects`✅`follow_redirects`✅`auth`✅`cookies`✅`connect_timeout`❌ ignored`proxy`❌ ignored`verify`❌ ignored`verifyname`❌ ignored`filename`❌`hooks`❌`max_bytes`❌Limitations
-----------

[](#limitations)

Running PHP scripts via CLI instead of a web server comes with inherent limitations:

### Not Supported

[](#not-supported)

FeatureReasonPersistent connectionsEach request spawns a new PHP processKeep-aliveNo connection reuse between requestsHTTP/2, HTTP/3CLI execution doesn't use HTTP protocolWebSocketsRequires persistent connectionServer-Sent EventsRequires streaming connectionReal SSL/TLSNo actual HTTPS handshake (URLs are parsed, not connected)Output streamingResponse is captured after script completes`fastcgi_finish_request()`FPM-specific functionAPCu user cacheNot shared between CLI processesOPcache benefitsEach process starts freshStatic filesOnly executes PHP - images, fonts, CSS, JS won't be served### Behavioral Differences

[](#behavioral-differences)

- **Performance**: Process spawning overhead, but no DNS resolution, TCP/SSL handshake, or network latency
- **`$_SERVER` values**: Some values like `SERVER_SOFTWARE` will differ from Apache/nginx
- **File uploads**: Multipart parts are written to temp files and populated in `$_FILES`
- **Session handling**: Works but uses an in-memory handler, not file-based persistence
- **`php://input`**: Custom stream wrapper provides the request body

License
-------

[](#license)

MIT

###  Health Score

49

↑

FairBetter than 94% of packages

Maintenance96

Actively maintained with recent releases

Popularity29

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity49

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 75% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~82 days

Total

3

Last Release

17d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/62f16c9d375343e12eb02b2a3095dc9a02047287b5f12f75ef4c59929fcb2802?d=identicon)[n5s](/maintainers/n5s)

---

Top Contributors

[![nlemoine](https://avatars.githubusercontent.com/u/2526939?v=4)](https://github.com/nlemoine "nlemoine (9 commits)")[![github-actions[bot]](https://avatars.githubusercontent.com/in/15368?v=4)](https://github.com/github-actions[bot] "github-actions[bot] (3 commits)")

---

Tags

cliguzzlehttp-clienthttptestingclicommand-linesymfonyhttp clientGuzzle

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan, Rector

Code StyleECS

Type Coverage Yes

### Embed Badge

![Health badge](/badges/n5s-http-cli/health.svg)

```
[![Health](https://phpackages.com/badges/n5s-http-cli/health.svg)](https://phpackages.com/packages/n5s-http-cli)
```

###  Alternatives

[laravel/framework

The Laravel Framework.

34.8k543.8M20.1k](/packages/laravel-framework)[drupal/core

Drupal is an open source content management platform powering millions of websites and applications.

21866.0M1.7k](/packages/drupal-core)[sulu/sulu

Core framework that implements the functionality of the Sulu content management system

1.3k1.4M203](/packages/sulu-sulu)[drupal/core-recommended

Locked core dependencies; require this project INSTEAD OF drupal/core.

6942.5M421](/packages/drupal-core-recommended)[spatie/laravel-export

Create a static site bundle from a Laravel app

674146.0k6](/packages/spatie-laravel-export)[osteel/openapi-httpfoundation-testing

Validate HttpFoundation requests and responses against OpenAPI (3+) definitions

1202.1M7](/packages/osteel-openapi-httpfoundation-testing)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
