Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
901 changes: 901 additions & 0 deletions phpstan-baseline.neon

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions phpstan.neon
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
includes:
- phpstan-baseline.neon

parameters:
level: max
paths:
Expand Down
62 changes: 34 additions & 28 deletions src/ReCaptcha/ReCaptcha.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
<?php

declare(strict_types=1);

/**
* This is a PHP library that handles calling reCAPTCHA.
*
Expand Down Expand Up @@ -49,7 +47,7 @@ class ReCaptcha
*
* @var string
*/
public const VERSION = 'php_1.5.0';
public const VERSION = 'php_1.4.2';

/**
* URL for reCAPTCHA siteverify API.
Expand Down Expand Up @@ -137,19 +135,23 @@ class ReCaptcha

/**
* Shared secret for the site.
*
* @var string
*/
private string $secret;
private $secret;

/**
* Method used to communicate with service. Defaults to POST request.
*
* @var RequestMethod
*/
private RequestMethod $requestMethod;
private $requestMethod;

private ?string $hostname = null;
private ?string $apkPackageName = null;
private ?string $action = null;
private ?float $threshold = null;
private ?int $timeoutSeconds = null;
private $hostname;
private $apkPackageName;
private $action;
private $threshold;
private $timeoutSeconds;

/**
* Create a configured instance to use the reCAPTCHA service.
Expand All @@ -159,15 +161,19 @@ class ReCaptcha
*
* @throws \RuntimeException if $secret is invalid
*/
public function __construct(string $secret, ?RequestMethod $requestMethod = null)
public function __construct($secret, ?RequestMethod $requestMethod = null)
{
if ('' === $secret) {
if (empty($secret)) {
throw new \RuntimeException('No secret provided');
}

if (!is_string($secret)) {
throw new \RuntimeException('The provided secret must be a string');
}

$this->secret = $secret;

if (null !== $requestMethod) {
if (!is_null($requestMethod)) {
$this->requestMethod = $requestMethod;
} elseif (function_exists('curl_version')) {
$this->requestMethod = new RequestMethod\CurlPost();
Expand All @@ -180,15 +186,15 @@ public function __construct(string $secret, ?RequestMethod $requestMethod = null
* 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 null|string $remoteIp the end user's IP address
* @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(string $response, ?string $remoteIp = null): Response
public function verify($response, $remoteIp = null)
{
// Discard empty solution submissions
if ('' === $response) {
if (empty($response)) {
return new Response(false, [self::E_MISSING_INPUT_RESPONSE]);
}

Expand All @@ -197,23 +203,23 @@ public function verify(string $response, ?string $remoteIp = null): Response
$initialResponse = Response::fromJson($rawResponse);
$validationErrors = [];

if (null !== $this->hostname && 0 !== strcasecmp($this->hostname, $initialResponse->getHostname())) {
if (isset($this->hostname) && 0 !== strcasecmp($this->hostname, $initialResponse->getHostname())) {
$validationErrors[] = self::E_HOSTNAME_MISMATCH;
}

if (null !== $this->apkPackageName && 0 !== strcasecmp($this->apkPackageName, $initialResponse->getApkPackageName())) {
if (isset($this->apkPackageName) && 0 !== strcasecmp($this->apkPackageName, $initialResponse->getApkPackageName())) {
$validationErrors[] = self::E_APK_PACKAGE_NAME_MISMATCH;
}

if (null !== $this->action && 0 !== strcasecmp($this->action, $initialResponse->getAction())) {
if (isset($this->action) && 0 !== strcasecmp($this->action, $initialResponse->getAction())) {
$validationErrors[] = self::E_ACTION_MISMATCH;
}

if (null !== $this->threshold && $this->threshold > $initialResponse->getScore()) {
if (isset($this->threshold) && $this->threshold > $initialResponse->getScore()) {
$validationErrors[] = self::E_SCORE_THRESHOLD_NOT_MET;
}

if (null !== $this->timeoutSeconds) {
if (isset($this->timeoutSeconds)) {
$challengeTs = strtotime($initialResponse->getChallengeTs());

if ($challengeTs > 0 && time() - $challengeTs > $this->timeoutSeconds) {
Expand Down Expand Up @@ -244,7 +250,7 @@ public function verify(string $response, ?string $remoteIp = null): Response
*
* @return ReCaptcha Current instance for fluent interface
*/
public function setExpectedHostname(string $hostname): self
public function setExpectedHostname($hostname)
{
$this->hostname = $hostname;

Expand All @@ -258,7 +264,7 @@ public function setExpectedHostname(string $hostname): self
*
* @return ReCaptcha Current instance for fluent interface
*/
public function setExpectedApkPackageName(string $apkPackageName): self
public function setExpectedApkPackageName($apkPackageName)
{
$this->apkPackageName = $apkPackageName;

Expand All @@ -273,7 +279,7 @@ public function setExpectedApkPackageName(string $apkPackageName): self
*
* @return ReCaptcha Current instance for fluent interface
*/
public function setExpectedAction(string $action): self
public function setExpectedAction($action)
{
$this->action = $action;

Expand All @@ -288,9 +294,9 @@ public function setExpectedAction(string $action): self
*
* @return ReCaptcha Current instance for fluent interface
*/
public function setScoreThreshold(float $threshold): self
public function setScoreThreshold($threshold)
{
$this->threshold = $threshold;
$this->threshold = floatval($threshold);

return $this;
}
Expand All @@ -302,7 +308,7 @@ public function setScoreThreshold(float $threshold): self
*
* @return ReCaptcha Current instance for fluent interface
*/
public function setChallengeTimeout(int $timeoutSeconds): self
public function setChallengeTimeout($timeoutSeconds)
{
$this->timeoutSeconds = $timeoutSeconds;

Expand Down
4 changes: 1 addition & 3 deletions src/ReCaptcha/RequestMethod.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
<?php

declare(strict_types=1);

/**
* This is a PHP library that handles calling reCAPTCHA.
*
Expand Down Expand Up @@ -51,5 +49,5 @@ interface RequestMethod
*
* @return string Body of the reCAPTCHA response
*/
public function submit(RequestParameters $params): string;
public function submit(RequestParameters $params);
}
80 changes: 80 additions & 0 deletions src/ReCaptcha/RequestMethod/Curl.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
<?php

/**
* This is a PHP library that handles calling reCAPTCHA.
*
* BSD 3-Clause License
*
* @copyright (c) 2019, Google Inc.
*
* @see https://www.google.com/recaptcha
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

namespace ReCaptcha\RequestMethod;

/**
* Convenience wrapper around the cURL functions to allow mocking.
*/
class Curl
{
/**
* @see http://php.net/curl_init
*
* @param string $url
*
* @return resource cURL handle
*/
public function init($url = null)
{
return curl_init($url);
}

/**
* @see http://php.net/curl_setopt_array
*
* @param resource $ch
*
* @return bool
*/
public function setoptArray($ch, array $options)
{
return curl_setopt_array($ch, $options);
}

/**
* @see http://php.net/curl_exec
*
* @param resource $ch
*
* @return mixed
*/
public function exec($ch)
{
return curl_exec($ch);
}
}
40 changes: 22 additions & 18 deletions src/ReCaptcha/RequestMethod/CurlPost.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
<?php

declare(strict_types=1);

/**
* This is a PHP library that handles calling reCAPTCHA.
*
Expand Down Expand Up @@ -51,18 +49,29 @@
*/
class CurlPost implements RequestMethod
{
/**
* Curl connection to the reCAPTCHA service.
*
* @var Curl
*/
private $curl;

/**
* URL for reCAPTCHA siteverify API.
*
* @var string
*/
private string $siteVerifyUrl;
private $siteVerifyUrl;

/**
* Only needed if you want to override the defaults.
*
* @param null|string $siteVerifyUrl URL for reCAPTCHA siteverify API
* @param Curl $curl Curl resource
* @param string $siteVerifyUrl URL for reCAPTCHA siteverify API
*/
public function __construct(?string $siteVerifyUrl = null)
public function __construct(?Curl $curl = null, $siteVerifyUrl = null)
{
$this->curl = (is_null($curl)) ? new Curl() : $curl;
$this->siteVerifyUrl = (is_null($siteVerifyUrl)) ? ReCaptcha::SITE_VERIFY_URL : $siteVerifyUrl;
}

Expand All @@ -73,9 +82,9 @@ public function __construct(?string $siteVerifyUrl = null)
*
* @return string Body of the reCAPTCHA response
*/
public function submit(RequestParameters $params): string
public function submit(RequestParameters $params)
{
$handle = curl_init($this->siteVerifyUrl);
$handle = $this->curl->init($this->siteVerifyUrl);

$options = [
CURLOPT_POST => true,
Expand All @@ -87,20 +96,15 @@ public function submit(RequestParameters $params): string
CURLOPT_HEADER => false,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_SSL_VERIFYPEER => true,
CURLOPT_TIMEOUT => 60,
];
curl_setopt_array($handle, $options);
$this->curl->setoptArray($handle, $options);

try {
$response = curl_exec($handle);
$response = $this->curl->exec($handle);

if (is_string($response)) {
return $response;
}

return '{"success": false, "error-codes": ["'.ReCaptcha::E_CONNECTION_FAILED.'"]}';
} finally {
curl_close($handle);
if (false !== $response) {
return $response;
}

return '{"success": false, "error-codes": ["'.ReCaptcha::E_CONNECTION_FAILED.'"]}';
}
}
Loading
Loading