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": "*", 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.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); 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..76b148c 100644 --- a/examples/geetest.php +++ b/examples/geetest.php @@ -4,25 +4,27 @@ 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; // 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/examples/hcaptcha.php b/examples/hcaptcha.php index 6a25033..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()); } -die('Captcha solved: ' . $result->code); +var_dump($result); +die('Captcha ' . $result->captchaId .' solved! Token: ' . $result->code . ' respKey: ' . $result->respKey . ' useragent: ' . $result->useragent); 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); } diff --git a/src/TwoCaptcha.php b/src/TwoCaptcha.php index 32496ef..43953f3 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; @@ -600,11 +603,50 @@ 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; + + 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); + } + unset($result->status); return $result; } @@ -686,15 +728,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 +753,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 +789,7 @@ private function res($query) } $query['key'] = $this->apiKey; + $query['json'] = 1; return $this->apiClient->res($query); } @@ -791,6 +838,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 * diff --git a/tests/AbstractWrapperTestCase.php b/tests/AbstractWrapperTestCase.php index 11d2c7c..fdbb951 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, @@ -90,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 = [