zhylon / captcha-php
PHP client for server-side verification of Zhylon Captcha tokens.
Requires
- php: ^8.2
- ext-curl: *
- ext-json: *
Requires (Dev)
- laravel/pint: ^1.30
- pestphp/pest: ^3.0
README
PHP client for server-side verification of Zhylon Captcha tokens.
Installation
composer require zhylon/captcha-php
Usage
use Zhylon\CaptchaPhp\CaptchaClient; $client = new CaptchaClient(secretKey: 'your-secret-key'); $result = $client->verify($_POST['captcha_token'] ?? null); if (! $result->success) { // $result->reason is one of: invalid_token, config_error, network_error // $result->message contains a human-readable explanation abort(403, $result->message); }
CaptchaClient
| Parameter | Type | Default | Description |
|---|---|---|---|
secretKey |
string |
— | Your Zhylon Captcha secret key |
verifyUrl |
string |
https://captcha.zhylon.net/captcha/siteverify |
Verification endpoint |
timeout |
int |
5 |
Request timeout in seconds |
CaptchaResult
| Property | Type | Description |
|---|---|---|
success |
bool |
Whether verification succeeded |
reason |
?string |
invalid_token, config_error, or network_error on failure |
message |
?string |
Human-readable explanation |
Use $result->isTechnicalFailure() to distinguish infrastructure problems (config_error, network_error) from a genuinely invalid token.
Self-hosted challenge/verify proxy
If your widget's JS talks to your own domain instead of captcha.zhylon.net directly, use CaptchaProxy to forward the captcha/challenge and captcha/verify calls to the real Zhylon Captcha host. It reuses the host already configured on your CaptchaClient, so no extra configuration is needed, and it never lets an upstream failure (e.g. a misconfigured endpoint) turn into an uncaught exception — you always get back a status code and a JSON body to relay as-is.
Note: CaptchaProxy::verify() forwards the proof-of-work captcha/verify call (used to obtain a verification_token). It is unrelated to CaptchaClient::verify(), which is the server-side siteverify check performed with your secret key.
use Zhylon\CaptchaPhp\CaptchaClient; use Zhylon\CaptchaPhp\CaptchaProxy; $client = new CaptchaClient(secretKey: 'your-secret-key'); $proxy = CaptchaProxy::forClient($client); Route::get('captcha/challenge', function () use ($proxy) { $response = $proxy->challenge(['sitekey' => request()->get('sitekey')]); return response()->json($response->body, $response->status); }); Route::post('captcha/verify', function () use ($proxy) { $response = $proxy->verify(request()->only(['nonce', 'solve_ms', 'token'])); return response()->json($response->body, $response->status); });
CaptchaProxy
| Parameter | Type | Default | Description |
|---|---|---|---|
baseUrl |
string |
https://captcha.zhylon.net |
Host the challenge/verify calls are forwarded to |
timeout |
int |
5 |
Request timeout in seconds |
Use CaptchaProxy::forClient($client) to derive baseUrl automatically from an existing CaptchaClient's verifyUrl.
On an upstream failure (unreachable host, non-2xx response, or invalid JSON), challenge()/verify() return a CaptchaProxyResponse with status = 502 and a body of ['error' => '...'] instead of throwing.
Testing
composer test
License
The MIT License (MIT). See LICENSE for more information.