Solver captcha in PHP con cURL: esempio funzionante (2026)
Per risolvere un captcha con PHP serve solo l'estensione cURL, che è presente nella maggior parte delle installazioni. Invii una POST JSON all'API di Scarnox, leggi solution.token dalla risposta e invii quel token al form del sito. Questa guida percorre l'intero flusso PHP per PopularCaptcha, che Scarnox risolve oggi in modalità proxyless.
Inizia con crediti di prova gratuiti, senza carta di credito e prova lo script su una pagina che controlli prima di usarlo altrove.
Requisiti
- PHP 8.0 o successivo, con le estensioni
curlejsonabilitate. Verifica conphp -m. - Una chiave API di Scarnox.
- La sitekey del widget PopularCaptcha della pagina. Per aiuto a trovarla, vedi come trovare la sitekey di un captcha.
La funzione solver
Questa funzione invia la richiesta all'API, controlla errorId e restituisce il token. Lancia un'eccezione per qualsiasi errore, così chi chiama può decidere se riprovare:
<?php
declare(strict_types=1);
const SCARNOX_API_KEY = 'scarnox_YOURAPIKEY';
const SCARNOX_API_URL = 'https://api.scarnox.com/api/tasks/create';
function solveCaptcha(string $sitekey, string $pageUrl, bool $invisible = false): string
{
$body = [
'captcha_type' => 'PopularCaptchaTaskProxyless',
'site_key' => $sitekey,
'site_url' => $pageUrl,
];
if ($invisible) {
$body['is_invisible'] = true;
}
$ch = curl_init(SCARNOX_API_URL);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($body, JSON_THROW_ON_ERROR),
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . SCARNOX_API_KEY,
'Content-Type: application/json',
],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 185, // la chiamata ritorna quando il token è pronto
]);
$raw = curl_exec($ch);
if ($raw === false) {
$error = curl_error($ch);
throw new RuntimeException('cURL error: ' . $error);
}
$data = json_decode((string) $raw, true);
if (!is_array($data)) {
throw new RuntimeException('Response was not JSON');
}
if (($data['errorId'] ?? 1) !== 0) {
throw new RuntimeException(
($data['errorCode'] ?? 'ERROR') . ': ' . ($data['errorDescription'] ?? 'unknown')
);
}
return (string) $data['solution']['token'];
}
L'header Authorization usa il prefisso Bearer. Il timeout è di 185 secondi perché l'API si blocca finché il token non è pronto, senza passaggi di polling.
Riprova gli errori temporanei
Una risoluzione fallita non viene addebitata, quindi qualche retry costa poco. Metti un ciclo attorno alla chiamata e attendi un po' di più dopo ogni errore:
function solveWithRetry(string $sitekey, string $pageUrl, int $attempts = 3): string
{
$lastError = null;
for ($i = 1; $i <= $attempts; $i++) {
try {
return solveCaptcha($sitekey, $pageUrl);
} catch (RuntimeException $e) {
$lastError = $e;
fwrite(STDERR, "Attempt $i failed: " . $e->getMessage() . PHP_EOL);
sleep($i);
}
}
throw $lastError;
}
Per una politica di errori completa, incluse le situazioni in cui fermarsi, vedi gestione degli errori del solver captcha.
Invia il token con un cookie jar
Molti siti legano il captcha alla sessione che ha caricato il form. Un file di cookie permette a cURL di inviare gli stessi cookie nella GET e nella POST. La funzione seguente invia il token al form della pagina:
function submitToken(string $pageUrl, string $token): string
{
$cookieFile = sys_get_temp_dir() . '/scarnox-cookies.txt';
// Prima GET, così il sito imposta il cookie di sessione.
$ch = curl_init($pageUrl);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_COOKIEFILE => $cookieFile,
CURLOPT_COOKIEJAR => $cookieFile,
CURLOPT_TIMEOUT => 60,
]);
curl_exec($ch);
// Poi POST del form con il token in entrambi i campi captcha.
$fields = http_build_query([
'email' => 'you@example.com',
'h-captcha-response' => $token,
'g-recaptcha-response' => $token,
]);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $fields,
CURLOPT_TIMEOUT => 60,
]);
$body = curl_exec($ch);
if ($body === false) {
throw new RuntimeException('Form submit failed: ' . curl_error($ch));
}
return (string) $body;
}
Contano due cose. La GET avviene prima della risoluzione, così il cookie è già presente. E il token parte subito dopo la risoluzione, perché scade in circa due minuti. Metti la chiamata di risoluzione direttamente prima di questa funzione, non all'inizio di un lungo batch.
Il file dei cookie è condiviso da tutte le chiamate nello stesso processo, quindi assegna un file separato a ogni account o sessione se esegui più registrazioni in parallelo. Altrimenti una sessione può sovrascrivere i cookie di un'altra, e la seconda POST fallirà per motivi che sembrano un problema di captcha ma non lo sono.
Mettere tutto insieme
$pageUrl = 'https://example.com/signup';
$token = solveWithRetry('YOUR-SITEKEY-UUID', $pageUrl);
$html = submitToken($pageUrl, $token);
echo strlen($html) . " bytes returned\n";
Eseguilo dalla riga di comando:
php signup.php
Widget invisibili
Se il widget è invisibile, chiama solveCaptcha($sitekey, $pageUrl, true). Il campo is_invisible viene inviato con la richiesta. Alcune pagine richiedono anche una callback JavaScript chiamata con il token, che uno script lato server non può attivare. In quel caso usa invece uno strumento per il browser. La guida sul captcha invisibile tratta i casi.
Tempistiche e scadenza
Il token è valido per circa due minuti. Tieni vicini la risoluzione e l'invio. Scadenza del token captcha spiega come distinguere un token scaduto da uno rifiutato.
Scraping responsabile
Se il tuo script PHP fa scraping di pagine pubbliche, controlla robots.txt e i termini del sito prima di iniziare. Aggiungi un ritardo tra le richieste e non conservare dati personali che non ti servono. Risolvere un captcha non cambia ciò che sei autorizzato a raccogliere. Per l'aspetto legale, vedi il web scraping è legale.
Prezzi
Paghi per ogni risoluzione riuscita. Le risoluzioni fallite non vengono addebitate. Consulta i prezzi attuali per le tariffe, e inizia con crediti di prova gratuiti, senza carta di credito.