pax_global_header00006660000000000000000000000064136407013760014521gustar00rootroot0000000000000052 comment=614f25a9038be4f3f2da7cbfd778dc5b357d2419 recaptcha-1.2.4/000077500000000000000000000000001364070137600134575ustar00rootroot00000000000000recaptcha-1.2.4/.github/000077500000000000000000000000001364070137600150175ustar00rootroot00000000000000recaptcha-1.2.4/.github/ISSUE_TEMPLATE/000077500000000000000000000000001364070137600172025ustar00rootroot00000000000000recaptcha-1.2.4/.github/ISSUE_TEMPLATE/bug_report.md000066400000000000000000000015201364070137600216720ustar00rootroot00000000000000--- name: PHP client issue about: Report an issue with the PHP client library --- **Issue description** **Environment** * OS name and version: * PHP version: * Web server name and version: * `google/recaptcha` version: * Browser name and version: **Reproducing the issue** * URL (optional): * Code (optional): ***User steps*** 1. Visit page... recaptcha-1.2.4/.gitignore000066400000000000000000000001561364070137600154510ustar00rootroot00000000000000/.php_cs.cache /.phpunit.result.cache /build /composer.lock /examples/config.php /nbproject/private/ /vendor/ recaptcha-1.2.4/.travis.yml000066400000000000000000000011711364070137600155700ustar00rootroot00000000000000dist: trusty language: php sudo: false php: - '5.5' - '5.6' - '7.0' - '7.1' - '7.2' - '7.3' before_script: - composer install - phpenv version-name | grep ^5.[34] && echo "extension=apc.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini ; true - phpenv version-name | grep ^5.[34] && echo "apc.enable_cli=1" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini ; true script: - mkdir -p build/logs - composer run-script lint - composer run-script test after_success: - travis_retry php vendor/bin/php-coveralls cache: directories: - "$HOME/.composer/cache/files" git: depth: 5 recaptcha-1.2.4/ARCHITECTURE.md000066400000000000000000000047451364070137600156750ustar00rootroot00000000000000# Architecture The general pattern of usage is to instantiate the `ReCaptcha` class with your secret key, specify any additional validation rules, and then call `verify()` with the reCAPTCHA response and user's IP address. For example: ```php setExpectedHostname('recaptcha-demo.appspot.com') ->verify($gRecaptchaResponse, $remoteIp); if ($resp->isSuccess()) { // Verified! } else { $errors = $resp->getErrorCodes(); } ``` By default, this will use the [`stream_context_create()`](https://secure.php.net/stream_context_create) and [`file_get_contents()`](https://secure.php.net/file_get_contents) to make a POST request to the reCAPTCHA service. This is handled by the [`RequestMethod\Post`](./src/ReCaptcha/RequestMethod/Post.php) class. ## Alternate request methods You may need to use other methods for making requests in your environment. The [`ReCaptcha`](./src/ReCaptcha/ReCaptcha.php) class allows an optional [`RequestMethod`](./src/ReCaptcha/RequestMethod.php) instance to configure this. For example, if you want to use [cURL](https://secure.php.net/curl) instead you can do this: ```php setExpectedHostname('recaptcha-demo.appspot.com') ->verify($gRecaptchaResponse, $remoteIp); if ($resp->isSuccess()) { // Verified! } else { $errors = $resp->getErrorCodes(); } ``` The following methods are available: - `setExpectedHostname($hostname)`: ensures the hostname matches. You must do this if you have disabled "Domain/Package Name Validation" for your credentials. - `setExpectedApkPackageName($apkPackageName)`: if you're verifying a response from an Android app. Again, you must do this if you have disabled "Domain/Package Name Validation" for your credentials. - `setExpectedAction($action)`: ensures the action matches for the v3 API. - `setScoreThreshold($threshold)`: set a score threshold for responses from the v3 API - `setChallengeTimeout($timeoutSeconds)`: set a timeout between the user passing the reCAPTCHA and your server processing it. Each of the `set`\*`()` methods return the `ReCaptcha` instance so you can chain them together. For example: ```php setExpectedHostname('recaptcha-demo.appspot.com') ->setExpectedAction('homepage') ->setScoreThreshold(0.5) ->verify($gRecaptchaResponse, $remoteIp); if ($resp->isSuccess()) { // Verified! } else { $errors = $resp->getErrorCodes(); } ``` You can find the constants for the libraries error codes in the `ReCaptcha` class constants, e.g. `ReCaptcha::E_HOSTNAME_MISMATCH` For more details on usage and structure, see [ARCHITECTURE](ARCHITECTURE.md). ### Examples You can see examples of each reCAPTCHA type in [examples/](examples/). You can run the examples locally by using the Composer script: ```sh composer run-script serve-examples ``` This makes use of the in-built PHP dev server to host the examples at http://localhost:8080/ These are also hosted on Google AppEngine Flexible environment at https://recaptcha-demo.appspot.com/. This is configured by [`app.yaml`](./app.yaml) which you can also use to [deploy to your own AppEngine project](https://cloud.google.com/appengine/docs/flexible/php/download). ## Contributing No one ever has enough engineers, so we're very happy to accept contributions via Pull Requests. For details, see [CONTRIBUTING](CONTRIBUTING.md) recaptcha-1.2.4/app.yaml000066400000000000000000000001271364070137600151230ustar00rootroot00000000000000runtime: php env: flex skip_files: - tests runtime_config: document_root: examples recaptcha-1.2.4/composer.json000066400000000000000000000023271364070137600162050ustar00rootroot00000000000000{ "name": "google/recaptcha", "description": "Client library for reCAPTCHA, a free service that protects websites from spam and abuse.", "type": "library", "keywords": ["recaptcha", "captcha", "spam", "abuse"], "homepage": "https://www.google.com/recaptcha/", "license": "BSD-3-Clause", "support": { "forum": "https://groups.google.com/forum/#!forum/recaptcha", "source": "https://github.com/google/recaptcha" }, "require": { "php": ">=5.5" }, "require-dev": { "phpunit/phpunit": "^4.8.36|^5.7.27|^6.59|^7.5.11", "friendsofphp/php-cs-fixer": "^2.2.20|^2.15", "php-coveralls/php-coveralls": "^2.1" }, "autoload": { "psr-4": { "ReCaptcha\\": "src/ReCaptcha" } }, "extra": { "branch-alias": { "dev-master": "1.2.x-dev" } }, "scripts": { "lint": "vendor/bin/php-cs-fixer -vvv fix --using-cache=no --dry-run .", "lint-fix": "vendor/bin/php-cs-fixer -vvv fix --using-cache=no .", "test": "vendor/bin/phpunit --colors=always", "serve-examples": "@php -S localhost:8080 -t examples" }, "config": { "process-timeout": 0 } } recaptcha-1.2.4/examples/000077500000000000000000000000001364070137600152755ustar00rootroot00000000000000recaptcha-1.2.4/examples/appengine-https.php000066400000000000000000000040271364070137600211170ustar00rootroot00000000000000 [ 'site' => '', 'secret' => '', ], 'v2-invisible' => [ 'site' => '', 'secret' => '', ], 'v3' => [ 'site' => '', 'secret' => '', ], ]; recaptcha-1.2.4/examples/examples.css000066400000000000000000000006231364070137600176260ustar00rootroot00000000000000body { font-family: sans-serif; margin: 0; padding: 0; } h1, h2, p { margin: 0; padding: 0.5rem 0 0 0; font-weight: normal; } h1, h2 { color: #222244; } header { padding: 0.5rem 2rem 0.5rem 2rem; background: #f0f0f4; border-bottom: 1px solid #aaaabb; } main { padding: 0.5rem 2rem 0.5rem 2rem; } .form-field { display: block; margin: 1rem; } .hidden { display: none; } recaptcha-1.2.4/examples/google0afd8760fd68f119.html000066400000000000000000000000651364070137600216110ustar00rootroot00000000000000google-site-verification: google0afd8760fd68f119.htmlrecaptcha-1.2.4/examples/index.php000066400000000000000000000073321364070137600171220ustar00rootroot00000000000000 reCAPTCHA demo

reCAPTCHA demo

Try out the various forms of reCAPTCHA.

You can find the source code for these examples on GitHub in google/recaptcha.

recaptcha-1.2.4/examples/recaptcha-content-security-policy.php000066400000000000000000000205771364070137600245650ustar00rootroot00000000000000 reCAPTCHA demo - Content Security Policy

reCAPTCHA demo

Content Security Policy

↩️ Home

Add your keys

If you do not have keys already then visit https://www.google.com/recaptcha/admin to generate them. Edit this file and set the respective keys in $siteKey and $secret. Reload the page after this.

This example is sending the Content-Security-Policy header. Look at the source and inspect the network tab for this request to see what's happening. The reCAPTCHA v3 API is being called here, however you can use the same approach for the v2 API calls as well.

NOTE:This is a sample implementation, the score returned here is not a reflection on your Google account or type of traffic. In production, refer to the distribution of scores shown in your admin interface and adjust your own threshold accordingly. Do not raise issues regarding the score you see here.

  1. reCAPTCHA script loading

⤴️ Try again

recaptcha-1.2.4/examples/recaptcha-v2-checkbox-explicit.php000066400000000000000000000174241364070137600237000ustar00rootroot00000000000000 reCAPTCHA demo - "I'm not a robot" checkbox - Explicit render

reCAPTCHA demo

"I'm not a robot" checkbox - Explicit render

↩️ Home

Add your keys

If you do not have keys already then visit https://www.google.com/recaptcha/admin to generate them. Edit this file and set the respective keys in the config.php file or directly to $siteKey and $secret. Reload the page after this.

POST data

setExpectedHostname($_SERVER['SERVER_NAME']) ->verify($_POST['g-recaptcha-response'], $_SERVER['REMOTE_ADDR']); if ($resp->isSuccess()): // If the response is a success, that's it! ?>

Success!

That's it. Everything is working. Go integrate this into your real project.

⤴️ Try again

Something went wrong

Check the error code reference at https://developers.google.com/recaptcha/docs/verify#error-code-reference.

Note: Error code missing-input-response may mean the user just didn't complete the reCAPTCHA.

⤴️ Try again

Complete the reCAPTCHA then submit the form.

An example form
recaptcha-1.2.4/examples/recaptcha-v2-checkbox.php000066400000000000000000000165371364070137600220650ustar00rootroot00000000000000 reCAPTCHA demo - "I'm not a robot" checkbox

reCAPTCHA demo

"I'm not a robot" checkbox

↩️ Home

Add your keys

If you do not have keys already then visit https://www.google.com/recaptcha/admin to generate them. Edit this file and set the respective keys in the config.php file or directly to $siteKey and $secret. Reload the page after this.

POST data

setExpectedHostname($_SERVER['SERVER_NAME']) ->verify($_POST['g-recaptcha-response'], $_SERVER['REMOTE_ADDR']); if ($resp->isSuccess()): // If the response is a success, that's it! ?>

Success!

That's it. Everything is working. Go integrate this into your real project.

⤴️ Try again

Something went wrong

Check the error code reference at https://developers.google.com/recaptcha/docs/verify#error-code-reference.

Note: Error code missing-input-response may mean the user just didn't complete the reCAPTCHA.

⤴️ Try again

Complete the reCAPTCHA then submit the form.

An example form
recaptcha-1.2.4/examples/recaptcha-v2-invisible.php000066400000000000000000000161441364070137600222550ustar00rootroot00000000000000 reCAPTCHA demo - Invisible

reCAPTCHA demo

Invisible

↩️ Home

Add your keys

If you do not have keys already then visit https://www.google.com/recaptcha/admin to generate them. Edit this file and set the respective keys in $siteKey and $secret. Reload the page after this.

POST data

setExpectedHostname($_SERVER['SERVER_NAME']) ->verify($_POST['g-recaptcha-response'], $_SERVER['REMOTE_ADDR']); if ($resp->isSuccess()): // If the response is a success, that's it! ?>

Success!

That's it. Everything is working. Go integrate this into your real project.

⤴️ Try again

Something went wrong

Check the error code reference at https://developers.google.com/recaptcha/docs/verify#error-code-reference.

Note: Error code missing-input-response may mean the user just didn't complete the reCAPTCHA.

⤴️ Try again

Submit the form and reCAPTCHA will run automatically.

An example form
recaptcha-1.2.4/examples/recaptcha-v3-request-scores.php000066400000000000000000000152351364070137600232560ustar00rootroot00000000000000 reCAPTCHA demo - Request scores

reCAPTCHA demo

Request scores

↩️ Home

Add your keys

If you do not have keys already then visit https://www.google.com/recaptcha/admin to generate them. Edit this file and set the respective keys in $siteKey and $secret. Reload the page after this.

The reCAPTCHA v3 API provides a confidence score for each request.

NOTE:This is a sample implementation, the score returned here is not a reflection on your Google account or type of traffic. In production, refer to the distribution of scores shown in your admin interface and adjust your own threshold accordingly. Do not raise issues regarding the score you see here.

  1. reCAPTCHA script loading

⤴️ Try again

recaptcha-1.2.4/examples/recaptcha-v3-verify.php000066400000000000000000000055021364070137600215720ustar00rootroot00000000000000setExpectedHostname($_SERVER['SERVER_NAME']) ->setExpectedAction($_GET['action']) ->setScoreThreshold(0.5) ->verify($_GET['token'], $_SERVER['REMOTE_ADDR']); header('Content-type:application/json'); echo json_encode($resp->toArray()); recaptcha-1.2.4/examples/robots.txt000066400000000000000000000000301364070137600173370ustar00rootroot00000000000000User-agent: * Disallow: recaptcha-1.2.4/phpunit.xml.dist000066400000000000000000000012331364070137600166310ustar00rootroot00000000000000 tests/ReCaptcha/ src/ReCaptcha/ recaptcha-1.2.4/src/000077500000000000000000000000001364070137600142465ustar00rootroot00000000000000recaptcha-1.2.4/src/ReCaptcha/000077500000000000000000000000001364070137600161005ustar00rootroot00000000000000recaptcha-1.2.4/src/ReCaptcha/ReCaptcha.php000066400000000000000000000207061364070137600204500ustar00rootroot00000000000000secret = $secret; $this->requestMethod = (is_null($requestMethod)) ? new RequestMethod\Post() : $requestMethod; } /** * Calls the reCAPTCHA siteverify API to verify whether the user passes * CAPTCHA test and additionally runs any specified additional checks * * @param string $response The user response token provided by reCAPTCHA, verifying the user on your site. * @param string $remoteIp The end user's IP address. * @return Response Response from the service. */ public function verify($response, $remoteIp = null) { // Discard empty solution submissions if (empty($response)) { $recaptchaResponse = new Response(false, array(self::E_MISSING_INPUT_RESPONSE)); return $recaptchaResponse; } $params = new RequestParameters($this->secret, $response, $remoteIp, self::VERSION); $rawResponse = $this->requestMethod->submit($params); $initialResponse = Response::fromJson($rawResponse); $validationErrors = array(); if (isset($this->hostname) && strcasecmp($this->hostname, $initialResponse->getHostname()) !== 0) { $validationErrors[] = self::E_HOSTNAME_MISMATCH; } if (isset($this->apkPackageName) && strcasecmp($this->apkPackageName, $initialResponse->getApkPackageName()) !== 0) { $validationErrors[] = self::E_APK_PACKAGE_NAME_MISMATCH; } if (isset($this->action) && strcasecmp($this->action, $initialResponse->getAction()) !== 0) { $validationErrors[] = self::E_ACTION_MISMATCH; } if (isset($this->threshold) && $this->threshold > $initialResponse->getScore()) { $validationErrors[] = self::E_SCORE_THRESHOLD_NOT_MET; } if (isset($this->timeoutSeconds)) { $challengeTs = strtotime($initialResponse->getChallengeTs()); if ($challengeTs > 0 && time() - $challengeTs > $this->timeoutSeconds) { $validationErrors[] = self::E_CHALLENGE_TIMEOUT; } } if (empty($validationErrors)) { return $initialResponse; } return new Response( false, array_merge($initialResponse->getErrorCodes(), $validationErrors), $initialResponse->getHostname(), $initialResponse->getChallengeTs(), $initialResponse->getApkPackageName(), $initialResponse->getScore(), $initialResponse->getAction() ); } /** * Provide a hostname to match against in verify() * This should be without a protocol or trailing slash, e.g. www.google.com * * @param string $hostname Expected hostname * @return ReCaptcha Current instance for fluent interface */ public function setExpectedHostname($hostname) { $this->hostname = $hostname; return $this; } /** * Provide an APK package name to match against in verify() * * @param string $apkPackageName Expected APK package name * @return ReCaptcha Current instance for fluent interface */ public function setExpectedApkPackageName($apkPackageName) { $this->apkPackageName = $apkPackageName; return $this; } /** * Provide an action to match against in verify() * This should be set per page. * * @param string $action Expected action * @return ReCaptcha Current instance for fluent interface */ public function setExpectedAction($action) { $this->action = $action; return $this; } /** * Provide a threshold to meet or exceed in verify() * Threshold should be a float between 0 and 1 which will be tested as response >= threshold. * * @param float $threshold Expected threshold * @return ReCaptcha Current instance for fluent interface */ public function setScoreThreshold($threshold) { $this->threshold = floatval($threshold); return $this; } /** * Provide a timeout in seconds to test against the challenge timestamp in verify() * * @param int $timeoutSeconds Expected hostname * @return ReCaptcha Current instance for fluent interface */ public function setChallengeTimeout($timeoutSeconds) { $this->timeoutSeconds = $timeoutSeconds; return $this; } } recaptcha-1.2.4/src/ReCaptcha/RequestMethod.php000066400000000000000000000040251364070137600214030ustar00rootroot00000000000000curl = (is_null($curl)) ? new Curl() : $curl; $this->siteVerifyUrl = (is_null($siteVerifyUrl)) ? ReCaptcha::SITE_VERIFY_URL : $siteVerifyUrl; } /** * Submit the cURL request with the specified parameters. * * @param RequestParameters $params Request parameters * @return string Body of the reCAPTCHA response */ public function submit(RequestParameters $params) { $handle = $this->curl->init($this->siteVerifyUrl); $options = array( CURLOPT_POST => true, CURLOPT_POSTFIELDS => $params->toQueryString(), CURLOPT_HTTPHEADER => array( 'Content-Type: application/x-www-form-urlencoded' ), CURLINFO_HEADER_OUT => false, CURLOPT_HEADER => false, CURLOPT_RETURNTRANSFER => true, CURLOPT_SSL_VERIFYPEER => true ); $this->curl->setoptArray($handle, $options); $response = $this->curl->exec($handle); $this->curl->close($handle); if ($response !== false) { return $response; } return '{"success": false, "error-codes": ["'.ReCaptcha::E_CONNECTION_FAILED.'"]}'; } } recaptcha-1.2.4/src/ReCaptcha/RequestMethod/Post.php000066400000000000000000000063431364070137600223350ustar00rootroot00000000000000siteVerifyUrl = (is_null($siteVerifyUrl)) ? ReCaptcha::SITE_VERIFY_URL : $siteVerifyUrl; } /** * Submit the POST request with the specified parameters. * * @param RequestParameters $params Request parameters * @return string Body of the reCAPTCHA response */ public function submit(RequestParameters $params) { $options = array( 'http' => array( 'header' => "Content-type: application/x-www-form-urlencoded\r\n", 'method' => 'POST', 'content' => $params->toQueryString(), // Force the peer to validate (not needed in 5.6.0+, but still works) 'verify_peer' => true, ), ); $context = stream_context_create($options); $response = file_get_contents($this->siteVerifyUrl, false, $context); if ($response !== false) { return $response; } return '{"success": false, "error-codes": ["'.ReCaptcha::E_CONNECTION_FAILED.'"]}'; } } recaptcha-1.2.4/src/ReCaptcha/RequestMethod/Socket.php000066400000000000000000000064641364070137600226440ustar00rootroot00000000000000handle = fsockopen($hostname, $port, $errno, $errstr, (is_null($timeout) ? ini_get("default_socket_timeout") : $timeout)); if ($this->handle != false && $errno === 0 && $errstr === '') { return $this->handle; } return false; } /** * fwrite * * @see http://php.net/fwrite * @param string $string * @param int $length * @return int | bool */ public function fwrite($string, $length = null) { return fwrite($this->handle, $string, (is_null($length) ? strlen($string) : $length)); } /** * fgets * * @see http://php.net/fgets * @param int $length * @return string */ public function fgets($length = null) { return fgets($this->handle, $length); } /** * feof * * @see http://php.net/feof * @return bool */ public function feof() { return feof($this->handle); } /** * fclose * * @see http://php.net/fclose * @return bool */ public function fclose() { return fclose($this->handle); } } recaptcha-1.2.4/src/ReCaptcha/RequestMethod/SocketPost.php000066400000000000000000000100361364070137600235000ustar00rootroot00000000000000socket = (is_null($socket)) ? new Socket() : $socket; $this->siteVerifyUrl = (is_null($siteVerifyUrl)) ? ReCaptcha::SITE_VERIFY_URL : $siteVerifyUrl; } /** * Submit the POST request with the specified parameters. * * @param RequestParameters $params Request parameters * @return string Body of the reCAPTCHA response */ public function submit(RequestParameters $params) { $errno = 0; $errstr = ''; $urlParsed = parse_url($this->siteVerifyUrl); if (false === $this->socket->fsockopen('ssl://' . $urlParsed['host'], 443, $errno, $errstr, 30)) { return '{"success": false, "error-codes": ["'.ReCaptcha::E_CONNECTION_FAILED.'"]}'; } $content = $params->toQueryString(); $request = "POST " . $urlParsed['path'] . " HTTP/1.0\r\n"; $request .= "Host: " . $urlParsed['host'] . "\r\n"; $request .= "Content-Type: application/x-www-form-urlencoded\r\n"; $request .= "Content-length: " . strlen($content) . "\r\n"; $request .= "Connection: close\r\n\r\n"; $request .= $content . "\r\n\r\n"; $this->socket->fwrite($request); $response = ''; while (!$this->socket->feof()) { $response .= $this->socket->fgets(4096); } $this->socket->fclose(); if (0 !== strpos($response, 'HTTP/1.0 200 OK')) { return '{"success": false, "error-codes": ["'.ReCaptcha::E_BAD_RESPONSE.'"]}'; } $parts = preg_split("#\n\s*\n#Uis", $response); return $parts[1]; } } recaptcha-1.2.4/src/ReCaptcha/RequestParameters.php000066400000000000000000000066521364070137600222760ustar00rootroot00000000000000secret = $secret; $this->response = $response; $this->remoteIp = $remoteIp; $this->version = $version; } /** * Array representation. * * @return array Array formatted parameters. */ public function toArray() { $params = array('secret' => $this->secret, 'response' => $this->response); if (!is_null($this->remoteIp)) { $params['remoteip'] = $this->remoteIp; } if (!is_null($this->version)) { $params['version'] = $this->version; } return $params; } /** * Query string representation for HTTP request. * * @return string Query string formatted parameters. */ public function toQueryString() { return http_build_query($this->toArray(), '', '&'); } } recaptcha-1.2.4/src/ReCaptcha/Response.php000066400000000000000000000137501364070137600204150ustar00rootroot00000000000000success = $success; $this->hostname = $hostname; $this->challengeTs = $challengeTs; $this->apkPackageName = $apkPackageName; $this->score = $score; $this->action = $action; $this->errorCodes = $errorCodes; } /** * Is success? * * @return boolean */ public function isSuccess() { return $this->success; } /** * Get error codes. * * @return array */ public function getErrorCodes() { return $this->errorCodes; } /** * Get hostname. * * @return string */ public function getHostname() { return $this->hostname; } /** * Get challenge timestamp * * @return string */ public function getChallengeTs() { return $this->challengeTs; } /** * Get APK package name * * @return string */ public function getApkPackageName() { return $this->apkPackageName; } /** * Get score * * @return float */ public function getScore() { return $this->score; } /** * Get action * * @return string */ public function getAction() { return $this->action; } public function toArray() { return array( 'success' => $this->isSuccess(), 'hostname' => $this->getHostname(), 'challenge_ts' => $this->getChallengeTs(), 'apk_package_name' => $this->getApkPackageName(), 'score' => $this->getScore(), 'action' => $this->getAction(), 'error-codes' => $this->getErrorCodes(), ); } } recaptcha-1.2.4/src/autoload.php000066400000000000000000000054231364070137600165730ustar00rootroot00000000000000verify(''); $this->assertFalse($response->isSuccess()); $this->assertEquals(array(Recaptcha::E_MISSING_INPUT_RESPONSE), $response->getErrorCodes()); } private function getMockRequestMethod($responseJson) { $method = $this->getMockBuilder(\ReCaptcha\RequestMethod::class) ->disableOriginalConstructor() ->setMethods(array('submit')) ->getMock(); $method->expects($this->any()) ->method('submit') ->with($this->callback(function ($params) { return true; })) ->will($this->returnValue($responseJson)); return $method; } public function testVerifyReturnsResponse() { $method = $this->getMockRequestMethod('{"success": true}'); $rc = new ReCaptcha('secret', $method); $response = $rc->verify('response'); $this->assertTrue($response->isSuccess()); } public function testVerifyReturnsInitialResponseWithoutAdditionalChecks() { $method = $this->getMockRequestMethod('{"success": true}'); $rc = new ReCaptcha('secret', $method); $initialResponse = $rc->verify('response'); $this->assertEquals($initialResponse, $rc->verify('response')); } public function testVerifyHostnameMatch() { $method = $this->getMockRequestMethod('{"success": true, "hostname": "host.name"}'); $rc = new ReCaptcha('secret', $method); $response = $rc->setExpectedHostname('host.name')->verify('response'); $this->assertTrue($response->isSuccess()); } public function testVerifyHostnameMisMatch() { $method = $this->getMockRequestMethod('{"success": true, "hostname": "host.NOTname"}'); $rc = new ReCaptcha('secret', $method); $response = $rc->setExpectedHostname('host.name')->verify('response'); $this->assertFalse($response->isSuccess()); $this->assertEquals(array(ReCaptcha::E_HOSTNAME_MISMATCH), $response->getErrorCodes()); } public function testVerifyApkPackageNameMatch() { $method = $this->getMockRequestMethod('{"success": true, "apk_package_name": "apk.name"}'); $rc = new ReCaptcha('secret', $method); $response = $rc->setExpectedApkPackageName('apk.name')->verify('response'); $this->assertTrue($response->isSuccess()); } public function testVerifyApkPackageNameMisMatch() { $method = $this->getMockRequestMethod('{"success": true, "apk_package_name": "apk.NOTname"}'); $rc = new ReCaptcha('secret', $method); $response = $rc->setExpectedApkPackageName('apk.name')->verify('response'); $this->assertFalse($response->isSuccess()); $this->assertEquals(array(ReCaptcha::E_APK_PACKAGE_NAME_MISMATCH), $response->getErrorCodes()); } public function testVerifyActionMatch() { $method = $this->getMockRequestMethod('{"success": true, "action": "action/name"}'); $rc = new ReCaptcha('secret', $method); $response = $rc->setExpectedAction('action/name')->verify('response'); $this->assertTrue($response->isSuccess()); } public function testVerifyActionMisMatch() { $method = $this->getMockRequestMethod('{"success": true, "action": "action/NOTname"}'); $rc = new ReCaptcha('secret', $method); $response = $rc->setExpectedAction('action/name')->verify('response'); $this->assertFalse($response->isSuccess()); $this->assertEquals(array(ReCaptcha::E_ACTION_MISMATCH), $response->getErrorCodes()); } public function testVerifyAboveThreshold() { $method = $this->getMockRequestMethod('{"success": true, "score": "0.9"}'); $rc = new ReCaptcha('secret', $method); $response = $rc->setScoreThreshold('0.5')->verify('response'); $this->assertTrue($response->isSuccess()); } public function testVerifyBelowThreshold() { $method = $this->getMockRequestMethod('{"success": true, "score": "0.1"}'); $rc = new ReCaptcha('secret', $method); $response = $rc->setScoreThreshold('0.5')->verify('response'); $this->assertFalse($response->isSuccess()); $this->assertEquals(array(ReCaptcha::E_SCORE_THRESHOLD_NOT_MET), $response->getErrorCodes()); } public function testVerifyWithinTimeout() { // Responses come back like 2018-07-31T13:48:41Z $challengeTs = date('Y-M-d\TH:i:s\Z', time()); $method = $this->getMockRequestMethod('{"success": true, "challenge_ts": "'.$challengeTs.'"}'); $rc = new ReCaptcha('secret', $method); $response = $rc->setChallengeTimeout('1000')->verify('response'); $this->assertTrue($response->isSuccess()); } public function testVerifyOverTimeout() { // Responses come back like 2018-07-31T13:48:41Z $challengeTs = date('Y-M-d\TH:i:s\Z', time() - 600); $method = $this->getMockRequestMethod('{"success": true, "challenge_ts": "'.$challengeTs.'"}'); $rc = new ReCaptcha('secret', $method); $response = $rc->setChallengeTimeout('60')->verify('response'); $this->assertFalse($response->isSuccess()); $this->assertEquals(array(ReCaptcha::E_CHALLENGE_TIMEOUT), $response->getErrorCodes()); } public function testVerifyMergesErrors() { $method = $this->getMockRequestMethod('{"success": false, "error-codes": ["initial-error"], "score": "0.1"}'); $rc = new ReCaptcha('secret', $method); $response = $rc->setScoreThreshold('0.5')->verify('response'); $this->assertFalse($response->isSuccess()); $this->assertEquals(array('initial-error', ReCaptcha::E_SCORE_THRESHOLD_NOT_MET), $response->getErrorCodes()); } } recaptcha-1.2.4/tests/ReCaptcha/RequestMethod/000077500000000000000000000000001364070137600212445ustar00rootroot00000000000000recaptcha-1.2.4/tests/ReCaptcha/RequestMethod/CurlPostTest.php000066400000000000000000000112661364070137600243760ustar00rootroot00000000000000markTestSkipped( 'The cURL extension is not available.' ); } } public function testSubmit() { $curl = $this->getMockBuilder(\ReCaptcha\RequestMethod\Curl::class) ->disableOriginalConstructor() ->setMethods(array('init', 'setoptArray', 'exec', 'close')) ->getMock(); $curl->expects($this->once()) ->method('init') ->willReturn(new \stdClass); $curl->expects($this->once()) ->method('setoptArray') ->willReturn(true); $curl->expects($this->once()) ->method('exec') ->willReturn('RESPONSEBODY'); $curl->expects($this->once()) ->method('close'); $pc = new CurlPost($curl); $response = $pc->submit(new RequestParameters("secret", "response")); $this->assertEquals('RESPONSEBODY', $response); } public function testOverrideSiteVerifyUrl() { $url = 'OVERRIDE'; $curl = $this->getMockBuilder(\ReCaptcha\RequestMethod\Curl::class) ->disableOriginalConstructor() ->setMethods(array('init', 'setoptArray', 'exec', 'close')) ->getMock(); $curl->expects($this->once()) ->method('init') ->with($url) ->willReturn(new \stdClass); $curl->expects($this->once()) ->method('setoptArray') ->willReturn(true); $curl->expects($this->once()) ->method('exec') ->willReturn('RESPONSEBODY'); $curl->expects($this->once()) ->method('close'); $pc = new CurlPost($curl, $url); $response = $pc->submit(new RequestParameters("secret", "response")); $this->assertEquals('RESPONSEBODY', $response); } public function testConnectionFailureReturnsError() { $curl = $this->getMockBuilder(\ReCaptcha\RequestMethod\Curl::class) ->disableOriginalConstructor() ->setMethods(array('init', 'setoptArray', 'exec', 'close')) ->getMock(); $curl->expects($this->once()) ->method('init') ->willReturn(new \stdClass); $curl->expects($this->once()) ->method('setoptArray') ->willReturn(true); $curl->expects($this->once()) ->method('exec') ->willReturn(false); $curl->expects($this->once()) ->method('close'); $pc = new CurlPost($curl); $response = $pc->submit(new RequestParameters("secret", "response")); $this->assertEquals('{"success": false, "error-codes": ["'.ReCaptcha::E_CONNECTION_FAILED.'"]}', $response); } } recaptcha-1.2.4/tests/ReCaptcha/RequestMethod/PostTest.php000066400000000000000000000124131364070137600235430ustar00rootroot00000000000000parameters = new RequestParameters('secret', 'response', 'remoteip', 'version'); } public function tearDown() { self::$assert = null; } public function testHTTPContextOptions() { $req = new Post(); self::$assert = array($this, 'httpContextOptionsCallback'); $req->submit($this->parameters); $this->assertEquals(1, $this->runcount, 'The assertion was ran'); } public function testSSLContextOptions() { $req = new Post(); self::$assert = array($this, 'sslContextOptionsCallback'); $req->submit($this->parameters); $this->assertEquals(1, $this->runcount, 'The assertion was ran'); } public function testOverrideVerifyUrl() { $req = new Post('https://over.ride/some/path'); self::$assert = array($this, 'overrideUrlOptions'); $req->submit($this->parameters); $this->assertEquals(1, $this->runcount, 'The assertion was ran'); } public function testConnectionFailureReturnsError() { $req = new Post('https://bad.connection/'); self::$assert = array($this, 'connectionFailureResponse'); $response = $req->submit($this->parameters); $this->assertEquals('{"success": false, "error-codes": ["'.ReCaptcha::E_CONNECTION_FAILED.'"]}', $response); } public function connectionFailureResponse() { return false; } public function overrideUrlOptions(array $args) { $this->runcount++; $this->assertEquals('https://over.ride/some/path', $args[0]); } public function httpContextOptionsCallback(array $args) { $this->runcount++; $this->assertCommonOptions($args); $options = stream_context_get_options($args[2]); $this->assertArrayHasKey('http', $options); $this->assertArrayHasKey('method', $options['http']); $this->assertEquals('POST', $options['http']['method']); $this->assertArrayHasKey('content', $options['http']); $this->assertEquals($this->parameters->toQueryString(), $options['http']['content']); $this->assertArrayHasKey('header', $options['http']); $headers = array( 'Content-type: application/x-www-form-urlencoded', ); foreach ($headers as $header) { $this->assertContains($header, $options['http']['header']); } } public function sslContextOptionsCallback(array $args) { $this->runcount++; $this->assertCommonOptions($args); $options = stream_context_get_options($args[2]); $this->assertArrayHasKey('http', $options); $this->assertArrayHasKey('verify_peer', $options['http']); $this->assertTrue($options['http']['verify_peer']); } protected function assertCommonOptions(array $args) { $this->assertCount(3, $args); $this->assertStringStartsWith('https://www.google.com/', $args[0]); $this->assertFalse($args[1]); $this->assertTrue(is_resource($args[2]), 'The context options should be a resource'); } } function file_get_contents() { if (PostTest::$assert) { return call_user_func(PostTest::$assert, func_get_args()); } // Since we can't represent maxlen in userland... return call_user_func_array('file_get_contents', func_get_args()); } recaptcha-1.2.4/tests/ReCaptcha/RequestMethod/SocketPostTest.php000066400000000000000000000134761364070137600247260ustar00rootroot00000000000000getMockBuilder(\ReCaptcha\RequestMethod\Socket::class) ->disableOriginalConstructor() ->setMethods(array('fsockopen', 'fwrite', 'fgets', 'feof', 'fclose')) ->getMock(); $socket->expects($this->once()) ->method('fsockopen') ->willReturn(true); $socket->expects($this->once()) ->method('fwrite'); $socket->expects($this->once()) ->method('fgets') ->willReturn("HTTP/1.0 200 OK\n\nRESPONSEBODY"); $socket->expects($this->exactly(2)) ->method('feof') ->will($this->onConsecutiveCalls(false, true)); $socket->expects($this->once()) ->method('fclose') ->willReturn(true); $ps = new SocketPost($socket); $response = $ps->submit(new RequestParameters("secret", "response", "remoteip", "version")); $this->assertEquals('RESPONSEBODY', $response); } public function testOverrideSiteVerifyUrl() { $socket = $this->getMockBuilder(\ReCaptcha\RequestMethod\Socket::class) ->disableOriginalConstructor() ->setMethods(array('fsockopen', 'fwrite', 'fgets', 'feof', 'fclose')) ->getMock(); $socket->expects($this->once()) ->method('fsockopen') ->with('ssl://over.ride', 443, 0, '', 30) ->willReturn(true); $socket->expects($this->once()) ->method('fwrite') ->with($this->matchesRegularExpression('/^POST \/some\/path.*Host: over\.ride/s')); $socket->expects($this->once()) ->method('fgets') ->willReturn("HTTP/1.0 200 OK\n\nRESPONSEBODY"); $socket->expects($this->exactly(2)) ->method('feof') ->will($this->onConsecutiveCalls(false, true)); $socket->expects($this->once()) ->method('fclose') ->willReturn(true); $ps = new SocketPost($socket, 'https://over.ride/some/path'); $response = $ps->submit(new RequestParameters("secret", "response", "remoteip", "version")); $this->assertEquals('RESPONSEBODY', $response); } public function testSubmitBadResponse() { $socket = $this->getMockBuilder(\ReCaptcha\RequestMethod\Socket::class) ->disableOriginalConstructor() ->setMethods(array('fsockopen', 'fwrite', 'fgets', 'feof', 'fclose')) ->getMock(); $socket->expects($this->once()) ->method('fsockopen') ->willReturn(true); $socket->expects($this->once()) ->method('fwrite'); $socket->expects($this->once()) ->method('fgets') ->willReturn("HTTP/1.0 500 NOPEn\\nBOBBINS"); $socket->expects($this->exactly(2)) ->method('feof') ->will($this->onConsecutiveCalls(false, true)); $socket->expects($this->once()) ->method('fclose') ->willReturn(true); $ps = new SocketPost($socket); $response = $ps->submit(new RequestParameters("secret", "response", "remoteip", "version")); $this->assertEquals('{"success": false, "error-codes": ["'.ReCaptcha::E_BAD_RESPONSE.'"]}', $response); } public function testConnectionFailureReturnsError() { $socket = $this->getMockBuilder(\ReCaptcha\RequestMethod\Socket::class) ->disableOriginalConstructor() ->setMethods(array('fsockopen')) ->getMock(); $socket->expects($this->once()) ->method('fsockopen') ->willReturn(false); $ps = new SocketPost($socket); $response = $ps->submit(new RequestParameters("secret", "response", "remoteip", "version")); $this->assertEquals('{"success": false, "error-codes": ["'.ReCaptcha::E_CONNECTION_FAILED.'"]}', $response); } } recaptcha-1.2.4/tests/ReCaptcha/RequestParametersTest.php000066400000000000000000000056631364070137600235120ustar00rootroot00000000000000 'SECRET', 'response' => 'RESPONSE', 'remoteip' => 'REMOTEIP', 'version' => 'VERSION'), 'secret=SECRET&response=RESPONSE&remoteip=REMOTEIP&version=VERSION'), array('SECRET', 'RESPONSE', null, null, array('secret' => 'SECRET', 'response' => 'RESPONSE'), 'secret=SECRET&response=RESPONSE'), ); } /** * @dataProvider provideValidData */ public function testToArray($secret, $response, $remoteIp, $version, $expectedArray, $expectedQuery) { $params = new RequestParameters($secret, $response, $remoteIp, $version); $this->assertEquals($params->toArray(), $expectedArray); } /** * @dataProvider provideValidData */ public function testToQueryString($secret, $response, $remoteIp, $version, $expectedArray, $expectedQuery) { $params = new RequestParameters($secret, $response, $remoteIp, $version); $this->assertEquals($params->toQueryString(), $expectedQuery); } } recaptcha-1.2.4/tests/ReCaptcha/ResponseTest.php000066400000000000000000000150331364070137600216240ustar00rootroot00000000000000assertEquals($success, $response->isSuccess()); $this->assertEquals($errorCodes, $response->getErrorCodes()); $this->assertEquals($hostname, $response->getHostname()); $this->assertEquals($challengeTs, $response->getChallengeTs()); $this->assertEquals($apkPackageName, $response->getApkPackageName()); $this->assertEquals($score, $response->getScore()); $this->assertEquals($action, $response->getAction()); } public function provideJson() { return array( array( '{"success": true}', true, array(), null, null, null, null, null, ), array( '{"success": true, "hostname": "google.com"}', true, array(), 'google.com', null, null, null, null, ), array( '{"success": false, "error-codes": ["test"]}', false, array('test'), null, null, null, null, null, ), array( '{"success": false, "error-codes": ["test"], "hostname": "google.com"}', false, array('test'), 'google.com', null, null, null, null, ), array( '{"success": false, "error-codes": ["test"], "hostname": "google.com", "challenge_ts": "timestamp", "apk_package_name": "apk", "score": "0.5", "action": "action"}', false, array('test'), 'google.com', 'timestamp', 'apk', 0.5, 'action', ), array( '{"success": true, "error-codes": ["test"]}', true, array(), null, null, null, null, null, ), array( '{"success": true, "error-codes": ["test"], "hostname": "google.com"}', true, array(), 'google.com', null, null, null, null, ), array( '{"success": false}', false, array(ReCaptcha::E_UNKNOWN_ERROR), null, null, null, null, null, ), array( '{"success": false, "hostname": "google.com"}', false, array(ReCaptcha::E_UNKNOWN_ERROR), 'google.com', null, null, null, null, ), array( 'BAD JSON', false, array(ReCaptcha::E_INVALID_JSON), null, null, null, null, null, ), ); } public function testIsSuccess() { $response = new Response(true); $this->assertTrue($response->isSuccess()); $response = new Response(false); $this->assertFalse($response->isSuccess()); $response = new Response(true, array(), 'example.com'); $this->assertEquals('example.com', $response->getHostName()); } public function testGetErrorCodes() { $errorCodes = array('test'); $response = new Response(true, $errorCodes); $this->assertEquals($errorCodes, $response->getErrorCodes()); } public function testGetHostname() { $hostname = 'google.com'; $errorCodes = array(); $response = new Response(true, $errorCodes, $hostname); $this->assertEquals($hostname, $response->getHostname()); } public function testGetChallengeTs() { $timestamp = 'timestamp'; $errorCodes = array(); $response = new Response(true, array(), 'hostname', $timestamp); $this->assertEquals($timestamp, $response->getChallengeTs()); } public function TestGetApkPackageName() { $apk = 'apk'; $response = new Response(true, array(), 'hostname', 'timestamp', 'apk'); $this->assertEquals($apk, $response->getApkPackageName()); } public function testGetScore() { $score = 0.5; $response = new Response(true, array(), 'hostname', 'timestamp', 'apk', $score); $this->assertEquals($score, $response->getScore()); } public function testGetAction() { $action = 'homepage'; $response = new Response(true, array(), 'hostname', 'timestamp', 'apk', '0.5', 'homepage'); $this->assertEquals($action, $response->getAction()); } public function testToArray() { $response = new Response(true, array(), 'hostname', 'timestamp', 'apk', '0.5', 'homepage'); $expected = array( 'success' => true, 'error-codes' => array(), 'hostname' => 'hostname', 'challenge_ts' => 'timestamp', 'apk_package_name' => 'apk', 'score' => 0.5, 'action' => 'homepage', ); $this->assertEquals($expected, $response->toArray()); } }