Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Php Http Class Laravel Package

ptcong/php-http-class

A lightweight PHP HTTP client class for sending GET and POST requests, managing cookies, custom headers, redirects, and file uploads through a simple API. Drop-in and dependency-free, it fits into any PHP project without extra setup.

View on GitHub
Deep Wiki
Context7

Getting Started

Install it like any other Composer dependency:

composer require ptcong/php-http-class

Two things to verify before you write a line of code:

  1. The vendor/package name and the namespace don't match the repo name. The repo is ptcong/php-http-client but the Packagist name is ptcong/php-http-class. Check vendor/ptcong/php-http-class/composer.json for the psr-4 map — that is the source of truth for your use statements, not the README. Old, low-traffic packages like this frequently have a namespace that differs from what the README shows.
  2. It's cURL-only. Confirm ext-curl is enabled in your container/CI image; there is no stream/Guzzle fallback.

Where to look first: src/ for the four or five classes that matter (client, request, response, cookie, and whatever "browser"/session object wraps them). Read those before the README — for a package this size the class signatures are more reliable documentation than the readme, and the method names are self-describing.

The first use case worth wiring up is the one this library is actually good at: a stateful, browser-like request sequence — hit a login form, keep the cookies, then fetch a page behind auth. That's the scenario where its built-in cookie jar and redirect handling save you more code than Guzzle would.

// Pseudocode shape — verify exact setters against src/
$client = new HttpClient();

$request = new HttpRequest('https://example.com/login');
$request->setMethod('POST')
    ->setHeaders(['User-Agent' => 'Mozilla/5.0 ...', 'Referer' => 'https://example.com/'])
    ->setData(['user' => $u, 'pass' => $p]);

$response = $client->send($request);

echo $response->getStatusCode();   // 200
echo $response->getBody();         // raw HTML/JSON

Implementation Patterns

Wrap it, don't sprinkle it. The classes are not PSR-18 and share no interface with Laravel's HTTP client, so every direct new HttpClient() is a future refactor. Put it behind one class:

namespace App\Services;

use App\Contracts\Fetcher;

class LegacyHttpFetcher implements Fetcher
{
    public function get(string $url, array $headers = []): array
    {
        $request = new HttpRequest($url);
        $request->setHeaders($headers);

        $response = (new HttpClient())->send($request);

        return [
            'status' => $response->getStatusCode(),
            'headers' => $response->getHeaders(),
            'body' => $response->getBody(),
        ];
    }
}

Bind Fetcher to the implementation in a service provider. Now tests can swap in a fake, and if you later migrate to Guzzle/Laravel Http, only one class changes.

Reuse one client object per unit of work. A fresh client per request defeats the cookie jar and can re-do DNS/TLS handshakes. Hold a single instance for the whole sequence:

class ScrapeLoginPage
{
    public function __construct(private HttpClient $client) {}

    public function handle(): string
    {
        $this->client->send($this->loginRequest());
        $this->client->send($this->csrfWarmup());       // cookies now carried
        return $this->client->send($this->targetRequest())->getBody();
    }
}

If the class hierarchy supports a shared cookie jar/session object separate from the client, pass that explicitly instead — it survives client re-instantiation and is easier to inspect in a debug dump.

Laravel conventions that pay off:

  • Register the client as a scoped binding (not singleton) so an Octane/queue worker doesn't leak cookies between jobs.
  • Move timeouts, proxy, and default User-Agent into config/services.php, and apply them in one place. Hardcoded timeouts are the most common cause of a hung queue worker.
  • If you're doing this from a job, wrap it with RateLimited middleware or an explicit usleep — a raw cURL client will hammer a host with no backoff.
  • For HTML parsing, pipe getBody() straight into symfony/dom-crawler or Dom\HTMLDocument; don't scrape with regex.

Response handling: treat non-2xx as data, not an exception you rely on. Normalize immediately (status → bool, JSON decode with JSON_THROW_ON_ERROR, trim BOM) inside the wrapper so callers never touch the library's response object.

Gotchas and Tips

It duplicates a dependency you already have. Laravel ships Guzzle by default and Illuminate\Support\Facades\Http wraps it with fakes, retries, and ->throw(). The honest everyday calculus: reach for this package only when (a) you're maintaining an existing codebase that already uses it, or (b) you genuinely want a zero-dependency, ~5-class client and don't need middleware. Don't adopt it greenfield just for cookie persistence — Guzzle's CookieJar does that too. Note also that 0 stars and 0 dependents means no ecosystem, no security advisories, and no one to ask when it breaks.

No PSR-7/PSR-18/PSR-17. Consequences: Http::fake() won't intercept it, Guzzle middleware (retry, logging, OAuth subs) won't apply, and you can't type-hint ClientInterface. Everything — retries, logging, auth refresh — has to be hand-rolled in your wrapper.

PHP version drift. This is pre-PHP-7.4-era code in all likelihood. On PHP 8.1+ you'll hit dynamic-property deprecations and possibly implicit-nullable-parameter deprecations. Check composer show ptcong/php-http-class for the php constraint; if it's >=5.x with no upper bound, treat a PHP 8.2/8.3 upgrade as a mini-project. Suppress noise rather than ignore it — deprecations become errors in 9.0.

Error signalling is ambiguous. Old cURL wrappers typically return false or a response object with status 0 on transport failure rather than throwing. Always check for both: a falsy return and a zero/negative status. Wrap in your own exception:

if (! $response || $response->getStatusCode() === 0) {
    throw new HttpTransportException($request->getUrl()); // include cURL error if exposed
}

Timeouts and SSL. Defaults in libraries this age are frequently "no timeout" and SSL verification inherited from php.ini. In containers with missing CA bundles you'll get silent failures; set the CA path explicitly rather than flipping verification off. Always set a connect timeout and a total timeout — a connect timeout alone won't save you from a slow-drip response.

Cookie behaviour is the whole point and the easiest thing to get wrong. The jar is usually in-memory and tied to the client instance, so:

  • Re-instantiating per request breaks the login flow — this is the #1 reported symptom.
  • Domain/path matching may be looser than a browser's; if a site sets cookies on a parent domain, verify it's sent on subrequests.
  • Inspect the jar directly (var_dump the cookie collection) when a session "randomly" drops.

Redirects hide POST semantics. If the library auto-follows redirects, confirm whether the method is downgraded to GET (correct) or the body is resent (rare, but wrong). Login flows silently failing usually trace here.

Debugging. Set CURLOPT_VERBOSE/CURLINFO_HEADER_OUT — if the wrapper exposes the underlying handle or a debug flag, turn it on and log the outgoing request line plus headers. If it doesn't expose it, subclass the client and override the single method that performs curl_exec (that's the most useful extension point this package offers). Log getStatusCode(), getHeaders(), and the first 500 chars of the body together; correlating those three is what actually solves scrapers.

Extension points are thin. No events, no middleware, no interceptors. The realistic options are: subclass and override, decorate via your own wrapper class, or fork. Given the size of the library, forking a single class into app/Support/ is often more honest than depending on an unmaintained package — at least then you own the PHP 8 compatibility.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib