alexstack/google-recaptcha-to-any-form
Add Google reCAPTCHA to any Laravel or PHP form with minimal setup. This lightweight package handles token verification and validation, helping protect existing forms from spam and bots. Works with your current form markup, with simple configuration and no major code changes.
The package ships a thin cURL wrapper intended for outbound HTTP calls that the Laravel HTTP client (Illuminate\Support\Facades\Http) doesn't cover cleanly — typically raw cURL options, streaming responses, or legacy endpoints. Start here:
composer require <vendor>/<package> then check composer show <vendor>/<package> to confirm which version you actually resolved. Since 1.4.0 disables TLS verification (see Gotchas), pin explicitly before installing.php artisan vendor:publish --provider="<Vendor>\<Package>\ServiceProvider". If no config file is published, the options are almost certainly hardcoded in the client class — read the source rather than assuming configurability.curl_setopt_array() call. That array is the package's real public API surface and tells you more about behaviour than the README does.If the package has no facade or container binding, resolve it manually and wrap it — you will want a seam for testing regardless.
Wrap the client in your own service. The package's surface is narrow and cURL-heavy; binding it directly into controllers couples your app to its option handling. A small Gateway class that takes the package client via constructor injection gives you a place to normalise errors, add retries, and swap the implementation later.
Configure timeouts explicitly on every call. cURL defaults are effectively unbounded for the connect phase. Set CURLOPT_CONNECTTIMEOUT and CURLOPT_TIMEOUT in one place (your wrapper or a config array) so a hung upstream can't stall a queue worker.
Push slow calls to jobs. Any request that can exceed a second or two belongs in a queued job with $tries and backoff() set. cURL inside a web request is the most common source of Laravel timeouts, and the package won't manage retries for you.
Test at the wrapper boundary. Because the package issues real sockets, use Http::fake() if it delegates to Laravel's client, or bind a fake implementation of your wrapper in the container. Avoid asserting against live endpoints in CI — a network-dependent test suite is a flaky test suite.
Normalise the response before it leaves your wrapper. Return a small DTO (status, headers, body, error) rather than cURL's raw tuple. This keeps curl_errno/curl_error handling in one place and makes logging consistent.
Log outbound calls with correlation IDs. Middleware or a wrapper-level hook that records URL, duration, and status (never credentials or full bodies) pays for itself the first time an upstream returns 200 with an error payload.
Version 1.4.0 hardcodes CURLOPT_SSL_VERIFYPEER => false. This disables certificate verification on every request the package makes, which removes your protection against man-in-the-middle attacks — any network position between your app and the upstream can present an arbitrary certificate and read or alter the traffic. This is not a toggle in the release as described; it is applied unconditionally. Treat it as a security regression:
1.3.x in composer.json until the maintainer makes it configurable, and add a composer audit / dependency check to your pipeline.CURLOPT_SSL_VERIFYPEER => true, CURLOPT_SSL_VERIFYHOST => 2, and an explicit CURLOPT_CAINFO. If it doesn't expose a hook, fork it or replace it.CURLOPT_SSL_VERIFYHOST is a separate option; disabling peer verification alone is already sufficient to break TLS trust, so don't assume setting only VERIFYHOST to 2 recovers the guarantee.Self-signed and internal CAs are the likely motivation for that change. If your upstream uses a private CA, the correct fix is CURLOPT_CAINFO pointing at your CA bundle, or adding the CA to the system store — never blanket-disabling verification. On Docker images, confirm ca-certificates is installed; a missing bundle produces the same "SSL certificate problem" error that tempts people into disabling verification.
Config caching bites. If the package reads config() at construction time inside a service provider, php artisan config:cache can freeze stale values. After any .env change, run php artisan config:clear before debugging anything else.
curl_error() returns an empty string on success — always branch on the return value of curl_exec(), not on the error string. A false return with no error message usually means the handle was reused or the response was empty.
Debug TLS problems with CURLOPT_VERBOSE => true and CURLOPT_STDERR. Write to php://temp and read it back rather than letting verbose output leak into the response body. This shows the certificate chain and where verification failed, which is the fastest way to distinguish an expired cert from a missing CA bundle from a genuinely hostile interception.
Extension points are usually thin. With a single-purpose cURL wrapper there is often no middleware pipeline — plan for a fork or a wrapper class rather than expecting an event hook. Check whether the class is final or has private option assembly before you build on it.
Watch the changelog for further security-relevant cURL options. If CURLOPT_SSL_VERIFYPEER was flipped without fanfare, audit subsequent releases for CURLOPT_FOLLOWLOCATION, redirect limits, and header handling before upgrading.
How can I help you explore Laravel packages today?