PHP में GeeTest v3 कैसे हल करें और परिणाम वापस पोस्ट करें

अधिकांश कैप्चा code मानता है कि एक token अंदर और एक token बाहर। GeeTest इसमें फिट नहीं बैठता। एक हल लौटाता है तीन ऐसे मान जिन्हें एक साथ पोस्ट किया जाना चाहिए, और आपने जो challenge फ़ीड किया था वह जारी होने के लगभग साठ सेकंड बाद एक्सपायर हो जाता है। PHP में, जहाँ काम अक्सर किसी queue पर धकेल दिया जाता है, वह एक्सपायरी एक बहुत ख़ास और बहुत भ्रमित करने वाली किस्म के बग का कारण बनती है।
दो inputs जो अलग-अलग व्यवहार करते हैं
| Value | आजीवन |
|---|---|
gt | प्रति साइट स्थिर। cache करना सुरक्षित |
challenge | Single use, लगभग 60 सेकंड में समाप्त |
दोनों साइट’s के अपने GeeTest init endpoint से आते हैं। यह gt साइट की पहचान करता है; वह challenge प्रति प्रयास होता है और जल्दी खत्म हो जाता है।
Setup
# PHP 8.0+, with the curl and json extensions. composer require capskip/capskip
use CapSkip\CapSkip;
$solver = new CapSkip([
'host' => '127.0.0.1',
'port' => 8080,
'recaptchaTimeout' => 300, // GeeTest uses this, not defaultTimeout
]);defaultTimeout केवल image कैप्चा को नियंत्रित करता है। हर इंटरैक्टिव चीज़, GeeTest सहित, उपयोग करती है recaptchaTimeout.
Solving
$result = $solver->geetest(
'81388ea1fc187e0c335c0a8907ff2625', // gt, static per site
'7cf6a8b1a2c34d5e6f7089abcdef0123', // challenge, fetched seconds ago
'https://example.com/login'
);
echo $result['challenge'];
echo $result['validate'];
echo $result['seccode'];वे तीन keys ही answer हैं। $result['code'] भी भरा जाता है, लेकिन GeeTest के लिए इसमें submit करने योग्य कुछ के बजाय raw JSON string होती है, इसलिए आदतन इसे उठा लेना एक उलझन भरी विफलता पैदा करता है।
इसका उपयोग करें the challenge जो वापस आता है, वह नहीं जो आपने भेजा था। ये हमेशा एक जैसे नहीं होते।
पूरा flow
use CapSkip\CapSkip;
$solver = new CapSkip();
$login = 'https://example.com/login';
// 1. Fresh pair, cache-busted. Cached init responses return spent challenges.
$init = json_decode(file_get_contents(
'https://example.com/geetest/init?t=' . (int) (microtime(true) * 1000)
), true);
// 2. Solve immediately. Nothing slow between here and step 1.
$result = $solver->geetest($init['gt'], $init['challenge'], $login);
// 3. Post all three together with the real form fields.
$ch = curl_init($login);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POSTFIELDS => http_build_query([
'geetest_challenge' => $result['challenge'],
'geetest_validate' => $result['validate'],
'geetest_seccode' => $result['seccode'],
'username' => '...',
'password' => '...',
]),
]);
$response = curl_exec($ch);
curl_close($ch);cache-busting parameter असली काम कर रहा है। GeeTest init endpoints को अक्सर कोई CDN या reverse proxy cache कर लेता है, और एक cached response आपको ऐसा challenge थमा देता है जिसे कोई पहले ही इस्तेमाल कर चुका है।
वे तीनों field नाम सामान्य GeeTest v3 परंपरा हैं, लेकिन कोई site उनका नाम बदल सकती है, इसलिए पहले असली form जांचें।
queue का जाल, जो PHP में और भी बुरा है
PHP applications job queues पर बहुत निर्भर करते हैं, और GeeTest स्पष्ट design के साथ खराब तरीके से इंटरैक्ट करता है। एक ऐसा job dispatch करना जो साथ ले जाता है gt और challenge उचित लगता है और queue में कोई भी backlog होते ही फ़ेल हो जाता है:
// WRONG: the challenge expires while the job waits to be picked up. $init = fetchGeetestPair(); dispatch(new SolveCaptchaJob($init['gt'], $init['challenge'], $url));
इसके बजाय जोड़ी को worker के अंदर fetch करें, ताकि इस्तेमाल होने पर challenge कुछ सेकंड पुराना ही हो:
// RIGHT: the job fetches its own pair at the moment it runs.
class SolveCaptchaJob
{
public function handle(CapSkip $solver): array
{
$init = fetchGeetestPair(); // called inside the worker
return $solver->geetest($init['gt'], $init['challenge'], $this->url);
}
}PHP सिंक्रोनस रूप से निष्पादित होता है और AsyncCapSkip यहाँ केवल एक alias है, इसलिए parallelism SDK से नहीं बल्कि अधिक workers चलाने से आती है।
Errors
use CapSkip\Exceptions\ValidationException;
use CapSkip\Exceptions\NetworkException;
use CapSkip\Exceptions\ApiException;
use CapSkip\Exceptions\TimeoutException;
try {
$result = $solver->geetest($gt, $challenge, $pageUrl);
} catch (ValidationException $e) {
// missing gt or challenge
} catch (NetworkException $e) {
// CapSkip is not running
} catch (ApiException $e) {
// usually a challenge that expired before the solve finished
} catch (TimeoutException $e) {
// exceeded recaptchaTimeout
}ज़्यादातर GeeTest विफलताएँ इस रूप में आती हैं ApiException और इसका मतलब है कि challenge मर गया। उसी जोड़ी के साथ दोबारा प्रयास कभी सफल नहीं होता, क्योंकि एक खर्च हो चुका challenge फिर से वैध नहीं होता।
अक्सर पूछे जाने वाले सवाल
$result[‘code’] उपयोग योग्य क्यों नहीं है?
क्योंकि उत्तर एक के बजाय तीन मान होता है। code पूर्णता के लिए raw JSON रखता है जबकि SDK उपयोगी हिस्सों को विस्तारित कर देता है challenge, validate और seccode। उन तीनों को पोस्ट करें।
क्या मैं challenge को database में स्टोर कर सकता हूँ?
नहीं। यह single use है और लगभग एक मिनट में समाप्त हो जाता है, इसलिए जो कुछ भी इसे बनाए रखता है वह इसे वापस पढ़ने वाली किसी भी चीज़ को एक मृत मान थमा देगा। कैश करें gt अगर आप चाहें; challenge कभी नहीं।
क्या यह GeeTest v4 को कवर करता है?
The geetest method v3 को लक्षित करता है, वह slide puzzle जो एक पर बना है gt और challenge जोड़ी। v4 ने पैरामीटर model बदल दिया, इसलिए मौजूदा जांचें API डॉक्युमेंटेशन यह मानने से पहले कि वही कॉल लागू होती है।
सारांश
एक cache-busted pair fetch करें, तुरंत हल करें, फिर post करें challenge, validate और seccode एक साथ। लौटाए गए challenge का उपयोग करें, केवल कैश करें gt, और किसी चैलेंज को कतार के माध्यम से पास करने के बजाय वर्कर के अंदर फेच करें।
अन्य भाषाएँ इस पर हैं GeeTest solver पेज, इस पर व्यापक PHP सतह PHP कैप्चा सॉल्वर पेज, और हमारे यहाँ एक लाइव पहेली है GeeTest v3 demo। CapSkip संभालता है कैप्चा बायपास लोकल रूप से, इसलिए मात्रा की प्रति हल कोई लागत नहीं।
