diff --git a/recaptcha-php/README.md b/recaptcha-php/README.md index fac73b8622747c1878744704c0aec27ed133074c..6e81a8edafbc891e3fdb2c37a967b417be920bb6 100644 --- a/recaptcha-php/README.md +++ b/recaptcha-php/README.md @@ -6,7 +6,7 @@ * Project page: http://www.google.com/recaptcha/ * Repository: https://github.com/google/recaptcha -* Version: 1.1.0 +* Version: 1.1.2 * License: BSD, see [LICENSE](LICENSE) ## Description @@ -17,15 +17,60 @@ with reCAPTCHA. ## Installation -Use [Composer](https://getcomposer.org/) to install the library. Either use -`composer require google/recaptcha "~1.1"` or add the following to your -`composer.json`: +### Composer (Recommended) + +[Composer](https://getcomposer.org/) is a widely used dependency manager for PHP +packages. This reCAPTCHA client is available on Packagist as +[`google/recaptcha`](https://packagist.org/packages/google/recaptcha) and can be +installed either by running the `composer require` command or adding the library +to your `composer.json`. To enable Composer for you project, refer to the +project's [Getting Started](https://getcomposer.org/doc/00-intro.md) +documentation. + +To add this dependency using the command, run the following from within your +project directory: +``` +composer require google/recaptcha "~1.1" +``` + +Alternatively, add the dependency directly to your `composer.json` file: ```json - "require": { - "google/recaptcha": "~1.1" - } +"require": { + "google/recaptcha": "~1.1" +} +``` + +### Direct download (no Composer) + +If you wish to install the library manually (i.e. without Composer), then you +can use the links on the main project page to either clone the repo or download +the [ZIP file](https://github.com/google/recaptcha/archive/master.zip). For +convenience, an autoloader script is provided in `src/autoload.php` which you +can require into your script instead of Composer's `vendor/autoload.php`. For +example: + +```php +require('/path/to/recaptcha/src/autoload.php'); +$recaptcha = new \ReCaptcha\ReCaptcha($secret); ``` +The classes in the project are structured according to the +[PSR-4](http://www.php-fig.org/psr/psr-4/) standard, so you may of course also +use your own autoloader or require the needed files directly in your code. + +### Development install + +If you would like to contribute to this project or run the unit tests on within +your own environment you will need to install the development dependencies, in +this case that means [PHPUnit](https://phpunit.de/). If you clone the repo and +run `composer install` from within the repo, this will also grab PHPUnit and all +its dependencies for you. If you only need the autoloader installed, then you +can always specify to Composer not to run in development mode, e.g. `composer +install --no-dev`. + +*Note:* These dependencies are only required for development, there's no +requirement for them to be included in your production code. + ## Usage First, register keys for your site at https://www.google.com/recaptcha/admin @@ -43,21 +88,23 @@ if ($resp->isSuccess()) { } ``` -You can see an end-to-end working example in [examples/example-captcha.php](examples/example-captcha.php) +You can see an end-to-end working example in +[examples/example-captcha.php](examples/example-captcha.php) ## Upgrading ### From 1.0.0 -The previous version of this client is still available on the `1.0.0` tag -[in this repo](https://github.com/google/recaptcha/tree/1.0.0) but it is purely -for reference and will not receive any updates. +The previous version of this client is still available on the `1.0.0` tag [in +this repo](https://github.com/google/recaptcha/tree/1.0.0) but it is purely for +reference and will not receive any updates. The major changes in 1.1.0 are: - * installation now via Composer; - * class loading also via Composer; - * classes now namespaced; - * old method call was `$rc->verifyResponse($remoteIp, $response)`, new call is `$rc->verify($response, $remoteIp)` +* installation now via Composer; +* class loading also via Composer; +* classes now namespaced; +* old method call was `$rc->verifyResponse($remoteIp, $response)`, new call is + `$rc->verify($response, $remoteIp)` ## Contributing diff --git a/recaptcha-php/examples/example-captcha.php b/recaptcha-php/examples/example-captcha.php index e76723938a745252aa809bc2d7c7057ed7e1567e..8875171b8b6aa5215040dd530c2dbd3600b1886a 100644 --- a/recaptcha-php/examples/example-captcha.php +++ b/recaptcha-php/examples/example-captcha.php @@ -30,7 +30,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -// Initiate the autoloader. +// Initiate the autoloader. The file should be generated by Composer. +// You will provide your own autoloader or require the files directly if you did +// not install via Composer. require_once __DIR__ . '/../vendor/autoload.php'; // Register API keys at https://www.google.com/recaptcha/admin @@ -98,7 +100,7 @@ elseif (isset($_POST['g-recaptcha-response'])):

Something went wrong

The following error was returned: getErrorCodes() as $code) { - echo '' . $code . ' '; + echo '' , $code , ' '; } ?>

Check the error code reference at https://developers.google.com/recaptcha/docs/verify#error-code-reference. diff --git a/recaptcha-php/phpunit.xml.dist b/recaptcha-php/phpunit.xml.dist index c4a8896142d0e52d46b98f0becfc15eefcd5b8af..437667880aefff4702d82bb20956fe5e866b4733 100644 --- a/recaptcha-php/phpunit.xml.dist +++ b/recaptcha-php/phpunit.xml.dist @@ -1,8 +1,9 @@ + verbose="true" + bootstrap="src/autoload.php"> tests/ReCaptcha/ diff --git a/recaptcha-php/src/ReCaptcha/ReCaptcha.php b/recaptcha-php/src/ReCaptcha/ReCaptcha.php index 414c52159d44d66c43fb5b030c21860ded920cfe..e2f7c347ebfc4e2da61480e1a1e31301847d165d 100644 --- a/recaptcha-php/src/ReCaptcha/ReCaptcha.php +++ b/recaptcha-php/src/ReCaptcha/ReCaptcha.php @@ -35,7 +35,7 @@ class ReCaptcha * Version of this client library. * @const string */ - const VERSION = 'php_1.1.0'; + const VERSION = 'php_1.1.2'; /** * Shared secret for the site. diff --git a/recaptcha-php/src/ReCaptcha/RequestMethod/Curl.php b/recaptcha-php/src/ReCaptcha/RequestMethod/Curl.php new file mode 100644 index 0000000000000000000000000000000000000000..20ee53099c7a7cc1a5ca9446b40b50117766faa0 --- /dev/null +++ b/recaptcha-php/src/ReCaptcha/RequestMethod/Curl.php @@ -0,0 +1,74 @@ +curl = $curl; + } else { + $this->curl = new Curl(); + } + } + + /** + * 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(self::SITE_VERIFY_URL); + + $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); + + return $response; + } +} diff --git a/recaptcha-php/src/ReCaptcha/RequestMethod/Socket.php b/recaptcha-php/src/ReCaptcha/RequestMethod/Socket.php index e74fc49d62331edcc4291eae0ef8f2fc78c359b4..d3c87922d224e4b88cc0d542f09eb7c98bbe2949 100644 --- a/recaptcha-php/src/ReCaptcha/RequestMethod/Socket.php +++ b/recaptcha-php/src/ReCaptcha/RequestMethod/Socket.php @@ -74,6 +74,7 @@ class Socket * * @see http://php.net/fgets * @param int $length + * @return string */ public function fgets($length = null) { diff --git a/recaptcha-php/src/ReCaptcha/RequestMethod/SocketPost.php b/recaptcha-php/src/ReCaptcha/RequestMethod/SocketPost.php index 4f0c61a3fdea622e204dcd6153b0c4dec0b6671c..47541215f046f893d824a494ce972ab9af5c3567 100644 --- a/recaptcha-php/src/ReCaptcha/RequestMethod/SocketPost.php +++ b/recaptcha-php/src/ReCaptcha/RequestMethod/SocketPost.php @@ -30,15 +30,15 @@ use ReCaptcha\RequestMethod; use ReCaptcha\RequestParameters; /** - * Sends a POST request to the reCAPTCHA service, but makes use of fsockopen() - * instead of get_file_contents(). This is to account for people who may be on + * Sends a POST request to the reCAPTCHA service, but makes use of fsockopen() + * instead of get_file_contents(). This is to account for people who may be on * servers where allow_furl_open is disabled. */ class SocketPost implements RequestMethod { /** * reCAPTCHA service host. - * @const string + * @const string */ const RECAPTCHA_HOST = 'www.google.com'; @@ -65,7 +65,7 @@ class SocketPost implements RequestMethod /** * Constructor - * + * * @param \ReCaptcha\RequestMethod\Socket $socket optional socket, injectable for testing */ public function __construct(Socket $socket = null) @@ -88,33 +88,34 @@ class SocketPost implements RequestMethod $errno = 0; $errstr = ''; - if ($this->socket->fsockopen('ssl://' . self::RECAPTCHA_HOST, 443, $errno, $errstr, 30) !== false) { - $content = $params->toQueryString(); + if (false === $this->socket->fsockopen('ssl://' . self::RECAPTCHA_HOST, 443, $errno, $errstr, 30)) { + return self::BAD_REQUEST; + } - $request = "POST " . self::SITE_VERIFY_PATH . " HTTP/1.1\r\n"; - $request .= "Host: " . self::RECAPTCHA_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"; + $content = $params->toQueryString(); - $this->socket->fwrite($request); - $response = ''; + $request = "POST " . self::SITE_VERIFY_PATH . " HTTP/1.1\r\n"; + $request .= "Host: " . self::RECAPTCHA_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"; - while (!$this->socket->feof()) { - $response .= $this->socket->fgets(4096); - } + $this->socket->fwrite($request); + $response = ''; - $this->socket->fclose(); + while (!$this->socket->feof()) { + $response .= $this->socket->fgets(4096); + } - if (0 === strpos($response, 'HTTP/1.1 200 OK')) { - $parts = preg_split("#\n\s*\n#Uis", $response); - return $parts[1]; - } + $this->socket->fclose(); + if (0 !== strpos($response, 'HTTP/1.1 200 OK')) { return self::BAD_RESPONSE; } - return self::BAD_REQUEST; + $parts = preg_split("#\n\s*\n#Uis", $response); + + return $parts[1]; } } diff --git a/recaptcha-php/src/ReCaptcha/RequestParameters.php b/recaptcha-php/src/ReCaptcha/RequestParameters.php index f446842839dcadb6b65e54cccdf256aca7cab008..cb66f26cf4b6c76edc3707549c9c4f24ad08a295 100644 --- a/recaptcha-php/src/ReCaptcha/RequestParameters.php +++ b/recaptcha-php/src/ReCaptcha/RequestParameters.php @@ -98,6 +98,6 @@ class RequestParameters */ public function toQueryString() { - return http_build_query($this->toArray()); + return http_build_query($this->toArray(), '', '&'); } } diff --git a/recaptcha-php/src/autoload.php b/recaptcha-php/src/autoload.php new file mode 100644 index 0000000000000000000000000000000000000000..a53cbd78bf25c41ac1776f775e4e39d5be278b2f --- /dev/null +++ b/recaptcha-php/src/autoload.php @@ -0,0 +1,38 @@ +markTestSkipped( + 'The cURL extension is not available.' + ); + } + } + + public function testSubmit() + { + $curl = $this->getMock('\\ReCaptcha\\RequestMethod\\Curl', + array('init', 'setoptArray', 'exec', 'close')); + $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); + } +}