Cara Memecahkan GeeTest v3 di PHP dan Mengirim Hasilnya Kembali

solve geetest in php - How to Solve GeeTest v3 in PHP and Post the Result Back

Sebagian besar kode CAPTCHA mengasumsikan satu token masuk dan satu token keluar. GeeTest tidak cocok dengan itu. Satu pemecahan mengembalikan tiga nilai yang harus dikirim bersama-sama, dan challenge yang Anda masukkan kedaluwarsa kira-kira enam puluh detik setelah diterbitkan. Di PHP, tempat pekerjaan sering didorong ke antrean, masa kedaluwarsa itu menimbulkan jenis bug yang sangat spesifik dan sangat membingungkan.

Dua input yang berperilaku berbeda

NilaiSeumur hidup
gtStatis per situs. Aman untuk di-cache
challengeSekali pakai, mati dalam sekitar 60 detik

Keduanya berasal dari endpoint init GeeTest milik situs itu sendiri. Nilai gt mengidentifikasi situs; challenge berlaku per percobaan dan cepat kedaluwarsa.

Penyiapan

# 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 hanya mengatur CAPTCHA gambar. Semua yang interaktif, termasuk GeeTest, menggunakan recaptchaTimeout.

Pemecahan

$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'];

Ketiga kunci itulah jawabannya. $result['code'] juga terisi, tetapi untuk GeeTest isinya string JSON mentah alih-alih sesuatu yang bisa dikirim, jadi mengambilnya karena kebiasaan menghasilkan kegagalan yang membingungkan.

Gunakan challenge yang dikembalikan, bukan yang Anda kirimkan. Keduanya tidak selalu sama.

Seluruh alur

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);

Parameter cache-busting benar-benar berperan. Endpoint init GeeTest sering di-cache oleh CDN atau reverse proxy, dan respons yang di-cache memberi Anda tantangan yang sudah dipakai orang lain.

Ketiga nama field itu adalah konvensi umum GeeTest v3, tetapi sebuah situs bisa mengganti namanya, jadi periksa dulu formulir aslinya.

Jebakan antrean, yang lebih parah di PHP

Aplikasi PHP sangat bergantung pada job queue, dan GeeTest bereaksi buruk terhadap desain yang paling jelas. Mengirim job yang membawa gt dan challenge terlihat masuk akal dan gagal begitu antrean memiliki tumpukan:

// WRONG: the challenge expires while the job waits to be picked up.
$init = fetchGeetestPair();
dispatch(new SolveCaptchaJob($init['gt'], $init['challenge'], $url));

Sebagai gantinya, ambil pasangan itu di dalam worker, agar challenge-nya baru berumur beberapa detik saat dipakai:

// 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 dieksekusi secara sinkron dan AsyncCapSkip di sini hanyalah alias, jadi paralelisme berasal dari menjalankan lebih banyak worker, bukan dari SDK.

Kesalahan

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
}

Sebagian besar kegagalan GeeTest muncul sebagai ApiException dan berarti tantangan sudah mati. Mencoba ulang dengan pasangan yang sama tidak akan pernah berhasil, karena challenge yang sudah terpakai tidak akan valid lagi.

Pertanyaan yang sering diajukan

Mengapa $result[‘code’] tidak dapat digunakan?

Karena jawabannya terdiri dari tiga nilai, bukan satu. code menyimpan JSON mentahnya demi kelengkapan sementara SDK memperluas bagian yang berguna menjadi challenge, validate dan seccode. Kirim ketiganya.

Bisakah saya menyimpan challenge di dalam basis data?

Tidak. Nilainya sekali pakai dan kedaluwarsa dalam sekitar satu menit, jadi apa pun yang menyimpannya akan menyerahkan nilai mati ke apa pun yang membacanya kembali. Simpan di cache gt jika Anda mau; tetapi tidak pernah challenge-nya.

Apakah ini mencakup GeeTest v4?

The geetest metode menargetkan v3, teka-teki geser yang dibangun di atas gt dan challenge pasangan. v4 mengubah model parameternya, jadi periksa versi terkini dari dokumentasi API sebelum menganggap panggilan yang sama berlaku.

Ringkasan

Ambil pasangan yang bebas cache, pecahkan segera, lalu kirim challenge, validate dan seccode bersama-sama. Gunakan challenge yang dikembalikan, cache hanya gt, dan lakukan pengambilan di dalam worker alih-alih meneruskan challenge melalui antrean.

Bahasa lain ada di pemecah GeeTest , cakupan PHP yang lebih luas ada di halaman pemecah CAPTCHA PHP , dan ada puzzle langsung di halaman kami Demo GeeTest v3. CapSkip menangani bypass captcha secara lokal, sehingga volume tidak memakan biaya per pemecahan.