Download the PHP package hamaadraza/php-impersonate without Composer

On this page you can find all versions of the php package hamaadraza/php-impersonate. 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 php-impersonate

PHP-Impersonate

Tests Latest Version Total Downloads PHP Version

Make HTTP requests that look like a real browser. PHP-Impersonate wraps curl-impersonate to reproduce the exact TLS and HTTP/2 fingerprints of Chrome, Firefox, Safari, Edge and Tor, so your requests carry a browser's signature instead of the one that gets ordinary HTTP clients blocked.


Contents


Why

Websites increasingly fingerprint the TLS handshake and HTTP/2 frames to tell real browsers from scripts. cURL, Guzzle and friends have a distinctive signature that is trivial to block. PHP-Impersonate sends byte-for-byte the same handshake as a chosen browser version, so your request looks like it came from that browser.

Requirements

Installation

That's it on common platforms β€” the binaries are bundled. On other platforms run a one-time installer.

Quick start


Two engines, one class

PHPImpersonate is the only class you use. Under the hood it has two engines for reaching curl-impersonate, and by default it transparently picks the faster one that works in your environment β€” you never touch a second class.

FFI engine Executable engine
How calls libcurl-impersonate in-process via PHP FFI runs the bundled curl-impersonate binary per request
Performance no process spawn; keep-alive connections reused across requests one short-lived process per request
Requirements the ffi extension usable + the shared library (see platforms) none β€” works everywhere
Curl options βœ… same curated set βœ… same curated set

[!TIP] Just use PHPImpersonate β€” the default 'auto' engine chooses FFI when it's usable, otherwise the executable. Both accept the same options and produce the same fingerprints, so your code is identical either way. They draw the fingerprint from one place β€” the impersonation table built into curl-impersonate itself (curl_easy_impersonate() on FFI, --impersonate on the executable) β€” so the two cannot drift apart.

Static helpers β€” one-liners for one-off requests:

Instance β€” reuse configuration across requests (the FFI engine keeps its connection alive across calls on the same instance):

All request methods share one signature and return the same Response:

Choosing the engine

Pass engine: to force one, and inspect the choice when you need to:

If the FFI engine misbehaves in a way no exception can describe (a crash), run php vendor/hamaadraza/php-impersonate/scripts/ffi-diagnose.php: it executes each stage of the engine in a separate process and reports which one failed, along with the PHP build and extensions it ran under β€” paste that into a bug report.

Under 'auto', the FFI engine is used whenever PHPImpersonate::ffiAvailable() is true; otherwise the executable engine runs. Both engines accept the exact same curl options, so the choice never changes behaviour. ffiAvailable() is true only when the ffi extension is usable β€” always on the CLI; other SAPIs also need ffi.enable β€” and the shared library loads on this platform (bundled for common platforms; PHP_IMPERSONATE_LIB overrides it).

[!WARNING] A libcurl compiled into the php binary (ext-curl built in rather than loaded as a module: the official Docker images, some source builds) sits ahead of the bundled libcurl-impersonate in the dynamic linker's symbol lookup, so the library's own internal calls could land in that stock libcurl β€” which answers CURLE_UNKNOWN_OPTION and corrupts the handle. On glibc the library is loaded with RTLD_DEEPBIND, which makes it bind to itself, and the FFI engine works. On musl (Alpine) there is no such flag: ffiAvailable() detects the situation (it checks that the default profile actually applies, not just that the library loads), auto uses the executable engine, and ffiUnavailableReason() spells it out. Nothing crashes either way. Windows cannot hit this at all: a DLL's imports bind to the module its own import table names, and the library's internal calls never go through one.


Supported platforms

Prebuilt binaries and FFI libraries ship inside the package for the most common platforms, so everything works with no extra steps:

Platform Executable FFI library
Linux x86_64 (glibc) bundled bundled
macOS ARM64 (Apple Silicon) bundled bundled
Windows x86_64 bundled bundled
Linux x86_64 (musl / Alpine) on demand on demand
Linux ARM64 (glibc & musl) on demand on demand
macOS x86_64 (Intel) on demand on demand

On Alpine, note that the official php:*-alpine images do not enable the ffi extension; add apk add libffi-dev && docker-php-ext-install ffi to use the FFI engine there, otherwise the executable engine is used.

On an β€œon demand” platform, run the installer once after composer require to download the matching binary and library:

To run it automatically, add it to your project's composer.json (a dependency's own scripts don't run on install):

The installer is a no-op when the platform is already bundled. Flags: --no-libs (skip the FFI library), --force (re-download), --version=TAG.


Making requests

GET

POST / PUT / PATCH

Pass an array of data. It is form-encoded by default, or JSON when you set a JSON Content-Type (see Request bodies).

DELETE / HEAD

Responses

Every request returns a Response:

Method Returns Description
status() int HTTP status code
isSuccess() bool true for 2xx
body() string Raw response body
json($assoc = true, $depth = 512, $flags = 0) mixed Decoded JSON β€” throws \JsonException on invalid JSON
header($name, $default = null) ?string First value of a header (case-insensitive)
headerAll($name) string[] All values of a header (use for Set-Cookie)
hasHeader($name) bool Whether a header is present (case-insensitive)
headers() array<string, string[]> All headers as name β†’ list of values
effectiveUrl() ?string The URL the transfer ended on, after redirects
setCookieHeaders() string[] Every Set-Cookie from every hop (see Cookies)
toArray() array ['body' => …, 'statusCode' => …, 'headers' => …, 'effectiveUrl' => …, 'setCookieHeaders' => …]
dump() string Human-readable summary (for logging)
debug() self Echo dump() and return $this

Working with headers

Each header name maps to an array of values (string[]), because headers like Set-Cookie legitimately appear multiple times.

[!IMPORTANT] Set-Cookie must not be folded into one comma-joined string (RFC 6265 Β§4.1.1), so header('Set-Cookie') would drop all but the first cookie. Use headerAll():

headers() contains only headers that were on the wire β€” the status line is not mixed in; read it with $response->status().

Cookies

Within one request, cookies behave as they do in a browser: a cookie set on a redirect hop (the classic POST /login β†’ 302 + Set-Cookie β†’ GET /home) is sent on the follow-up automatically, on both engines. Nothing persists between requests β€” there is no cookie jar yet β€” so to keep a session, read the cookies every response in the chain set and send them back yourself:

Overriding a profile header

A header you pass replaces the browser profile's header of the same name (matched case-insensitively) rather than being sent alongside it. This is how you change the User-Agent without breaking the TLS fingerprint:

[!NOTE] Malformed headers are rejected with an InvalidArgumentException rather than silently dropped, so a typo cannot leave a header quietly unsent.

Browsers

Pass any of these names as the $browser argument (default firefox147):

All 39 supported browsers **Chrome** β€” `chrome99`, `chrome99_android`, `chrome100`, `chrome101`, `chrome104`, `chrome107`, `chrome110`, `chrome116`, `chrome119`, `chrome120`, `chrome123`, `chrome124`, `chrome131`, `chrome131_android`, `chrome133a`, `chrome136`, `chrome142`, `chrome145`, `chrome146`, `chrome150` **Edge** β€” `edge99`, `edge101` **Firefox** β€” `firefox133`, `firefox135`, `firefox144`, `firefox147` *(default)* **Safari** β€” `safari153`, `safari155`, `safari170`, `safari172_ios`, `safari180`, `safari180_ios`, `safari184`, `safari184_ios`, `safari260`, `safari260_ios`, `safari2601` **Other** β€” `tor145`, `okhttp4_android`

The authoritative list is always Raza\PHPImpersonate\Browser\BrowserName::getAll().

A profile is one specific browser release, and releases age: anti-bot vendors flag versions that have been out of support for years, so a 2022 Chrome is a signal in itself even when its handshake is byte-perfect. The profiles of releases older than 2024 (chrome99–chrome120, edge99/edge101, safari153–safari172_ios) are marked @deprecated and listed in BrowserName::DEPRECATED; they still work. For a current identity that keeps up as profiles are added, ask for the newest of a family:

Pin the result if the identity must stay the same across releases of this package.

[!NOTE] okhttp4_android reproduces upstream's profile of the same name, and that profile carries a desktop Safari 17 User-Agent, not an Android one β€” its TLS fingerprint is OkHttp's, but it will not read as an Android client. Pass your own User-Agent header if you need one that matches.

Curl options

Pass extra curl options as the third constructor argument. The same curated, validated set works on both engines β€” the shared registry lives in Raza\PHPImpersonate\Support\CurlOptions:

Option Type Description
proxy string Proxy address (http://, https://, socks5://, …)
proxy-user string Proxy credentials, user:password
noproxy string Comma-separated hosts that bypass the proxy
referer string Referer header value
cacert string Path to a custom CA bundle file
capath string Path to a custom CA directory
max-redirs int β‰₯ 0 Maximum redirects to follow (default 50); 0 stops at the first response
max-filesize int β‰₯ 0 Largest response body accepted, in bytes (default 256 MiB); a larger one throws RequestException with code 63. 0 removes the cap; a negative value is rejected
insecure bool Skip TLS certificate verification (use with care)

[!NOTE] Any option not in this list is rejected with a clear error. Options that would alter the browser fingerprint β€” ciphers, curves, tls-*, the HTTP version, user-agent β€” are intentionally not configurable: overriding them would silently defeat the impersonation. Set a custom User-Agent as a request header instead β€” it replaces the profile's, see Overriding a profile header.

[!NOTE] Responses are buffered in full before they are returned, so max-filesize is what stands between you and a server that streams forever. The default is deliberately finite; raise it for known-large downloads.

[!TIP] Without an explicit cacert/capath, the CA bundle is taken from CURL_CA_BUNDLE, then SSL_CERT_FILE, then the usual system locations (SSL_CERT_DIR supplies a CA directory). Setting one of those variables overrides the system bundle on both engines.

Request bodies

For POST, PUT and PATCH, the array you pass is encoded based on the Content-Type header (matched case-insensitively):

[!NOTE] PUT and PATCH default to JSON; POST defaults to form-encoded. An explicit Content-Type always wins.

Nested arrays are flattened to parent[child] field names in both the form-encoded and multipart encodings, null values are dropped and booleans become 1/0 β€” so the two carry the same data and only the framing differs. Supply your own boundary= in the Content-Type to control it; otherwise one is generated for you. File uploads are not supported: pass a pre-encoded body via Request if you need them.

Security considerations

This library performs no SSRF filtering. Any http/https URL is fetched: loopback, RFC 1918 ranges, link-local addresses, cloud metadata endpoints (169.254.169.254), decimal or hex IP spellings β€” and a public URL may redirect to any of them, since redirects are followed (to http/https only). That policy belongs in your application, which knows its network; what the library gives you to enforce it:

Environment. PHP_IMPERSONATE_LIB loads an arbitrary shared object into the PHP process; CURL_CA_BUNDLE, SSL_CERT_FILE and SSL_CERT_DIR change what is trusted. None of them should be settable by untrusted configuration.

FFI in web SAPIs. Setting ffi.enable=On for PHP-FPM or Apache lets any PHP code in that SAPI call arbitrary C functions, not just this library. If that is unacceptable, leave FFI off there β€” the executable engine is used automatically β€” or run the library from CLI workers and queues, where FFI is always available.

What is not taken from the environment

The executable engine runs curl with -q, so a ~/.curlrc (or $CURL_HOME/$XDG_CONFIG_HOME) on the machine is ignored β€” the FFI engine never read one, and a curlrc could otherwise add headers, a proxy or --insecure to every request. What both engines do honour, like every libcurl program, are the http_proxy/HTTPS_PROXY/NO_PROXY variables; pass 'proxy' => '' to go direct regardless.

Timeouts

Error handling

The library raises two kinds of error:

HTTP error statuses do not throw β€” check isSuccess().

Both implement PHPImpersonateException, so one catch covers everything the library can raise. Reach for that unless you want to tell the two apart:

Catching RequestException alone is not enough to be safe against bad input: InvalidArgumentException extends LogicException, so the two share no built-in parent, and PHPImpersonate::get('not a url') would escape it.

Keeping up to date

New browser profiles and binaries come straight from upstream curl-impersonate β€” no manual editing:

See scripts/README.md for per-step commands and details.

Testing

The behaviour tests talk to an httpbin instance. For a fast, reliable, offline run, start one locally instead of hitting the public service:

Any test whose service is unreachable skips rather than fails, so an outage never breaks the suite. The TLS-fingerprint tests use an external service (tls.peet.ws, override with TLS_FINGERPRINT_URL) since httpbin can't report JA3/JA4; they skip too when it's unavailable.

Two environment variables change that, both used by CI:

Variable Effect
REQUIRE_LIVE_SERVICES=1 An unreachable service fails instead of skipping. Set it where a silent skip would be mistaken for a pass.
PHP_IMPERSONATE_BUILD_FIXTURES=1 Runs the tests that compile small C fixtures with gcc to reproduce the symbol-interposition bug. Skipped by default, since not every machine has a compiler.

Contributors changing how a profile reaches the wire should read docs/CONFIGURATION_BASED_APPROACH.md first: BrowserConfig is not what goes on the wire for a built-in browser, which catches most people out once.

License

MIT β€” see LICENSE.md. The bundled curl-impersonate binaries are built from curl, BoringSSL, nghttp2, brotli, zstd and libidn2, each under its own licence; see THIRD_PARTY_NOTICES.md, which also explains how every bundled file can be re-derived from upstream's release (bin/UPSTREAM-CHECKSUMS).


All versions of php-impersonate with dependencies

PHP Build Version
Package Version
Requires php Version ^8.2
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 hamaadraza/php-impersonate contains the following files

Loading the files please wait ...