Download the PHP package mtk3d/http-vcr without Composer

On this page you can find all versions of the php package mtk3d/http-vcr. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package http-vcr

http-vcr — record and replay HTTP requests in PHP tests

Record real HTTP interactions once, replay them on every test run after that.

Tests Docs PHP 8.2+ Packagist

The PHP test suite for "the code that talks to Shopify/Stripe/Zendesk" becomes fast, deterministic, and runnable in CI with no network access and no API credentials.

http-vcr is a decorator over PSR-18 (Psr\Http\Client\ClientInterface). Anything that already speaks PSR-18 (Guzzle 7+, Symfony's Psr18Client, php-http, Buzz) works unchanged, and two VcrClient instances in one process never interfere — nothing outside the instance you construct is touched.

Recording works with no setup on a developer machine, and is refused on CI, so a missing cassette fails loudly instead of quietly reaching for a real API without credentials.


Contents

Installation

You need PHP 8.2+ and an HTTP client to wrap — whichever one the project already uses. To rebuild a replayed response http-vcr also needs a PSR-17 factory, and it takes that from the client library you already have (Guzzle ships one, Symfony's client pulls one in). If nothing usable is found it stops before the first request rather than partway through one, and composer require --dev nyholm/psr7 settles it.

Quick start

One line in phpunit.xml registers the extension behind #[UseCassette]. PHPUnit has no auto-discovery for extensions, so this is the one thing http-vcr can't do for you:

That's the whole setup — no bootstrap code, no config file, no cassette directory to create. Then put the attribute on the test and take the client from the trait:

$this->vcrClient() is a Psr\Http\Client\ClientInterface, so it drops into the exact spot the real client occupied — no interface changes, no test-only branch in the code under test.

First run — with a real key available, the call goes over the wire and is written to tests/Cassettes/shopify/get-product.yaml:

Every run after — the cassette exists, so the same test replays it. No network, no API key, no flakiness:

Commit the cassette next to the test. Credentials in Authorization and Cookie headers were replaced with placeholders before it hit disk.

Every field of the attribute is a VcrClient constructor parameter under the same name:

On a class it applies to every test method in it; a method-level attribute replaces a class-level one outright rather than merging with it.

Without PHPUnit

The attribute is a convenience over an ordinary object. In a script, or under a different test framework, construct it directly — everything the attribute sets is a constructor argument or a method on this object:

What lands on disk

A cassette is a plain text file, meant to be read in review and edited by hand when needed:

YAML wherever symfony/yaml is installed — which in a Laravel or Symfony project it already is — and the same model in JSON everywhere else. Name a serializer to pin either one, and vendor/bin/http-vcr migrate --to=json to rewrite cassettes already on disk.

Cassettes live in tests/Cassettes/ by default, with the cassette name as a path inside it. Bodies that are binary or oversized go to sidecar files; compressed responses are decoded before storage. HAR import/export moves traffic to and from a browser's Network tab, Postman or a proxy.

Record modes

Three cases decide what happens when an incoming request matches nothing in the cassette:

RecordMode Behavior
RecordIfAbsent (default) No cassette → record everything. Cassette exists → replay only; an unmatched request throws.
ExtendCassette Replays what exists and appends unmatched requests as new recordings, leaving the rest untouched.
PlaybackOnly Never records. A missing cassette or a changed request shape fails loudly.

The declared mode never changes based on the environment. Protecting CI is a separate switch, VCR_ALLOW_RECORDING, which sits above RecordMode and blocks the recording branch of whichever mode is declared:

VCR_ALLOW_RECORDING Result
1 or 0 exactly that — an explicit value always wins
unset, CI detected recording blocked
unset, no CI signal recording allowed

CI detection is narrow and fully enumerated: a non-empty CI, CONTINUOUS_INTEGRATION, BUILD_NUMBER, JENKINS_URL or TEAMCITY_VERSION. Setting VCR_ALLOW_RECORDING=0 in the pipeline is one line and recommended regardless.

Re-recording

VCR_ERASE_TAPE names what to erase and record fresh. It takes a target, never a bare 1 — so the shortest thing to type is not also the one with the widest blast radius:

A cassette recorded from a test that talks to two APIs is refreshable one API at a time: interactions belonging to other providers survive the truncation and keep replaying, so the run needs credentials only for the API being refreshed.

Matching

Which recorded interaction a request corresponds to is decided by a composable list of matchers, all of which must agree. The default set is [MethodMatcher, UriMatcher, QueryStringMatcher].

Matcher Compares
MethodMatcher HTTP method, case-insensitively
UriMatcher scheme + host + path, normalized
HostMatcher host only, when matching the full path is too strict
QueryStringMatcher query params as an unordered set; repeated keys keep their order
HeadersMatcher named headers, subset match by default, exact: true for both directions
BodyMatcher raw body, exact
BodyJsonMatcher semantic JSON — key order doesn't matter, types are compared strictly

Values that legitimately change every run are handled on the matcher that sees them, since redaction can't help with a value not known in advance:

Writing your own means implementing one method — matchers compare two RecordedRequest snapshots, not live PSR-7 objects, so no matcher can drain a stream out from under the next one:

Redaction and secret scanning

Authorization, Proxy-Authorization, Cookie and Set-Cookie are redacted from the first recording with nothing to configure. Anything else is opt-in:

Redaction is symmetric: the real value is replaced with the placeholder before anything touches disk, and swapped back at replay time — on the recorded request before matching, and on the recorded response before application code receives it. It covers everything stored in an interaction, including the message of a recorded transport failure.

Both are built on a general hook pipeline (beforeRecord / beforePlayback) that's open for anything else an interaction needs done to it on the way in or out.

On top of that, every session that records anything runs the new interactions through a credential heuristic and warns:

It never fails a test and never blocks the write — the point is to put the finding in front of you while the context is fresh, before the file is committed. For the blocking version across every cassette, with an exit code CI can act on, run vendor/bin/http-vcr scan-secrets — and --redact on the same command asks about each finding and replaces the confirmed ones in the file, one way.

More control

Framework integration

How
Any PSR-18 client new VcrClient($client, cassette: '…') — nothing else needed
Guzzle VcrMiddleware on the HandlerStack, so $client->get() and friends are covered too — those bypass any decorator around the client
Symfony VcrHttpClient implements HttpClientInterface, the one a Symfony app injects into services. Psr18Client needs no bridge
PHPUnit #[UseCassette], #[CassetteDirectory], InteractsWithCassettes, Extension. PHPUnit 10–13
Laravel mtk3d/laravel-http-vcr — a separate package: auto-registered provider, Http facade interception, artisan vcr:*. Laravel 12+. The manual recipe covers it without the extra package

Runnable versions of each are in examples/.

CLI

Command Does
stale Lists interactions past their staleAfter
tests Lists tests touching a provider, plus a ready-made --filter regex
providers Every configured provider with its hosts, requiresEnv and cassette counts, then the hosts running unclaimed
scan-secrets Credential scan across every cassette, with an exit code
lock / unlock Sets or clears the write-protect flag on an interaction

None of these run the test suite: #[UseCassette] is read by parsing the source, so no command needs a correctly configured environment to answer a question about cassettes. That also means anything not statically resolvable (staleAfter: self::INTERVAL, a computed cassette name) is reported as "couldn't be fully analyzed" rather than guessed at.

The tests command exists to make a targeted re-record quick:

The filter is only ever a speed optimization — what gets erased is decided by VCR_ERASE_TAPE, so the same command without it produces the same cassettes, just slower.

Configuration

Everything is optional; http-vcr works with none of it. Project-wide defaults go in an http-vcr.php found by walking up from the working directory, no further than the directory holding composer.json:

A provider is a name for an external API: host patterns plus the environment variables recording it requires. Naming one buys VCR_ERASE_TAPE=@shopify and a check that fails before anything is recorded against a missing credential — [email protected] works against a bare hostname without any configuration either way.

The same object can be filled in from code instead, for projects that would rather configure in a PHPUnit bootstrap than add a file:

Documentation

mtk3d.github.io/http-vcr — the full book, covering every option in reference tables, plus the parts this README only names: the cassette format, the hook pipeline, storage backends and serializers, the environment-variable precedence table, and every exception with the question it answers.

The source is in docs/; mdbook serve docs reads it locally.

PLAN.md carries the design decisions, each with the alternatives that were rejected and why. It's written in Polish; everything else is in English.

Dependencies

The record/replay core depends on psr/http-message, psr/http-client, psr/http-factory and psr/clock, and nothing else — no Guzzle, no Symfony, no framework. The package additionally requires symfony/console and nikic/php-parser for the CLI; since http-vcr is installed as a dev dependency, neither reaches an application's production autoloader.

Optional, install only if needed: guzzlehttp/guzzle (the middleware bridge), symfony/http-client (the native HttpClientInterface bridge), symfony/yaml (makes YAML the cassette format instead of JSON), phpunit/phpunit (the attribute and trait).

Development

All three run in CI across PHP 8.2–8.5. Conventions for working on this repository are in AGENTS.md.

License

MIT — see LICENSE.


All versions of http-vcr with dependencies

PHP Build Version
Package Version
Requires php Version ^8.2
psr/clock Version ^1.0
psr/http-message Version ^2.0
psr/http-client Version ^1.0
psr/http-factory Version ^1.0
symfony/console Version ^6.4 || ^7.0 || ^8.0
nikic/php-parser Version ^5.0
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package mtk3d/http-vcr contains the following files

Loading the files please wait ...