From cd6c683e90f5e2fc1849b9cf201db4b14afb4542 Mon Sep 17 00:00:00 2001 From: kratzky Date: Fri, 9 Aug 2024 10:03:06 -0300 Subject: [PATCH 01/11] use JSON with backwards compatibility --- src/TwoCaptcha.php | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/TwoCaptcha.php b/src/TwoCaptcha.php index 32496ef..e413075 100644 --- a/src/TwoCaptcha.php +++ b/src/TwoCaptcha.php @@ -600,11 +600,16 @@ public function solve($captcha, $waitOptions = []) { $result = new \stdClass(); - $result->captchaId = $this->send($captcha); + $captchaId = $this->send($captcha); if ($this->lastCaptchaHasCallback) return $result; - $result->code = $this->waitForResult($result->captchaId, $waitOptions); + $result = $this->waitForResult($captchaId, $waitOptions); + + $result->captchaId = $captchaId; + $result->code = $result->request; + unset($result->request); + unset($result->status); return $result; } @@ -686,15 +691,19 @@ public function getResult($id) 'id' => $id, ]); - if ($response == 'CAPCHA_NOT_READY') { + $decoded_response = json_decode($response); + + if ($decoded_response->request == 'CAPCHA_NOT_READY') { return null; } - if (mb_strpos($response, 'OK|') !== 0) { + if ($decoded_response->status == 0) { throw new ApiException('Cannot recognise api response (' . $response . ')'); } - return mb_substr($response, 3); + if ($decoded_response->status == 1) { + return $decoded_response; + } } /** @@ -707,8 +716,8 @@ public function getResult($id) public function balance() { $response = $this->res('getbalance'); - - return floatval($response); + $decoded_response = json_decode($response); + return floatval($decoded_response->request); } /** @@ -743,6 +752,7 @@ private function res($query) } $query['key'] = $this->apiKey; + $query['json'] = 1; return $this->apiClient->res($query); } From e77f0cbe7551e503a390f478fbbe280e26610c53 Mon Sep 17 00:00:00 2001 From: kratzky Date: Mon, 12 Aug 2024 13:49:30 -0300 Subject: [PATCH 02/11] fix object processing --- src/TwoCaptcha.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/TwoCaptcha.php b/src/TwoCaptcha.php index e413075..cbe91ba 100644 --- a/src/TwoCaptcha.php +++ b/src/TwoCaptcha.php @@ -607,8 +607,12 @@ public function solve($captcha, $waitOptions = []) $result = $this->waitForResult($captchaId, $waitOptions); $result->captchaId = $captchaId; - $result->code = $result->request; - unset($result->request); + if (is_object($result->request)) { + $result->code = json_encode($result->request); + } else { + $result->code = $result->request; + unset($result->request); + } unset($result->status); return $result; From 3f67629830340cdbb8f496caec751a4eb3b703fc Mon Sep 17 00:00:00 2001 From: kratzky Date: Tue, 13 Aug 2024 13:33:25 -0300 Subject: [PATCH 03/11] fix update tests --- tests/AbstractWrapperTestCase.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tests/AbstractWrapperTestCase.php b/tests/AbstractWrapperTestCase.php index 11d2c7c..3f11faf 100644 --- a/tests/AbstractWrapperTestCase.php +++ b/tests/AbstractWrapperTestCase.php @@ -37,11 +37,16 @@ protected function checkIfCorrectParamsSendAndResultReturned($data) ) ->willReturn('OK|' . $captchaId); + + $resMock = new \stdClass(); + $resMock->status = 1; + $resMock->request = $code; + $apiClient ->expects($this->once()) ->method('res') - ->with($this->equalTo(['action' => 'get', 'id' => $captchaId, 'key' => $apiKey])) - ->willReturn('OK|' . $code); + ->with($this->equalTo(['action' => 'get', 'id' => $captchaId, 'key' => $apiKey, 'json' => 1])) + ->willReturn(json_encode($resMock)); $solver = new TwoCaptcha([ 'apiKey' => $apiKey, From e8106a545bf809f582d16781cd22ec02aa029e9e Mon Sep 17 00:00:00 2001 From: kratzky Date: Wed, 14 Aug 2024 06:05:56 -0300 Subject: [PATCH 04/11] update hCaptcha example --- examples/hcaptcha.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/hcaptcha.php b/examples/hcaptcha.php index 6a25033..ae8d9a7 100644 --- a/examples/hcaptcha.php +++ b/examples/hcaptcha.php @@ -15,4 +15,4 @@ die($e->getMessage()); } -die('Captcha solved: ' . $result->code); +die('Captcha ' . $result->captchaId .' solved! Token: ' . $result->code . ' respKey: ' . $result->respKey . ' useragent: ' . $result->useragent); From b6d690927f0102e3829954372e3b26e1f00b50a4 Mon Sep 17 00:00:00 2001 From: dzmitry-duboyski Date: Wed, 14 Aug 2024 13:37:03 +0400 Subject: [PATCH 05/11] Add test script --- composer.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/composer.json b/composer.json index 7ac3ec7..6a3c35b 100644 --- a/composer.json +++ b/composer.json @@ -30,6 +30,9 @@ "homepage": "https://2captcha.com/" } ], + "scripts": { + "test": "phpunit" + }, "require": { "php": ">=7.3", "ext-curl": "*", From 6145f6fb47f8a3989acf62e19444f742b1f2e410 Mon Sep 17 00:00:00 2001 From: kratzky Date: Wed, 21 Aug 2024 19:01:52 -0300 Subject: [PATCH 06/11] fix grid method --- src/TwoCaptcha.php | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/TwoCaptcha.php b/src/TwoCaptcha.php index cbe91ba..9b7f32d 100644 --- a/src/TwoCaptcha.php +++ b/src/TwoCaptcha.php @@ -467,8 +467,10 @@ public function grid($captcha) } $this->requireFileOrBase64($captcha); + $this->requireHintOrHintImg($captcha); $captcha['method'] = empty($captcha['base64']) ? 'post' : 'base64'; + $captcha['recaptcha'] = 1; return $this->solve($captcha); } @@ -498,7 +500,7 @@ public function canvas($captcha) $captcha['canvas'] = 1; if ( empty($captcha['hintText']) && empty($captcha['hintImg']) ) { - throw new ValidationException('At least one of parameters: hintText or hintImg required!'); + throw new ValidationException('At least one parameter required: hintText or hintImg'); } return $this->solve($captcha); @@ -523,6 +525,7 @@ public function coordinates($captcha) } $this->requireFileOrBase64($captcha); + $this->requireHintOrHintImg($captcha); $captcha['method'] = empty($captcha['base64']) ? 'post' : 'base64'; $captcha['coordinatescaptcha'] = 1; @@ -805,6 +808,18 @@ private function requireFileOrBase64($captcha, $key = 'file') } } + /** + * Validates if grid/coordinates parameters are correct + * + * @param $captcha + * @param string $key + * @throws ValidationException + */ + private function requireHintOrHintImg($captcha) + { + if (empty($captcha['hintText']) && empty($captcha['hintImg'])) throw new ValidationException('At least one parameter: hintText or hintImg is required'); + } + /** * Turns `files` parameter into `file_1`, `file_2`, `file_n` parameters * From 6bb703b2b8ddbac78d6093c31c141f737a2e8867 Mon Sep 17 00:00:00 2001 From: kratzky Date: Tue, 10 Sep 2024 12:53:50 -0300 Subject: [PATCH 07/11] update examples --- examples/canvas.php | 6 ++++-- examples/coordinates_base64.php | 4 +++- examples/geetest.php | 17 +++++++++++------ examples/grid.php | 13 +++++++++++-- src/ApiClient.php | 6 +++--- 5 files changed, 32 insertions(+), 14 deletions(-) diff --git a/examples/canvas.php b/examples/canvas.php index 69b5eb2..1b1ea6e 100644 --- a/examples/canvas.php +++ b/examples/canvas.php @@ -4,7 +4,8 @@ require(__DIR__ . '/../src/autoloader.php'); -$solver = new \TwoCaptcha\TwoCaptcha('YOUR_API_KEY'); +$apikey = getenv("APIKEY"); +$solver = new \TwoCaptcha\TwoCaptcha($apikey); try { $result = $solver->canvas([ @@ -15,4 +16,5 @@ die($e->getMessage()); } -die('Captcha solved: ' . $result->code); +var_dump($result); +// die('Captcha solved: ' . $result->code); diff --git a/examples/coordinates_base64.php b/examples/coordinates_base64.php index 0e6cf32..9c0a047 100644 --- a/examples/coordinates_base64.php +++ b/examples/coordinates_base64.php @@ -7,7 +7,8 @@ $image = __DIR__ . '/images/grid.jpg'; $base64 = base64_encode(file_get_contents($image)); -$solver = new \TwoCaptcha\TwoCaptcha('YOUR_API_KEY'); +$apikey = getenv("APIKEY"); +$solver = new \TwoCaptcha\TwoCaptcha($apikey); try { $result = $solver->coordinates(['base64' => $base64]); @@ -15,4 +16,5 @@ die($e->getMessage()); } +var_dump($result); die('Captcha solved: ' . $result->code); diff --git a/examples/geetest.php b/examples/geetest.php index b63fb6c..7a0cc79 100644 --- a/examples/geetest.php +++ b/examples/geetest.php @@ -4,25 +4,30 @@ require(__DIR__ . '/../src/autoloader.php'); -$solver = new \TwoCaptcha\TwoCaptcha('YOUR_API_KEY'); +$apikey = getenv("APIKEY"); +$solver = new \TwoCaptcha\TwoCaptcha($apikey); // To bypass GeeTest first we need to get new challenge value $ch = curl_init(); -curl_setopt($ch, CURLOPT_URL, "https://mysite.com/captcha_challenge"); +curl_setopt($ch, CURLOPT_URL, "https://2captcha.com/api/v1/captcha-demo/gee-test/init-params?t=" . time()); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); $resp = curl_exec($ch); -$challenge = explode(";", $resp)[0]; +$challenge = json_decode($resp)->challenge; + +var_dump($resp); +var_dump($challenge); // Then we are ready to make a call to 2captcha API try { $result = $solver->geetest([ - 'gt' => 'f2ae6cadcf7886856696502e1d55e00c', - 'apiServer' => 'api-na.geetest.com', + 'gt' => '81388ea1fc187e0c335c0a8907ff2625', + 'apiServer' => 'api.geetest.com', 'challenge' => $challenge, - 'url' => 'https://mysite.com/captcha.html', + 'url' => 'https://2captcha.com/demo/geetest', ]); } catch (\Exception $e) { die($e->getMessage()); } +var_dump($result); die('Captcha solved: ' . $result->code); diff --git a/examples/grid.php b/examples/grid.php index ffe3731..3708ace 100644 --- a/examples/grid.php +++ b/examples/grid.php @@ -4,12 +4,21 @@ require(__DIR__ . '/../src/autoloader.php'); -$solver = new \TwoCaptcha\TwoCaptcha('YOUR_API_KEY'); +$apikey = getenv("APIKEY"); +$solver = new \TwoCaptcha\TwoCaptcha($apikey); try { - $result = $solver->grid(__DIR__ . '/images/grid.jpg'); + $result = $solver->grid([ + 'file' => __DIR__ . '/images/grid_2.jpg', + 'rows' => 3, + 'cols' => 3, + 'lang' => 'en', + // 'hintText' => 'Select all images with an Orange', + 'hintImg' => __DIR__ . '/images/grid_hint.jpg', + ]); } catch (\Exception $e) { die($e->getMessage()); } +var_dump($result); die('Captcha solved: ' . $result->code); diff --git a/src/ApiClient.php b/src/ApiClient.php index dd9e76e..48e828b 100644 --- a/src/ApiClient.php +++ b/src/ApiClient.php @@ -46,7 +46,7 @@ public function in($captcha, $files = []) if (!$this->curl) $this->curl = curl_init(); foreach ($files as $key => $file) { - $captcha[$key] = $this->curlPrepareFile($file); + $captcha[$key] = $this->curlPrepareFile($file, $key); } curl_setopt_array($this->curl, [ @@ -114,10 +114,10 @@ private function execute() * @param $file * @return \CURLFile|string */ - private function curlPrepareFile($file) + private function curlPrepareFile($file, $key = 'file') { if (function_exists('curl_file_create')) { // php 5.5+ - return curl_file_create($file, mime_content_type($file), 'file'); + return curl_file_create($file, mime_content_type($file), $key); } else { return '@' . realpath($file); } From 0a596e2621b8d31acdda539318834e5fef834cda Mon Sep 17 00:00:00 2001 From: kratzky Date: Tue, 10 Sep 2024 12:54:00 -0300 Subject: [PATCH 08/11] update test cases --- tests/AbstractWrapperTestCase.php | 14 ++++++++++++++ tests/CoordinatesTest.php | 20 +++++++++++++------- tests/GridTest.php | 27 +++++++++++++++++++-------- 3 files changed, 46 insertions(+), 15 deletions(-) diff --git a/tests/AbstractWrapperTestCase.php b/tests/AbstractWrapperTestCase.php index 3f11faf..fdbb951 100644 --- a/tests/AbstractWrapperTestCase.php +++ b/tests/AbstractWrapperTestCase.php @@ -95,4 +95,18 @@ protected function checkIfExceptionThrownOnTooManyFiles() $result = $solver->{$this->method}($files); } + + /** + * If required parameters are missing + * should trigger ValidationException + */ + protected function checkIfExceptionThrownOnMissingParameter($data) + { + $this->expectException(ValidationException::class); + + $solver = new TwoCaptcha('API_KEY'); + + $result = $solver->{$this->method}($data['params']); + } + } diff --git a/tests/CoordinatesTest.php b/tests/CoordinatesTest.php index 0159200..6fbc326 100644 --- a/tests/CoordinatesTest.php +++ b/tests/CoordinatesTest.php @@ -8,11 +8,11 @@ class CoordinatesTest extends AbstractWrapperTestCase private $captchaImg = __DIR__ . '/../examples/images/grid.jpg'; - public function testSingleFile() + public function testMissingParameterCase() { - $this->checkIfCorrectParamsSendAndResultReturned([ + $this->checkIfExceptionThrownOnMissingParameter([ 'params' => $this->captchaImg, - 'sendParams' => ['method' => 'post', 'coordinatescaptcha' => 1, 'soft_id' => '4585'], + 'sendParams' => ['method' => 'post', 'coordinatescaptcha' => 1, 'soft_id' => 4585,], 'sendFiles' => ['file' => $this->captchaImg], ]); } @@ -20,8 +20,11 @@ public function testSingleFile() public function testSingleFileParameter() { $this->checkIfCorrectParamsSendAndResultReturned([ - 'params' => ['file' => $this->captchaImg], - 'sendParams' => ['method' => 'post', 'coordinatescaptcha' => 1,'soft_id' => '4585'], + 'params' => [ + 'file' => $this->captchaImg, + 'hintText' => 'Select all images with an Orange', + ], + 'sendParams' => ['method' => 'post', 'coordinatescaptcha' => 1,'soft_id' => '4585', 'textinstructions' => 'Select all images with an Orange'], 'sendFiles' => ['file' => $this->captchaImg], ]); } @@ -29,8 +32,11 @@ public function testSingleFileParameter() public function testBase64() { $this->checkIfCorrectParamsSendAndResultReturned([ - 'params' => ['base64' => '...'], - 'sendParams' => ['method' => 'base64', 'coordinatescaptcha' => 1, 'body' => '...','soft_id' => '4585'], + 'params' => [ + 'base64' => '...', + 'hintText' => 'Select all images with an Orange', + ], + 'sendParams' => ['method' => 'base64', 'coordinatescaptcha' => 1, 'body' => '...','soft_id' => '4585', 'textinstructions' => 'Select all images with an Orange'], 'sendFiles' => [], ]); } diff --git a/tests/GridTest.php b/tests/GridTest.php index a77fc13..2531505 100644 --- a/tests/GridTest.php +++ b/tests/GridTest.php @@ -8,20 +8,30 @@ class GridTest extends AbstractWrapperTestCase private $captchaImg = __DIR__ . '/../examples/images/grid.jpg'; - public function testSingleFile() + public function testMissingParameterCase() { - $this->checkIfCorrectParamsSendAndResultReturned([ + $this->checkIfExceptionThrownOnMissingParameter([ 'params' => $this->captchaImg, - 'sendParams' => ['method' => 'post','soft_id' => '4585'], + 'sendParams' => ['method' => 'post', 'recaptcha' => 1, 'soft_id' => 4585,], 'sendFiles' => ['file' => $this->captchaImg], ]); } + + // public function testSingleFile() + // { + // $this->checkIfCorrectParamsSendAndResultReturned([ + // 'params' => $this->captchaImg, + // 'sendParams' => ['method' => 'post','soft_id' => '4585', 'hintText' => 'Select all images with an Orange'], + // 'sendFiles' => ['file' => $this->captchaImg], + // ]); + // } + public function testSingleFileParameter() { $this->checkIfCorrectParamsSendAndResultReturned([ - 'params' => ['file' => $this->captchaImg], - 'sendParams' => ['method' => 'post','soft_id' => '4585'], + 'params' => ['file' => $this->captchaImg, 'hintText' => 'Select all images with an Orange'], + 'sendParams' => ['method' => 'post', 'recaptcha' => 1, 'soft_id' => 4585, 'textinstructions' => 'Select all images with an Orange'], 'sendFiles' => ['file' => $this->captchaImg], ]); } @@ -29,8 +39,8 @@ public function testSingleFileParameter() public function testBase64() { $this->checkIfCorrectParamsSendAndResultReturned([ - 'params' => ['base64' => '...'], - 'sendParams' => ['method' => 'base64', 'body' => '...','soft_id' => '4585'], + 'params' => ['base64' => '...', 'hintText' => 'Select all images with an Orange'], + 'sendParams' => ['method' => 'base64', 'recaptcha' => 1, 'body' => '...','soft_id' => 4585, 'textinstructions' => 'Select all images with an Orange'], 'sendFiles' => [], ]); } @@ -52,13 +62,14 @@ public function testAllParameters() $sendParams = [ 'method' => 'post', + 'recaptcha' => 1, 'recaptcharows' => 3, 'recaptchacols' => 3, 'previousID' => 0, 'can_no_answer' => 0, 'lang' => 'en', 'textinstructions' => 'Select all images with an Orange', - 'soft_id' => '4585', + 'soft_id' => 4585, ]; $sendFiles = [ From 575cdd93243b5187277ca8c0ecf9ab5c9ac83bea Mon Sep 17 00:00:00 2001 From: kratzky Date: Tue, 10 Sep 2024 16:45:12 -0300 Subject: [PATCH 09/11] canvas & coordinates compatibility format RC-2927 --- src/TwoCaptcha.php | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/TwoCaptcha.php b/src/TwoCaptcha.php index 9b7f32d..43953f3 100644 --- a/src/TwoCaptcha.php +++ b/src/TwoCaptcha.php @@ -610,8 +610,38 @@ public function solve($captcha, $waitOptions = []) $result = $this->waitForResult($captchaId, $waitOptions); $result->captchaId = $captchaId; + if (is_object($result->request)) { $result->code = json_encode($result->request); + } elseif (is_array($result->request) && isset($result->request[0])) { + if (is_object($result->request[0])) { + + $firstElement = $result->request[0]; + + if (isset($firstElement->{"0"}) && is_array($firstElement->{"0"})) { + $code = "canvas:"; + foreach ($result->request[0] as $key => $value) { + $coordinates = []; + foreach ($value as $coord) { + $coordinates[] = $coord->x . ',' . $coord->y; + } + $code .= implode(',', $coordinates) . ';'; + } + $result->canvas = $result->request; + } else { + $coordinates = []; + $code = "coordinates:"; + foreach ($result->request as $coord) { + $coordinates[] = 'x=' . $coord->x . ',' . 'y=' . $coord->y; + } + $code .= implode(';', $coordinates); + $result->coordinates = $result->request; + } + + $result->code = $code; + unset($result->request); + return $result; + } } else { $result->code = $result->request; unset($result->request); From 26f2837693e5bcd89730bcd2cf39fb25c858ae96 Mon Sep 17 00:00:00 2001 From: kratzky Date: Tue, 10 Sep 2024 16:45:58 -0300 Subject: [PATCH 10/11] update examples --- examples/coordinates.php | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/examples/coordinates.php b/examples/coordinates.php index 0dbc2c1..6d6b6ed 100644 --- a/examples/coordinates.php +++ b/examples/coordinates.php @@ -4,12 +4,17 @@ require(__DIR__ . '/../src/autoloader.php'); -$solver = new \TwoCaptcha\TwoCaptcha('YOUR_API_KEY'); +$apikey = getenv("APIKEY"); +$solver = new \TwoCaptcha\TwoCaptcha($apikey); try { - $result = $solver->coordinates(__DIR__ . '/images/grid.jpg'); + $result = $solver->coordinates([ + 'file' => __DIR__ . '/images/grid_2.jpg', + 'hintImg' => __DIR__ . '/images/grid_hint.jpg' + ]); } catch (\Exception $e) { die($e->getMessage()); } -die('Captcha solved: ' . $result->code); +var_dump($result); +// die('Captcha solved: ' . $result->code); From d21b1c38725f9b8e50548f66933625d474c29546 Mon Sep 17 00:00:00 2001 From: kratzky Date: Tue, 10 Sep 2024 16:55:16 -0300 Subject: [PATCH 11/11] update examples --- examples/geetest.php | 3 --- examples/hcaptcha.php | 9 +++++---- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/examples/geetest.php b/examples/geetest.php index 7a0cc79..76b148c 100644 --- a/examples/geetest.php +++ b/examples/geetest.php @@ -14,9 +14,6 @@ $resp = curl_exec($ch); $challenge = json_decode($resp)->challenge; -var_dump($resp); -var_dump($challenge); - // Then we are ready to make a call to 2captcha API try { $result = $solver->geetest([ diff --git a/examples/hcaptcha.php b/examples/hcaptcha.php index ae8d9a7..b595520 100644 --- a/examples/hcaptcha.php +++ b/examples/hcaptcha.php @@ -3,16 +3,17 @@ set_time_limit(130); require(__DIR__ . '/../src/autoloader.php'); - -$solver = new \TwoCaptcha\TwoCaptcha('YOUR_API_KEY'); +$apikey = getenv("APIKEY"); +$solver = new \TwoCaptcha\TwoCaptcha($apikey); try { $result = $solver->hcaptcha([ - 'sitekey' => '10000000-ffff-ffff-ffff-000000000001', - 'url' => 'https://www.site.com/page/', + 'sitekey' => 'c0421d06-b92e-47fc-ab9a-5caa43c04538', + 'url' => 'https://2captcha.com/demo/hcaptcha', ]); } catch (\Exception $e) { die($e->getMessage()); } +var_dump($result); die('Captcha ' . $result->captchaId .' solved! Token: ' . $result->code . ' respKey: ' . $result->respKey . ' useragent: ' . $result->useragent);