PHP'de GeeTest v3 Nasıl Çözülür ve Sonuç Geri Nasıl Gönderilir

Çoğu CAPTCHA kodu bir token girişi ve bir token çıkışı varsayar. GeeTest buna uymaz. Bir çözüm şunu döndürür: üç birlikte gönderilmesi gereken değerler ve verdiğiniz challenge, verildikten kabaca altmış saniye sonra sona erer. İşlerin genellikle bir kuyruğa itildiği PHP'de bu sona erme, çok özel ve çok kafa karıştırıcı bir hata sınıfına neden olur.
Farklı davranan iki girdi
| Değer | Ömür boyu |
|---|---|
gt | Site başına statik. Önbelleğe almak güvenli |
challenge | Tek kullanımlık, yaklaşık 60 saniyede ölür |
İkisi de sitenin’ kendi GeeTest init endpoint'inden gelir. gt siteyi tanımlar; challenge deneme başınadır ve hızla yok olur.
Kurulum
# 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 yalnızca görüntü CAPTCHA'larını yönetir. GeeTest dahil etkileşimli olan her şey şunu kullanır: recaptchaTimeout.
Çözme
$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'];Bu üç anahtar cevaptır. $result['code'] da doldurulur, ancak GeeTest için gönderilebilir bir şey yerine ham JSON dizesini tutar; dolayısıyla onu alışkanlıkla almak kafa karıştırıcı bir başarısızlığa yol açar.
Şunu kullanın: challenge gönderdiğiniz değil, geri gelen. Bunlar her zaman aynı değildir.
Akışın tamamı
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);Önbellek kırıcı parametre gerçekten iş görür. GeeTest init uç noktaları genellikle bir CDN veya ters proxy tarafından önbelleğe alınır ve önbelleğe alınmış bir yanıt size birinin zaten tükettiği bir challenge verir.
O üç alan adı olağan GeeTest v3 kuralıdır, ancak bir site bunları yeniden adlandırabilir, bu yüzden önce gerçek formu kontrol edin.
Kuyruk tuzağı, ki bu PHP'de daha kötüdür
PHP uygulamaları büyük ölçüde iş kuyruklarına dayanır ve GeeTest bariz tasarımla kötü etkileşime girer. Şunu taşıyan bir işi göndermek: gt ve challenge makul görünür ve kuyrukta herhangi bir birikim olur olmaz başarısız olur:
// WRONG: the challenge expires while the job waits to be picked up. $init = fetchGeetestPair(); dispatch(new SolveCaptchaJob($init['gt'], $init['challenge'], $url));
Bunun yerine çifti worker içinde getirin, böylece challenge kullanıldığında yalnızca birkaç saniyelik olur:
// 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 eşzamanlı (senkron) olarak çalışır ve AsyncCapSkip burada yalnızca bir takma addır (alias), bu yüzden paralellik SDK'dan değil, daha fazla worker çalıştırmaktan gelir.
Hatalar
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
}Çoğu GeeTest hatası şu şekilde gelir: ApiException ve challenge'ın öldüğü anlamına gelir. Aynı çiftle yeniden denemek asla başarılı olmaz, çünkü harcanmış bir challenge tekrar geçerli hale gelmez.
Sık sorulan sorular
$result[‘code’] neden kullanılabilir değil?
Çünkü yanıt bir yerine üç değerdir. code eksiksizlik için ham JSON'u korurken, SDK yararlı kısımları şuraya genişletir: challenge, validate ve seccode. Bu üçünü gönderin.
Doğrulamayı veritabanında saklayabilir miyim?
Hayır. Tek kullanımlıktır ve yaklaşık bir dakikada süresi dolar, bu yüzden onu kalıcı hale getiren her şey, onu geri okuyan her neyse ona ölü bir değer verir. Şunu önbelleğe alın: gt isterseniz; asla doğrulamayı değil.
Bu, GeeTest v4'ü kapsıyor mu?
The geetest metodu v3'ü hedefler, bir şeyin üzerine kurulan kaydırma bulmacası: gt ve challenge çift. v4 parametre modelini değiştirdi, bu yüzden geçerli olanı kontrol edin API dokümantasyonu aynı çağrının geçerli olduğunu varsaymadan önce.
Özet
Önbelleği atlatılmış bir çift alın, hemen çözün, sonra gönderin challenge, validate ve seccode birlikte. Döndürülen challenge'ı kullanın, yalnızca şunu önbelleğe alın: gt, ve bir sorguyu kuyruktan geçirmek yerine worker'ın içinde getirin.
Diğer diller şuradadır: GeeTest çözücü sayfa, daha geniş PHP yüzeyi şurada: PHP CAPTCHA çözücü sayfası ve bizim üzerimizde canlı bir bulmaca var GeeTest v3 demosu. CapSkip şunları işler: captcha atlatma yerel olarak; dolayısıyla hacim, çözüm başına hiçbir maliyet oluşturmaz.
