PHP में एक Synchronous Request के अंदर ALTCHA कैसे हल करें

solve altcha in php - How to Solve ALTCHA in PHP on a Synchronous Request

PHP में ALTCHA हल करने के लिए आपको एक call चाहिए और कोई ब्राउज़र नहीं। ALTCHA पहचान नहीं, proof of work है: साइट एक challenge जारी करती है और client को तब तक hash करना होता है जब तक वह counter न मिल जाए जो उसे पूरा करे। यहां देखने लायक कुछ होता ही नहीं, इसलिए न WebDriver लगता है और न कोई headless ब्राउज़र, और जवाब अंदाज़े से नहीं, गणना से निकलता है। CapSkip ने यह टाइप version 1.2.6 में जोड़ा और PHP package इसे एक ही method के रूप में देता है। चारों SDK में PHP इकलौता है जिसमें concurrency की कोई कहानी ही नहीं है, और यही बात इस गाइड को आकार देती है: call चलते वक्त आपकी request को रोके रखती है, इसलिए जो चीज़ सही रखनी है वह यह है कि PHP की अपनी सीमाएं सॉल्वर के जवाब देने से पहले request को न काट दें।

आपको क्या चाहिए

  • किसी Windows मशीन पर चल रहा CapSkip 1.2.6 या उसके बाद का संस्करण। ALTCHA सपोर्ट उसी रिलीज़ में आया था।
  • PHP 8.0 या नया, curl और json extensions के साथ, जो ज़्यादातर installs में पहले से आते हैं। package की कोई और runtime dependency नहीं है, इसलिए यह सादी script, Laravel या Symfony, सब में एक जैसा बैठ जाता है।
  • उस page का URL जिस पर widget लगा है, और वह endpoint जिससे widget अपना challenge मांगता है।
  • सॉल्वर के लिए एक address। Local mode सिर्फ़ उसी डिवाइस के लिए 127.0.0.1 पर जवाब देता है; Server mode आपके network address या public IP पर सुनता है ताकि कोई दूसरी मशीन उस तक पहुंच सके। कौन सा लागू होगा यह Step 4 में बताया गया है, और दोनों यहां मिलते हैं: कनेक्शन सेटिंग्स.
# composer require capskip/capskip
composer require capskip/capskip

Step 1: solve call, और challenge कहां से आता है

एक method, दो arguments: पहले page URL, फिर एक options array जिसमें challenge होता है। इसे endpoint थमा दें और CapSkip खुद challenge ले आता है।

// composer require capskip/capskip
require 'vendor/autoload.php';

use CapSkip\CapSkip;

$solver = new CapSkip(['host' => '127.0.0.1', 'port' => 8080]);

// CapSkip fetches the challenge, then hashes until the counter fits.
$result = $solver->altcha('https://example.com/signup', [
    'challenge_url' => 'https://example.com/altcha/challenge',
]);

echo $result['token'];   // base64 payload for the form field
echo $result['number'];  // the counter that satisfied it

लौटाई गई array की दो keys सिर्फ़ ALTCHA की हैं। token वह base64 payload है जो form को चाहिए, और number वह counter है जिसने challenge हल किया। code key में वही string होती है जो token में है, इसलिए दोनों में से कोई भी चलेगा, पर token का नाम उसी field पर है जिसमें वह जाता है और call वाली जगह पर वह ज़्यादा साफ़ पढ़ा जाता है। GeeTest की keys और Turnstile वाला user agent यहां मौजूद नहीं होते।

number को log करना फ़ायदेमंद है। ALTCHA की दोनों पीढ़ियों के लिए यह बताया जाता है, भले ही उनके payload अलग हों: legacy token counter को सबसे ऊपरी स्तर पर रखता है, जबकि proof-of-work v2 token ऐसा नहीं करता और उसे एक solution object के अंदर रखता है। CapSkip उसे सर्वर के अपने जवाब में मौजूद solution object से पढ़ लेता है, इसलिए दोनों पीढ़ियों की जानकारी एक ही तरह से दी जाती है।

वह endpoint ढूंढें जिसे widget मांगता है

DevTools खोलें, Network tab पर जाएं और जिस page पर widget लगा है उसे दोबारा लोड करें। widget अपने challenge के लिए एक request करता है, आम तौर पर ऐसे path पर जिसमें altcha होता है। वही request URL आपको पास करना है, और उससे लौटने वाला JSON ही challenge document है, जिसे आप उसकी जगह पास कर सकते हैं।

जो attribute इसका नाम बताता है उसका अनुमान न लगाएँ, क्योंकि widget की पीढ़ियों के बीच यह बदल चुका है। पेज सोर्स पढ़ें।

Widget पीढ़ीवह attribute जो challenge का नाम बताता है
v1 और v2endpoint के लिए challengeurl, और इनलाइन challenge के लिए अलग challengejson attribute
v3 और उसके बादchallenge, और वही attribute या तो URL लेता है या challenge डेटा

तीनों display styles, यानी native, checkbox और switch, सिर्फ़ दिखने में अलग हैं। तीनों वही payload submit करते हैं और यह फ़र्क सॉल्वर तक कभी पहुंचता ही नहीं, इसलिए आपको यह पता लगाने की ज़रूरत नहीं कि सामने कौन सा है। इन attributes के बारे में ALTCHA ने खुद लिखा है, देखें अपनी इंटीग्रेशन गाइड.

इसके बजाय challenge डॉक्यूमेंट पास करना

अगर आपके code ने challenge पहले ही ले लिया है, तो document पास कर दें और कोई network request होगी ही नहीं। यही रास्ता तब चुनें जब challenge किसी endpoint से नहीं, बल्कि page के अंदर ही जड़ा हुआ आता हो, या जब उसे लाने के लिए ऐसी cookies चाहिए जो आपकी script के पास हैं और सॉल्वर के पास नहीं।

// No fetch happens: the document is already here.
$result = $solver->altcha('https://example.com/signup', [
    'challenge_json' => [
        'algorithm' => 'SHA-256',
        'challenge' => 'YOUR_CHALLENGE_HASH',
        'salt'      => 'YOUR_SALT',
        'signature' => 'YOUR_SIGNATURE',
        'maxnumber' => 1000000,
    ],
]);

यह option एक array लेता है, जिसे आपके लिए serialise कर दिया जाता है, या फिर JSON string अगर वह आपके पास पहले से है। endpoint और document दोनों भेजना मना नहीं है, और ऐसे में inline document जीतता है, क्योंकि fetch करने से वही चीज़ दोबारा मिलेगी जो आपने अभी दी है। हां, load पड़ने पर ये दोनों रास्ते अलग तरह से बर्ताव करते हैं। जो inline challenge पहले ही expire हो चुका है उसे बेकार में hash करने के बजाय सीधे मना कर दिया जाता है, जबकि endpoint देने पर सॉल्वर एक नया challenge ले सकता है, अगर पहला वाला job के queue में पड़े रहने के दौरान खत्म हो गया हो।

solver किन algorithm को कवर करता है

वही एक method दोनों पीढ़ियों को संभालता है। लेगेसी स्कीम SHA-1, SHA-256, SHA-384 और SHA-512 के साथ कवर होती है, और proof-of-work v2 PBKDF2 तथा iterative SHA के साथ कवर होता है। PBKDF2 वही डिफ़ॉल्ट है जिसकी सिफ़ारिश ALTCHA खुद करता है, इसलिए इससे लाइव साइटों का बहुत बड़ा हिस्सा कवर हो जाता है।

Argon2id और scrypt अपवाद हैं, और इन्हें आज़माने के बजाय मना कर दिया जाता है: इनमें से किसी एक वाला task करीब एक तिहाई सेकंड में ERROR_CAPTCHA_UNSOLVABLE के साथ लौट आता है और दोबारा कभी नहीं आज़माया जाता। यह जानबूझकर है। memory-hard function वह चीज़ नहीं है जिसे retry ठीक कर दे, इसलिए व्यस्त दिखने से बेहतर है तुरंत फेल हो जाना। ALTCHA में यह नतीजा किसी न पढ़े जाने वाले image की नहीं, बल्कि algorithm की ओर इशारा करता है, और इस error code के बारे में अलग से भी बताया गया है, देखें अपनी एक अलग गाइड.

Step 2: solve को अपनी execution limit के अंदर रखें

यह हिस्सा खास PHP का है, और यही वह हिस्सा है जो उलझाने वाली failure पैदा करता है। call रुकी रहती है। यहां PHP के पास कोई background task नहीं है और package में मौजूद async client सिर्फ़ एक alias है, जो बाकी SDK से मेल बिठाने के लिए रखा गया है, इसलिए जब तक सॉल्वर काम करता है आपकी request वहीं बैठी रहती है। अब दो घड़ियां एक-दूसरे के खिलाफ़ चल रही हैं, और दोनों की failure बहुत अलग होती है।

ठीक-ठाक चलने वाला ALTCHA solve milliseconds लेता है, इसलिए सामान्य हालात में कोई भी घड़ी मायने नहीं रखती। वे बुरे रास्ते पर मायने रखती हैं: सॉल्वर reCAPTCHA jobs की कतार में उलझा है, और call इंतज़ार करती रहती है। ALTCHA के लिए क्लाइंट की अपनी अधिकतम सीमा 120 सेकंड का डिफ़ॉल्ट polling timeout है, और ALTCHA लंबे reCAPTCHA timeout के बजाय यही इस्तेमाल करता है, क्योंकि यह ब्राउज़र session नहीं, CPU का काम है।

कंस्ट्रक्टर ऑप्शनडिफ़ॉल्टयह क्या कवर करता है
defaultTimeout120 सेकंडALTCHA और इमेज कैप्चा की पोलिंग
recaptchaTimeout300 सेकंडreCAPTCHA, Turnstile और GeeTest की पोलिंग
pollingIntervalअधिकतम 5 सेकंडपोलिंग 0.25 सेकंड से शुरू होती है और बढ़कर इस तक पहुँचती है

इसके सामने, PHP का अपना max_execution_time वेब request पर डिफ़ॉल्ट रूप से 30 सेकंड होता है और command line पर शून्य, यानी कोई सीमा नहीं। solve के दौरान यह चलेगा या नहीं, यह platform पर निर्भर करता है, और इसीलिए यह लोगों को चौंका देता है। Unix जैसे सिस्टम पर यह उस समय को नहीं गिनता जो script किसी socket का इंतज़ार करते हुए बिताती है, इसलिए सॉल्वर का लंबा इंतज़ार पूरी तरह इससे बच निकल सकता है। Windows पर यही setting असल समय में नापी जाती है, इसलिए वहां यह चल जाती है। दोनों ही हालात में इसके ऊपर कुछ और सीमाएं हैं जिन्हें इससे कोई मतलब नहीं: PHP-FPM के पास request_terminate_timeout है, और आगे बैठे वेब सर्वर का अपना read timeout है।

असली फ़र्क यह है कि जब इनमें से कोई एक जीतती है तो आपको क्या मिलता है। अगर पहले SDK का timeout पूरा होता है तो आपको एक TimeoutException मिलता है, जिसे आपका catch block संभालकर एक समझदार response में बदल देता है। और अगर बाकी दोनों में से कोई जीत जाए, तो script सीधे मार दी जाती है और कोई catch block नहीं चलता। ये दोनों भी आपस में एक जैसे नहीं हैं: PHP की अपनी सीमा request को एक fatal error के साथ खत्म करती है, जो आपके error log में दर्ज होता है, और आपकी shutdown functions फिर भी चलती हैं, जबकि worker को मारने वाला process manager या वेब सर्वर कुछ भी नहीं चलाता और आने वाले के हाथ में सिर्फ़ 502 या 504 थमा देता है, जिसमें काम की कोई बात नहीं होती। इसलिए क्लाइंट की सीमा सोच-समझकर तय करें, उससे नीचे जो भी request को काट सकता है।

// Keep the client's ceiling under whatever kills the request.
$solver = new CapSkip([
    'host'           => '127.0.0.1',
    'port'           => 8080,
    'defaultTimeout' => 20,   // ALTCHA and image CAPTCHA polling
]);

जो टाइप आम तौर पर milliseconds में निपट जाता है, उसके लिए बीस सेकंड काफ़ी उदार है, और डिफ़ॉल्ट 30 सेकंड की वेब सीमा के नीचे बाकी request को चलने की जगह भी बच जाती है। command line पर, जहां कोई execution limit नहीं है, डिफ़ॉल्ट को वैसा ही छोड़ दें। अगर कोई solve बार-बार इन आंकड़ों के आसपास पहुंचने लगे तो दिक्कत timeout की नहीं है, दिक्कत यह है कि सॉल्वर तक पहुंच नहीं बन रही या वह भरा हुआ है, और सीमा बढ़ाने से बस request यही बात कहने से पहले और ज़्यादा देर लटकी रहेगी।

स्टेप 3: token को बिना बदले वापस पोस्ट करें, उसके समाप्त होने से पहले

widget अपना payload altcha नाम के फॉर्म फ़ील्ड में सबमिट करता है, इसलिए आपका token भी वहीं जाता है। यही वह स्टेप है जो चुपचाप टूट जाता है।

// Send it exactly as it came back: no trimming,
// no re-encoding, no reordering.
$body = http_build_query([
    'email'  => '[email protected]',
    'altcha' => $result['token'],
]);

$ch = curl_init('https://example.com/signup');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);

token असल में एक JSON document का base64 है, जिसके fields सर्वर के अपने HMAC signature से ढके होते हैं। कोई भी बदलाव उसे बेकार कर देता है, इसलिए सफ़ाई जैसी दिखने वाली हर चीज़ submit को तोड़ देगी: whitespace हटाना, उसे decode करके दोबारा encode करना, या keys का क्रम बदलकर JSON दोबारा बनाना। किसी framework के नेक इरादों वाले input filters से सावधान रहें, क्योंकि बाहर जाने वाले form data पर लगा sanitiser खुशी-खुशी एक अक्षर हटा देगा और आपके पास ऐसा payload बचेगा जो अपने ही signature से मेल नहीं खाता। कुछ integrations payload को form field के बजाय JSON body field से पढ़ते हैं, इसलिए देख लें कि page का अपना submit क्या भेजता है और वही दोहराएं।

यह step दूसरे तरीके से, यानी समय की वजह से फेल होता है। challenge की खिड़की छोटी होती है और कुछ साइटें उसे दो मिनट के अंदर ही बंद कर देती हैं। जब एक expire हो जाता है, तो साइट जवाब को एक सूखी verification failure के साथ मना कर देती है, जो बिल्कुल गलत जवाब जैसी दिखती है, और response में ऐसा कुछ नहीं होता जो बताए कि दोनों में से हुआ क्या। तीन आदतें इससे बचाती हैं: challenge को लंबी run की शुरुआत में नहीं, बल्कि हल करने से ठीक पहले fetch करें, token को उसी request में submit करें जिसने उसे हल किया, और जब तक कोई इंसान form भर रहा हो तब तक token को कभी session में रोककर न रखें।

स्टेप 4: solver कहाँ चलता है, और उसके लिए कौन सा कनेक्शन मोड चाहिए

ऊपर के samples में 127.0.0.1 इसलिए है क्योंकि जब PHP और सॉल्वर एक ही मशीन पर हों तो यही सही है। जैसे ही code कहीं और चलता है, जैसे किसी container, वेब होस्ट, VPS या CI runner पर, loopback सॉल्वर की ओर इशारा करना बंद कर देता है, और पहला ही solve एक NetworkException फेंकता है।

CapSkip को Server mode पर स्विच करें और वह इसके बजाय आपके network address या public IP पर सुनने लगता है, ताकि इनमें से कोई भी उसी HTTP API के ज़रिए उस तक पहुंच सके। जब रास्ता इंटरनेट से होकर जाए तो static public IP की सलाह दी जाती है, साथ में ऐसा firewall rule जो सिर्फ़ उन्हीं addresses को आने दे जिनकी आपको उम्मीद है। Server mode सिर्फ़ यह बदलता है कि सॉल्वर कहां सुनता है, और कुछ नहीं: यह अब भी आपका hardware है, और अब भी unmetered है। host और port को environment से पढ़ें ताकि एक ही deployment दोनों जगह काम करे। client CAPSKIP_HOST या CAPSKIP_PORT को अपने आप नहीं पढ़ता, इसलिए इन्हें constructor को पास करें, जैसा नीचे दिया गया पूरा उदाहरण करता है।

PHP कहां चलता हैकौन-सा कनेक्शन मोड
CapSkip वाली मशीन पर, किसी local dev server या CLI script मेंLocal mode। 127.0.0.1 सचमुच सही है
उसी नेटवर्क पर किसी दूसरी मशीन परServer मोड, उस मशीन के प्राइवेट पते पर
shared hosting पर, VPS पर या किसी container platform परस्टैटिक पब्लिक IP और एक फ़ायरवॉल नियम के साथ Server mode

प्रॉक्सी को लेकर ALTCHA से जुड़ी एक बात। यहाँ प्रॉक्सी सपोर्टेड है, लेकिन उसका इस्तेमाल सिर्फ़ challenge लाने के लिए होता है। रूट करने के लिए कोई ब्राउज़र सेशन होता ही नहीं, इसलिए खुद proof of work पर इसका कोई असर नहीं पड़ता।

पूरा चलने वाला उदाहरण

// composer require capskip/capskip
require 'vendor/autoload.php';

use CapSkip\CapSkip;
use CapSkip\Exceptions\ApiException;
use CapSkip\Exceptions\NetworkException;
use CapSkip\Exceptions\TimeoutException;

$solver = new CapSkip([
    'host'           => getenv('CAPSKIP_HOST') ?: '127.0.0.1',
    'port'           => (int) (getenv('CAPSKIP_PORT') ?: 8080),
    'defaultTimeout' => 20,
]);

try {
    // Fetch, solve and submit inside the one request.
    $result = $solver->altcha('https://example.com/signup', [
        'challenge_url' => 'https://example.com/altcha/challenge',
    ]);

    $body = http_build_query([
        'email'  => '[email protected]',
        'altcha' => $result['token'],
    ]);
    // POST $body to the form here, while the challenge is still fresh.

    echo 'solved at counter ' . $result['number'];
} catch (ApiException $e) {
    // ERROR_CAPTCHA_UNSOLVABLE here means Argon2id or scrypt.
    echo 'refused: ' . $e->getMessage();
} catch (TimeoutException $e) {
    echo 'gave up waiting, before anything could kill the request';
} catch (NetworkException $e) {
    echo 'solver unreachable: check the host and the connection mode';
}

चारों exceptions एक ही common base class से निकलती हैं, इसलिए उसी एक को catch करने से SDK जो भी failure उठा सकता है वह सब एक ही block में संभल जाती है। जब response अलग-अलग हो तो ऊपर की तरह खास exceptions catch करें, और जब अलग न हो तो base class।

बाकी टाइप भी इसी ढांचे के हैं, बस method अलग है। reCAPTCHA वाली call एक sitekey और एक page URL लेती है, Turnstile भी इसी तरह काम करता है, GeeTest page URL के साथ एक gt value और एक challenge लेता है, और image solving एक file path, एक URL या base64 लेता है। पूरी method सूची के लिए देखें PHP कैप्चा सॉल्वर पेज.

Turnstile इकलौता ऐसा टाइप है जिसे पूरे challenge page के रूप में आने पर sitekey से ज़्यादा की ज़रूरत पड़ती है। उसकी अतिरिक्त values के बारे में जानने के लिए देखें PHP Turnstile गाइड.

आम errors और उनका मतलब

आप जो देखते हैंकारणफिक्स
502 या 504, log में कुछ नहीं, और कोई catch block चला ही नहींSDK के हार मानने से पहले ही process manager या वेब सर्वर ने request को मार दियाdefaultTimeout को FPM के terminate timeout और upstream के read timeout से नीचे रखें
PHP log में maximum-execution-time वाली एक fatal error, और कोई catch block चला ही नहींPHP की अपनी सीमा ने request को पहले खत्म कर दियाdefaultTimeout को max_execution_time से नीचे रखें
एक TimeoutException, जो बताता है कि उसने कितने सेकंड इंतज़ार कियासॉल्वर ने क्लाइंट की सीमा के भीतर जवाब नहीं दियादेख लें कि सॉल्वर चल रहा है और भरा हुआ नहीं है। सीमा बढ़ाने से वही जवाब बस देर से मिलेगा
साइट से एक सूखी वेरिफ़िकेशन फेल्योर, जबकि token ठीक दिखता हैफॉर्म सबमिट होने से पहले ही challenge समाप्त हो गयाfetch, solve और submit एक ही request में करें
ApiException के अंदर ERROR_CAPTCHA_UNSOLVABLE, करीब एक तिहाई सेकंड मेंchallenge Argon2id या scrypt इस्तेमाल करता हैदोबारा कोशिश करने जैसा कुछ नहीं। वे दोनों जानबूझकर मना किए जाते हैं
कॉल पर एक ValidationExceptionकोई भी challenge ऑप्शन नहीं दिया गया, या ऐसा ऑप्शन पास किया गया जो ALTCHA नहीं लेताchallenge endpoint या challenge डॉक्यूमेंट पास करें, और बाकी सब हटा दें
पहले solve पर एक NetworkExceptionCapSkip चल नहीं रहा, या host और port गलत हैंCapSkip शुरू करें, फिर तय करें कि वह Local mode में रहेगा या Server mode में
array में token key मौजूद नहीं हैवह key सिर्फ़ ALTCHA के लिए भरी जाती हैALTCHA वाली method कॉल करें। ALTCHA के result में code key में वही string होती है
फॉर्म ऐसे token को ठुकरा देता है जिसे आपके लॉग हल हुआ दिखाते हैंकिसी चीज़ ने payload को दोबारा एनकोड किया, ट्रिम किया या उसका क्रम बदल दियास्ट्रिंग को जैसी है वैसी ही, बिना छेड़े आगे भेजें

FAQ

क्या PHP में ALTCHA हल करने के लिए ब्राउज़र चाहिए?

नहीं, और यही बात इसे PHP के लिए बढ़िया बनाती है। ALTCHA देखने लायक कुछ नहीं, बल्कि एक hashing problem देता है, इसलिए काम सिर्फ़ CPU का है और milliseconds में पूरा हो जाता है। न कोई WebDriver इंस्टॉल करना है और न अपने वेब सर्वर के बगल में कोई Chromium ज़िंदा रखना है, और यही वह हिस्सा है जो ब्राउज़र से चलने वाले कैप्चा टाइप को PHP से संभालना झंझट बना देता है। curl वाली एक सादी script काफ़ी है।

क्या shared hosting या VPS पर चल रहा PHP सॉल्वर तक पहुंच सकता है?

हां। connection settings में CapSkip को Server mode पर स्विच करें ताकि वह loopback के बजाय किसी network address पर सुने, फिर host वाले environment variable को उसी address पर लगा दें। shared hosting, VPS, container platform और CI runner, सब एक ही तरह से, उसी HTTP API के ज़रिए जुड़ते हैं। अगर रास्ता इंटरनेट से होकर जाता है तो static public IP इस्तेमाल करें, और उसे firewall rule से सीमित रखें। इन सब मामलों में सॉल्वर आपके अपने hardware पर ही रहता है, इसलिए लाइसेंस या हल की गिनती में कुछ नहीं बदलता।

क्या मैं PHP में एक साथ कई ALTCHA challenges हल कर सकता हूं?

एक ही script से नहीं। PHP client synchronous है और package में async नाम सिर्फ़ एक alias है, जो इसलिए रखा गया है कि चारों SDK एक जैसे पढ़े जाएं, कोई दूसरा implementation नहीं, इसलिए calls एक के बाद एक चलती हैं। यहां concurrency का मतलब है कई worker processes चलाना, PHP आम तौर पर यह काम ऐसे ही करता है। इस टाइप के लिए यह कम ही मायने रखता है, क्योंकि एक solve बस कुछ milliseconds की hashing है, पर इसके भरोसे कोई बड़ा bulk run बनाने से पहले यह जान लेना ज़रूरी है।

क्या मुझे वेब request के दौरान हल करना चाहिए या किसी queued job में?

जब submit उसी request में होता हो, जो आम बात है, तो request में ही हल करें, क्योंकि challenge की खिड़की छोटी होती है और queued job बिना किसी फ़ायदे के देरी जोड़ देती है। इसे worker में तब ले जाएं जब आसपास का काम पहले से ही asynchronous हो, जैसे कोई स्क्रैपर जो कई pages पर घूम रहा हो। जो आपको हरगिज़ नहीं करना है वह है दोनों को अलग कर देना: एक request में challenge लाना और उसे बाद की किसी job में हल करना, यही वह इंतज़ाम है जो साइट को expire हो चुका जवाब थमाने की सबसे ज़्यादा आशंका रखता है।

संक्षेप में

challenge endpoint को widget से पढ़ें, उसे page URL के साथ उस इकलौती ALTCHA method को दें, और token को बिना छुए altcha नाम वाले field में वापस भेज दें। क्लाइंट का डिफ़ॉल्ट timeout उससे नीचे रखें जो भी request को पहले मार सकता है, क्योंकि जिस TimeoutException को आप catch कर सकें वह उस request से कहीं ज़्यादा कीमती है जिसे process manager खत्म कर देता है। fetch, solve और submit को एक ही request में रखें, क्योंकि challenge की खिड़की दो मिनट के अंदर बंद हो सकती है और expire हो चुका challenge बिल्कुल गलत जवाब जैसा दिखता है। जिस पल PHP सॉल्वर वाली मशीन से अलग हो जाए, उसी पल Server mode पर स्विच कर दें।

आखिरी बात, जो आपके retry के डिज़ाइन को बदल देती है। क्योंकि इस तरीके से होने वाला कैप्चा बायपास proof of work उसी मशीन पर करता है जो पहले से आपकी अपनी है, इसलिए समाप्त हो चुके challenge को दोबारा आज़माने में आपके अपने CPU के कुछ मिलीसेकंड के अलावा कुछ खर्च नहीं होता, इसलिए आप बासी challenge को सँभालने के बजाय नया challenge लाने की छूट रख सकते हैं।