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

Curl Request Laravel Package

teknoo/curl-request

A lightweight PHP wrapper around cURL for building and sending HTTP requests. It offers a simple object-oriented API for handling URLs, headers, methods, and responses, making it easy to integrate clean cURL-based calls into any PHP project.

View on GitHub
Deep Wiki
Context7

Getting Started

Start by deciding whether you should start at all. This package is archived and marked deprecated, with no dependents and no maintainer. composer require teknoo/curl-request still resolves from Packagist, but nothing will ever be fixed in it. Adopt it only to service an existing dependency — for anything new, reach for Guzzle or symfony/http-client, both of which give you PSR-18, retries, and connection pooling for free.

If you are inheriting it, the fastest path to competence:

  1. Read src/, not the README. The README is a handful of examples and constitutes the entire documentation. The class count is small (request, response, and the cURL transport/executor) and each file is short — fifteen minutes of reading beats guessing at accessor names.
  2. Check composer.json for the PHP floor and the ext-curl requirement. This code predates PHP 8; verify it runs on your fleet's version before you build on top of it.
  3. Get one round trip working against a service you control.

The shape of the API is a request object you configure, plus a transport you execute it through:

use Teknoo\Curl\Request;
use Teknoo\Curl\Transport\CurlTransport;

$transport = new CurlTransport();

$request = new Request('https://api.internal/orders/42');
$request->setMethod('GET');
$request->addHeader('Accept: application/json');
$request->addHeader('Authorization: Bearer ' . $token);

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

$status = $response->getStatusCode();
$body   = $response->getContent();
$data   = json_decode($body, true, 512, JSON_THROW_ON_ERROR);

Class and method names follow the Teknoo\Curl namespace, but the package has no API reference beyond the README and its examples — confirm every accessor (getContent, getStatusCode, header iteration) against src/ before you paste. The shape is reliable; the spellings are not.

Your first real use case is almost always the same: replacing a bare curl_init() block or a file_get_contents() call in a service class with something that has headers, a timeout, and a testable seam.

Implementation Patterns

Never call the transport directly from business logic. The single highest-value thing you can do with an unmaintained dependency is put a one-method interface in front of it, so that the day you migrate to Guzzle the diff is confined to one class:

interface HttpClient
{
    public function send(string $method, string $url, array $headers = [], ?string $body = null): HttpResponse;
}

Implement CurlHttpClient against teknoo/curl-request today; implement GuzzleHttpClient tomorrow. Everything downstream is untouched.

Build a request factory for your recurring headers. Auth tokens, User-Agent, Accept, and a correlation ID appear on every call. Centralize them in one place so you can rotate a token or add tracing without touching fifty call sites. This package does no serialization — you encode JSON yourself and set Content-Type: application/json manually.

Reuse the transport instance. In a worker or a long-running process, construct the transport once in the container and pass it around. Constructing a fresh one per request throws away the cURL handle and any keep-alive benefit, and on a hot loop that is measurable.

Handle two distinct failure modes. cURL-level failures (DNS, connect refused, TLS, timeout) surface as exceptions from the transport. HTTP 4xx/5xx do not — those come back as a normal response object with a status code. Your wrapper should normalize both:

try {
    $response = $transport->send($request);
} catch (\Throwable $e) {
    throw new UpstreamUnavailable($url, previous: $e);
}

if ($response->getStatusCode() >= 400) {
    throw new UpstreamError($url, $response->getStatusCode(), $response->getContent());
}

Put retries in a decorator, not in the caller. Retry only idempotent verbs and only on connection errors and 502/503/504, with exponential backoff and a cap. Retrying a POST on a connect timeout is how you get duplicate orders.

Testing strategy: stub your HttpClient interface for unit tests — do not let a test hit the network. For integration coverage of the transport itself, spin up php -S locally or use a fixture server; that also exercises the TLS/timeout paths you actually care about.

Concurrency: there is none. This is a synchronous, one-request-at-a-time wrapper. If you need to fan out to ten endpoints, either reach for curl_multi yourself or — usually better — push each call onto a queue worker so ten processes each make one blocking call. Do not loop over a batch of API calls in a web request path.

Instrument it. Log method, URL (query string redacted for tokens), status, duration, and cURL error code. Because the library is silent, this logging is your only visibility when something goes wrong at 3am.

Gotchas and Tips

  • Archived means archived. No security patches, ever. If a CVE lands in how the wrapper handles headers or TLS, you own it. Write the migration ticket the day you add the dependency, and fork the repo into a private VCS rather than trusting it to stay on Packagist — owners can delete packages.
  • TLS verification: confirm CURLOPT_SSL_VERIFYPEER and CURLOPT_SSL_VERIFYHOST are left at secure defaults. Older cURL wrappers in this lineage had a habit of disabling them "to make it work" on a dev box; grep the source before shipping to production.
  • Redirects are not followed by default. Many wrappers leave CURLOPT_FOLLOWLOCATION off, so a 301/302 hands you an empty body and a confusing json_decode failure. Set it explicitly, and cap CURLOPT_MAXREDIRS.
  • Timeouts default to none. Set both a connect timeout and a total timeout, per request. Without them a slow upstream parks your PHP-FPM workers until they are all gone.
  • Responses are strings in memory. There is no streaming API here. Downloading a large file will OOM your worker; shell out to curl or use a proper client for that case.
  • Header format quirks. The library takes header strings, not a structured array. Header injection is on you: never interpolate untrusted input into a header value, and strip \r\n.
  • Catch narrowly. Because transport exceptions are the wrapper's own classes, catching \Exception broadly will swallow your own bugs alongside cURL failures. Enumerate the exception types from src/.
  • Extension point: subclass the transport to inject raw cURL options (CURLOPT_HTTP_VERSION, proxy settings, custom CA bundle) or to add timing/metrics around send(). That subclass is also your escape hatch — you can reimplement its single method on top of PSR-18 and keep every caller working.
  • PHP version drift: if the package's require pins a PHP line you have since upgraded past, Composer will refuse to install. --ignore-platform-reqs is not a fix; verify the code actually runs on your runtime, or migrate.
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.
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator
equipc/laravel-email-database-log
adedsec/nova-translated-labels
wazza/laravel-db-encryption
hokny/laravel-generator
vonsogt/backup
jengo/queues
jeremykenedy/laravel-observability
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums