From 55b0c1f948ac1b885416f058ba54f9860570995f Mon Sep 17 00:00:00 2001 From: James Turner Date: Sun, 14 Dec 2014 21:18:44 +0000 Subject: [PATCH] Now handle more error cases. Throw malformed response exception for times when the json we get back is non-compliant with the documentation. Also provide helper methods on the response object to better identify the problem. --- src/Google/MalformedResponseException.php | 9 +++ src/Google/ReCaptcha.php | 13 ++-- src/Google/ReCaptchaResponse.php | 23 +++++++ test/Google/Test/RecaptchaTest.php | 73 +++++++++++++++++++++-- 4 files changed, 107 insertions(+), 11 deletions(-) create mode 100644 src/Google/MalformedResponseException.php diff --git a/src/Google/MalformedResponseException.php b/src/Google/MalformedResponseException.php new file mode 100644 index 0000000..8575427 --- /dev/null +++ b/src/Google/MalformedResponseException.php @@ -0,0 +1,9 @@ +getMessage(), $e->getCode(), $e); } // verify json decoding. - if (false !== ($json = json_decode($response, true))) { + if (null !== ($json = json_decode($response, true))) { - if ($json['success']) { + if(array_key_exists("success", $json) && $json['success']) { return new ReCaptchaResponse(true); + }elseif(array_key_exists("error-codes", $json) && is_array($json['error-codes'])) { + return new ReCaptchaResponse(false, $json['error-codes']); + }else{ + throw new MalformedResponseException($response); } - return new ReCaptchaResponse(false, $json['error-codes']); } throw new ReCaptchaException("Non-json response '$response'"); } -} - -?> +} \ No newline at end of file diff --git a/src/Google/ReCaptchaResponse.php b/src/Google/ReCaptchaResponse.php index d489aab..81979c0 100644 --- a/src/Google/ReCaptchaResponse.php +++ b/src/Google/ReCaptchaResponse.php @@ -7,6 +7,12 @@ */ final class ReCaptchaResponse { + + const MISSING_INPUT_SECRET = "missing-input-secret"; + const INVALID_INPUT_SECRET = "invalid-input-secret"; + const MISSING_INPUT_RESPONSE = "missing-input-response"; + const INVALID_INPUT_RESPONSE = "invalid-input-response"; + private $success; private $errors; @@ -33,4 +39,21 @@ public function isSuccess(){ public function isFailure(){ return !$this->isSuccess(); } + + public function isMissingInputSecret(){ + return array_search(static::MISSING_INPUT_SECRET, $this->errors)!==false; + } + + public function isMissingInputResponse(){ + return array_search(static::MISSING_INPUT_RESPONSE, $this->errors)!==false; + } + + public function isInvalidInputSecret(){ + return array_search(static::INVALID_INPUT_SECRET, $this->errors)!==false; + } + + public function isInvalidInputResponse(){ + return array_search(static::INVALID_INPUT_RESPONSE, $this->errors)!==false; + } + } \ No newline at end of file diff --git a/test/Google/Test/RecaptchaTest.php b/test/Google/Test/RecaptchaTest.php index 22546cf..92c0a53 100644 --- a/test/Google/Test/RecaptchaTest.php +++ b/test/Google/Test/RecaptchaTest.php @@ -4,6 +4,7 @@ use Google\HttpClientException; use Google\ReCaptcha; +use Google\ReCaptchaException; use Google\ReCaptchaResponse; final class RecaptchaTest extends \PHPUnit_Framework_TestCase @@ -49,8 +50,10 @@ public function testInvalidSecret() $mockAdapter->expects($this->once())->method('get')->will($this->returnValue($this->invalidSecret())); $recaptcha = new ReCaptcha("bad secret", $mockAdapter); + $response = $recaptcha->validate("any token"); - $this->assertThat($recaptcha->validate("any token"), $this->equalTo(new ReCaptchaResponse(false, ["invalid-input-secret"]))); + $this->assertThat($response->isFailure(), $this->isTrue()); + $this->assertThat($response->isInvalidInputSecret(), $this->isTrue()); } public function testMissingSecret() @@ -59,8 +62,10 @@ public function testMissingSecret() $mockAdapter->expects($this->once())->method('get')->will($this->returnValue($this->missingSecret())); $recaptcha = new ReCaptcha("bad secret", $mockAdapter); + $response = $recaptcha->validate("any token"); - $this->assertThat($recaptcha->validate("any token"), $this->equalTo(new ReCaptchaResponse(false, ["missing-input-secret"]))); + $this->assertThat($response->isFailure(), $this->isTrue()); + $this->assertThat($response->isMissingInputSecret(), $this->isTrue()); } public function testInvalidToken() @@ -69,8 +74,10 @@ public function testInvalidToken() $mockAdapter->expects($this->once())->method('get')->will($this->returnValue($this->invalidToken())); $recaptcha = new ReCaptcha("bad secret", $mockAdapter); + $response = $recaptcha->validate("any token"); - $this->assertThat($recaptcha->validate("any token"), $this->equalTo(new ReCaptchaResponse(false, ["invalid-input-response"]))); + $this->assertThat($response->isFailure(), $this->isTrue()); + $this->assertThat($response->isInvalidInputResponse(), $this->isTrue()); } @@ -79,9 +86,11 @@ public function testMissingToken() $mockAdapter = $this->getMock('Google\HttpClientGetAdapter'); $mockAdapter->expects($this->once())->method('get')->will($this->returnValue($this->missingToken())); - $recaptcha = new ReCaptcha("bad secret", $mockAdapter); + $recaptcha = new ReCaptcha("some secret", $mockAdapter); - $this->assertThat($recaptcha->validate("any token"), $this->equalTo(new ReCaptchaResponse(false, ["missing-input-response"]))); + $response = $recaptcha->validate("any token"); + $this->assertThat($response->isFailure(), $this->isTrue()); + $this->assertThat($response->isMissingInputResponse(), $this->isTrue()); } public function testRealFailure() @@ -92,6 +101,60 @@ public function testRealFailure() $this->assertThat($recaptchaResponse, $this->equalTo(new ReCaptchaResponse(false, ["invalid-input-response","invalid-input-secret"]))); } + public function testInvalidJSON(){ + + $this->setExpectedException("Google\ReCaptchaException"); + + $httpAdapter = $this->getMock("Google\HttpClientGetAdapter"); + $httpAdapter->expects($this->once())->method('get')->will($this->returnValue("what no json here!")); + + $recaptcha = new ReCaptcha("some secret", $httpAdapter); + $recaptcha->validate("any token"); + + } + + public function testPartialJSON(){ + + $this->setExpectedException("Google\ReCaptchaException"); + + $httpAdapter = $this->getMock("Google\HttpClientGetAdapter"); + $httpAdapter->expects($this->once())->method('get')->will($this->returnValue(json_encode(["success"=>false]))); + + $recaptcha = new ReCaptcha("good secret", $httpAdapter); + $recaptcha->validate("any token"); + } + + public function testCustomHttpClientExceptionHandling(){ + + $httpException = new \Exception(); + + $httpAdapter = $this->getMock("Google\HttpClientGetAdapter"); + $httpAdapter->expects($this->once())->method('get')->will($this->throwException($httpException)); + + try { + + $recaptcha = new ReCaptcha("some secret", $httpAdapter); + $recaptcha->validate("any token"); + }catch (ReCaptchaException $e){ + + } + + $this->assertThat($e, $this->isInstanceOf("Google\ReCaptchaException")); + // must contain previously thrown exception + $this->assertThat($e->getPrevious(), $this->equalTo($httpException)); + } + + public function testNonExpectedJSONResponse(){ + + $this->setExpectedException("Google\MalformedResponseException"); + + $httpAdapter = $this->getMock("Google\HttpClientGetAdapter"); + $httpAdapter->expects($this->once())->method('get')->will($this->returnValue(json_encode(["some other key" => "some other value"]))); + + $recaptcha = new ReCaptcha("some secret", $httpAdapter); + $recaptcha->validate("any token"); + } + private function validUrl() {