承接 vxsilisk/pulsarx 相关项目开发

从需求分析到上线部署,全程专人跟进,保证项目质量与交付效率

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

vxsilisk/pulsarx

Composer 安装命令:

composer require vxsilisk/pulsarx

包简介

Browser-impersonating HTTP client for PHP — like curl_cffi/requests, but native. 32 TLS fingerprints, Sec-Fetch/Referer stealth, async (curl_multi), session cookies & multipart. Zero dependencies.

README 文档

README

✦ PulsarX

A requests-style HTTP client for PHP, built on cURL

The browser-impersonating HTTP client PHP was missing. Guzzle sends requests — PulsarX sends requests that look like Chrome.

In-memory session cookies · browser impersonation · async parallel requests · multipart uploads

⋆ ˚ 。 ⋆ ୨ ⋆ ˚ 。 ⋆

PHP License Built on cURL Impersonation targets Author


Why PulsarX · Install · Quick start · Sessions · Impersonate · Anti-detection · Retries · Async · Uploads · API

✦ Features

Feature What it does
Session model Cookies persist in memory across requests, scoped by domain / path / expiry — like requests.Session. No files touch disk.
Impersonation 32 version-pinned browser fingerprints (Chrome, Edge, Firefox, Safari — desktop, Android & iOS).
Anti-detection Coherent Sec-Fetch-Site + Referer chains (stealth()) and whole-profile rotation (rotate()).
Async Parallel requests over curl_multi with a rolling concurrency window and near-zero idle CPU.
Multipart multipart/form-data and file uploads via a fluent Mime builder (on-disk or in-memory).
JSON-first json: body param, plus Response::json(), ok() and getElapsed().
Zero deps One class per file, a tiny autoloader, and optional Composer. Just PHP + ext-curl.

✦ Why PulsarX?

PHP has great HTTP clients — but none of them can look like a browser. That's the gap PulsarX fills: it's the PHP answer to Python's curl_cffi.

PulsarX Guzzle Symfony HttpClient curl_cffi (Python)
Language PHP PHP PHP Python
Browser impersonation ✓ 32 targets
Anti-detection (Sec-Fetch / Referer) partial
Fingerprint rotation
Async / parallel curl_multi
Scoped session cookies
Multipart / file uploads
Runtime dependencies none several none C / curl-impersonate

On stock OpenSSL the TLS layer is approximate, not a byte-exact JA3 — see Anti-detection. For an exact fingerprint, run PHP against a curl-impersonate libcurl (auto-detected).

⬡ Installation

With Composer

composer require vxsilisk/pulsarx

Without Composer — require the bundled autoloader:

require __DIR__ . '/autoload.php';

Requirements: PHP ≥ 8.1 with the curl and json extensions.

✷ Quick start

require __DIR__ . '/autoload.php';

$s = new Pulsar();
$r = $s->get('https://example.com');

$r->getStatusCode();   // 200
$r->ok();              // true
$r->getBody();         // raw body
$r->json();            // decoded JSON
$r->getElapsed();      // transfer time in seconds

❍ Sessions & cookies

A Pulsar instance is a session. Cookies set by the server are stored in memory and re-sent automatically on later requests — correctly scoped by domain, path and expiry.

$s = new Pulsar();
$s->get('https://site.com/login');            // server sets cookies
$s->post('https://site.com/cart', $payload);   // cookies sent automatically

Cookies are isolated by host — a cookie from shop.com is never leaked to api.stripe.com. You can also pre-seed the jar:

$jar = new CookieJar();
$jar->add(new Cookie(name: 'session', value: 'abc123'));

$s->get('https://site.com', cookie: $jar);

◈ Impersonation

Mimic a real browser's fingerprint — User-Agent, the full header set in browser order, TLS cipher list, EC curves, HTTP/2 and Brotli/ZSTD. Chainable:

$s = (new Pulsar())->impersonate('chrome131');
$r = $s->get('https://protected-site.com');

Your own headers merge on top of the profile (overriding by name, preserving order):

$s->impersonate('chrome')->get($url, headers: ['Referer: https://google.com']);
◇ All 32 targets (or call Pulsar::impersonateTargets() at runtime)
Browser Targets
Chrome (desktop) chrome99 chrome110 chrome116 chrome119 chrome120 chrome124 chrome131 chrome133 chrome136 chrome142 chrome146 chrome
Chrome (Android) chrome99_android chrome131_android chrome_android
Edge edge99 edge101 edge131 edge
Firefox firefox133 firefox135 firefox144 firefox
Safari (macOS) safari153 safari170 safari180 safari260 safari
Safari (iOS) safari172_ios safari180_ios safari_ios
Tor tor

Bare names like chrome, safari, firefox are aliases for the latest stable build.

$s->impersonate('chrome131_android');   // mobile Chrome
$s->impersonate('safari172_ios');       // iOS Safari

Note

About JA3 accuracy. PulsarX runs on stock OpenSSL, so impersonation matches the HTTP layer and the TLS cipher ordering — strong, but not a byte-exact JA3/JA4 (TLS extension order, GREASE, ALPS and HTTP/2 SETTINGS require BoringSSL).

If you run PHP against a curl-impersonate libcurl, PulsarX auto-detects the extra options (ALPS, cert compression, extension permutation, no-server-push) and produces an exact fingerprint — no code change needed.

✸ Anti-detection

Bot detection checks coherence across layers — it catches you when something doesn't line up. PulsarX gives you two tools beyond raw impersonation, both fully working on stock OpenSSL.

Behavioural coherence — stealth()

A naive client always sends Sec-Fetch-Site: none with no Referer. A real browser derives both from where it navigated from. Enable stealth() and PulsarX maintains that context across the session automatically:

$s = (new Pulsar())->impersonate('chrome131')->stealth();

$s->get('https://shop.com/');           // Sec-Fetch-Site: none      (direct, no Referer)
$s->get('https://shop.com/cart');       // Sec-Fetch-Site: same-origin · Referer: https://shop.com/
$s->get('https://api.shop.com/data');   // Sec-Fetch-Site: same-site · Referer: https://shop.com/cart
$s->get('https://other.com/');          // Sec-Fetch-Site: cross-site · Referer: https://api.shop.com/  (origin only)

The Referer honours the default strict-origin-when-cross-origin policy — full URL within a site, origin-only across sites. Anything you set by hand always wins.

Fingerprint rotation — rotate()

Since Chrome 110, browsers randomise TLS extension order — so a single static fingerprint is itself suspicious. Rotation picks a fresh, coherent profile (UA + sec-ch-ua + TLS all in sync) on every request:

$s = (new Pulsar())->rotate();              // realistic pool of current browsers
$s = (new Pulsar())->rotate(['chrome146', 'firefox144', 'safari260']);  // your own pool
$s = (new Pulsar())->impersonate('random'); // one random profile, fixed for the session

Important

Rotation varies whole profiles, never fields within one. Randomising the sec-ch-ua brand order or mixing a Chrome UA with a Firefox header set is a mismatch signal that makes you easier to flag, not harder — so PulsarX never does it.

None of this forges a byte-exact JA3/JA4 on OpenSSL, and no HTTP client clears JavaScript challenges (Cloudflare Turnstile et al.). For hardened anti-bots you still need a curl-impersonate libcurl or a headless browser.

⟡ Async (parallel)

Build promises with getAsync() / postAsync() / requestAsync(), then resolve a batch with pool(). It uses curl_multi with a rolling concurrency window and curl_multi_select, so idle CPU stays near zero while requests are in flight.

$s = new Pulsar();

$promises = [
    $s->getAsync('https://api.com/a', key: 'a'),
    $s->getAsync('https://api.com/b', key: 'b'),
    $s->postAsync('https://api.com/c', json: ['x' => 1], key: 'c'),
];

$responses = $s->pool($promises, concurrency: 10);  // array keyed by `key`

echo $responses['a']->getStatusCode();

Prefer callbacks? Each promise resolves as soon as it finishes:

$s->getAsync($url)->then(fn(Response $r) => print($r->getStatusCode()));
$s->pool($promises);

❖ Multipart & file uploads

A fluent multipart/form-data builder — PulsarX's take on curl_cffi's CurlMime:

$mime = (new Mime)
    ->addPart('username', data: 'andy')
    ->addPart('avatar', filename: 'a.png', contentType: 'image/png', localPath: '/tmp/a.png')
    ->addPart('inline', filename: 'note.txt', data: 'in-memory bytes'); // no temp file needed

$s->post($url, $mime);

Or declaratively, from a list:

$mime = Mime::fromList([
    ['name' => 'username', 'data' => 'andy'],
    ['name' => 'avatar', 'filename' => 'a.png', 'local_path' => '/tmp/a.png'],
]);

⌗ JSON body

$s->post($url, json: ['id' => 1, 'tags' => ['a', 'b']]);  // sets Content-Type: application/json

A plain array passed as $data is still JSON-encoded (legacy behaviour). To send multipart instead, pass a Mime or an array containing a CURLFile.

↻ Retries, params & redirects

Retries with backoff — resilient against transient network errors and 429/5xx:

$s = (new Pulsar())->retries(3, baseDelay: 0.5);     // 3 tries, exponential backoff + jitter
$s->retries(5, 0.5, on: [429, 503]);                  // customise which statuses retry

Query params — built and appended for you:

$s->get('https://api.com/search', params: ['q' => 'x y', 'page' => 2]);
// -> https://api.com/search?q=x+y&page=2

Per-request timeout and redirect control:

$s->get($url, timeout: 5);              // override the default 60s for this call
$s->redirects(follow: true, max: 10);   // session-wide redirect policy
$r = $s->get($url);
$r->getUrl();             // final URL after redirects
$r->getRedirectCount();   // how many hops

Throw on error — opt into exceptions instead of checking ok() (sync requests):

$s->throwOnError();
try {
    $s->get('https://api.com/missing');   // 404 -> throws
} catch (PulsarException $e) { /* ... */ }

Important

TLS verification is ON by default (secure). Disable it explicitly when a target has a broken/self-signed certificate:

$s = new Pulsar(verify: false);

⇄ Proxy

// HTTP tunnel
$s->get($url, server: ['method' => 'tunnel', 'server' => 'http://1.2.3.4:8080']);

// Authenticated proxy
$s->get($url, server: ['method' => 'custom', 'server' => 'http://1.2.3.4:8080', 'auth' => 'user:pass']);

◇ Constructor options

Override any cURL default by passing options to the constructor:

$s = new Pulsar([
    CURLOPT_TIMEOUT        => 120,
    CURLOPT_SSL_VERIFYPEER => true,
]);

❯ API reference

HTTP methods — every method returns a Response.

All methods accept params: (query array) and timeout: (seconds).

Sync Async (returns Promise)
get($url, $headers?, $cookie?, $server?, $params?, $timeout?) getAsync(..., $params?, $key?)
post($url, $data?, $headers?, $cookie?, $server?, $json?, $params?, $timeout?) postAsync(..., $json?, $params?, $key?)
put / patch / delete($url, $data?, …) requestAsync($method, $url, …, $key?)
custom($url, $method, $data?, …) pool(array $promises, int $concurrency = 10): Response[]

Session policy (chainable)

Method Effect
retries($times = 3, $baseDelay = 0.5, $on = null) retry transport errors + given statuses with backoff
redirects($follow = true, $max = 20) redirect-following policy
throwOnError($on = true) throw PulsarException on 4xx/5xx (sync)
new Pulsar($config = [], verify: true) TLS verification (on by default)

Impersonation

Method Returns
impersonate(string|Profile $target) $this — fixed profile ('random' picks one)
rotate(?array $targets = null) $this — fresh coherent profile per request
stealth(bool $on = true) $this — auto Sec-Fetch-Site + Referer chain
clearImpersonation() $this
Pulsar::impersonateTargets() string[] of every target

Response

Method Description
isSuccess() transport succeeded
ok() status in [200, 400)
getStatusCode() HTTP status code
getBody() raw response body
json($assoc = true) decoded JSON body
getHeaders() request + response headers
getReason() error message, if any
getElapsed() transfer time in seconds
getUrl() final URL after redirects
getRedirectCount() number of redirects followed

❏ Project layout

PulsarX/
├── autoload.php          # zero-dependency autoloader
├── composer.json         # classmap autoload of src/
├── example.php           # runnable demo
└── src/
    ├── Pulsar.php             # the client (session · impersonate · async)
    ├── Response.php           # immutable response (ok / json / elapsed …)
    ├── Profile.php            # 32 impersonation targets
    ├── Mime.php               # multipart/form-data + file uploads
    ├── Promise.php            # deferred async request
    ├── CookieJar.php          # domain/path/expiry-scoped cookie jar
    ├── CookieJarInterface.php
    ├── Cookie.php
    ├── Helper.php             # header parsing
    └── PulsarException.php

Run php example.php to see sessions, impersonation, multipart, JSON and async in action.

⋆ ˚ 。 ⋆ ୨ ⋆ ˚ 。 ⋆

PulsarX — made by Vxsilisk · MIT License

统计信息

  • 总下载量: 0
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 1
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2026-06-24