vendor/google/recaptcha/src/ReCaptcha/ReCaptcha.php line 139

  1. <?php
  2. /**
  3.  * This is a PHP library that handles calling reCAPTCHA.
  4.  *
  5.  * BSD 3-Clause License
  6.  * @copyright (c) 2019, Google Inc.
  7.  * @link https://www.google.com/recaptcha
  8.  * All rights reserved.
  9.  *
  10.  * Redistribution and use in source and binary forms, with or without
  11.  * modification, are permitted provided that the following conditions are met:
  12.  * 1. Redistributions of source code must retain the above copyright notice, this
  13.  *    list of conditions and the following disclaimer.
  14.  *
  15.  * 2. Redistributions in binary form must reproduce the above copyright notice,
  16.  *    this list of conditions and the following disclaimer in the documentation
  17.  *    and/or other materials provided with the distribution.
  18.  *
  19.  * 3. Neither the name of the copyright holder nor the names of its
  20.  *    contributors may be used to endorse or promote products derived from
  21.  *    this software without specific prior written permission.
  22.  *
  23.  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  24.  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  25.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  26.  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  27.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  28.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  29.  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  30.  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  31.  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  32.  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  33.  */
  34. namespace ReCaptcha;
  35. /**
  36.  * reCAPTCHA client.
  37.  */
  38. class ReCaptcha
  39. {
  40.     /**
  41.      * Version of this client library.
  42.      * @const string
  43.      */
  44.     public const VERSION 'php_1.3.0';
  45.     /**
  46.      * URL for reCAPTCHA siteverify API
  47.      * @const string
  48.      */
  49.     public const SITE_VERIFY_URL 'https://www.google.com/recaptcha/api/siteverify';
  50.     /**
  51.      * Invalid JSON received
  52.      * @const string
  53.      */
  54.     public const E_INVALID_JSON 'invalid-json';
  55.     /**
  56.      * Could not connect to service
  57.      * @const string
  58.      */
  59.     public const E_CONNECTION_FAILED 'connection-failed';
  60.     /**
  61.      * Did not receive a 200 from the service
  62.      * @const string
  63.      */
  64.     public const E_BAD_RESPONSE 'bad-response';
  65.     /**
  66.      * Not a success, but no error codes received!
  67.      * @const string
  68.      */
  69.     public const E_UNKNOWN_ERROR 'unknown-error';
  70.     /**
  71.      * ReCAPTCHA response not provided
  72.      * @const string
  73.      */
  74.     public const E_MISSING_INPUT_RESPONSE 'missing-input-response';
  75.     /**
  76.      * Expected hostname did not match
  77.      * @const string
  78.      */
  79.     public const E_HOSTNAME_MISMATCH 'hostname-mismatch';
  80.     /**
  81.      * Expected APK package name did not match
  82.      * @const string
  83.      */
  84.     public const E_APK_PACKAGE_NAME_MISMATCH 'apk_package_name-mismatch';
  85.     /**
  86.      * Expected action did not match
  87.      * @const string
  88.      */
  89.     public const E_ACTION_MISMATCH 'action-mismatch';
  90.     /**
  91.      * Score threshold not met
  92.      * @const string
  93.      */
  94.     public const E_SCORE_THRESHOLD_NOT_MET 'score-threshold-not-met';
  95.     /**
  96.      * Challenge timeout
  97.      * @const string
  98.      */
  99.     public const E_CHALLENGE_TIMEOUT 'challenge-timeout';
  100.     /**
  101.      * Shared secret for the site.
  102.      * @var string
  103.      */
  104.     private $secret;
  105.     /**
  106.      * Method used to communicate with service. Defaults to POST request.
  107.      * @var RequestMethod
  108.      */
  109.     private $requestMethod;
  110.     private $hostname;
  111.     private $apkPackageName;
  112.     private $action;
  113.     private $threshold;
  114.     private $timeoutSeconds;
  115.     /**
  116.      * Create a configured instance to use the reCAPTCHA service.
  117.      *
  118.      * @param string $secret The shared key between your site and reCAPTCHA.
  119.      * @param RequestMethod $requestMethod method used to send the request. Defaults to POST.
  120.      * @throws \RuntimeException if $secret is invalid
  121.      */
  122.     public function __construct($secretRequestMethod $requestMethod null)
  123.     {
  124.         if (empty($secret)) {
  125.             throw new \RuntimeException('No secret provided');
  126.         }
  127.         if (!is_string($secret)) {
  128.             throw new \RuntimeException('The provided secret must be a string');
  129.         }
  130.         $this->secret $secret;
  131.         $this->requestMethod = (is_null($requestMethod)) ? new RequestMethod\Post() : $requestMethod;
  132.     }
  133.     /**
  134.      * Calls the reCAPTCHA siteverify API to verify whether the user passes
  135.      * CAPTCHA test and additionally runs any specified additional checks
  136.      *
  137.      * @param string $response The user response token provided by reCAPTCHA, verifying the user on your site.
  138.      * @param string $remoteIp The end user's IP address.
  139.      * @return Response Response from the service.
  140.      */
  141.     public function verify($response$remoteIp null)
  142.     {
  143.         // Discard empty solution submissions
  144.         if (empty($response)) {
  145.             $recaptchaResponse = new Response(false, array(self::E_MISSING_INPUT_RESPONSE));
  146.             return $recaptchaResponse;
  147.         }
  148.         $params = new RequestParameters($this->secret$response$remoteIpself::VERSION);
  149.         $rawResponse $this->requestMethod->submit($params);
  150.         $initialResponse Response::fromJson($rawResponse);
  151.         $validationErrors = array();
  152.         if (isset($this->hostname) && strcasecmp($this->hostname$initialResponse->getHostname()) !== 0) {
  153.             $validationErrors[] = self::E_HOSTNAME_MISMATCH;
  154.         }
  155.         if (isset($this->apkPackageName) && strcasecmp($this->apkPackageName$initialResponse->getApkPackageName()) !== 0) {
  156.             $validationErrors[] = self::E_APK_PACKAGE_NAME_MISMATCH;
  157.         }
  158.         if (isset($this->action) && strcasecmp($this->action$initialResponse->getAction()) !== 0) {
  159.             $validationErrors[] = self::E_ACTION_MISMATCH;
  160.         }
  161.         if (isset($this->threshold) && $this->threshold $initialResponse->getScore()) {
  162.             $validationErrors[] = self::E_SCORE_THRESHOLD_NOT_MET;
  163.         }
  164.         if (isset($this->timeoutSeconds)) {
  165.             $challengeTs strtotime($initialResponse->getChallengeTs());
  166.             if ($challengeTs && time() - $challengeTs $this->timeoutSeconds) {
  167.                 $validationErrors[] = self::E_CHALLENGE_TIMEOUT;
  168.             }
  169.         }
  170.         if (empty($validationErrors)) {
  171.             return $initialResponse;
  172.         }
  173.         return new Response(
  174.             false,
  175.             array_merge($initialResponse->getErrorCodes(), $validationErrors),
  176.             $initialResponse->getHostname(),
  177.             $initialResponse->getChallengeTs(),
  178.             $initialResponse->getApkPackageName(),
  179.             $initialResponse->getScore(),
  180.             $initialResponse->getAction()
  181.         );
  182.     }
  183.     /**
  184.      * Provide a hostname to match against in verify()
  185.      * This should be without a protocol or trailing slash, e.g. www.google.com
  186.      *
  187.      * @param string $hostname Expected hostname
  188.      * @return ReCaptcha Current instance for fluent interface
  189.      */
  190.     public function setExpectedHostname($hostname)
  191.     {
  192.         $this->hostname $hostname;
  193.         return $this;
  194.     }
  195.     /**
  196.      * Provide an APK package name to match against in verify()
  197.      *
  198.      * @param string $apkPackageName Expected APK package name
  199.      * @return ReCaptcha Current instance for fluent interface
  200.      */
  201.     public function setExpectedApkPackageName($apkPackageName)
  202.     {
  203.         $this->apkPackageName $apkPackageName;
  204.         return $this;
  205.     }
  206.     /**
  207.      * Provide an action to match against in verify()
  208.      * This should be set per page.
  209.      *
  210.      * @param string $action Expected action
  211.      * @return ReCaptcha Current instance for fluent interface
  212.      */
  213.     public function setExpectedAction($action)
  214.     {
  215.         $this->action $action;
  216.         return $this;
  217.     }
  218.     /**
  219.      * Provide a threshold to meet or exceed in verify()
  220.      * Threshold should be a float between 0 and 1 which will be tested as response >= threshold.
  221.      *
  222.      * @param float $threshold Expected threshold
  223.      * @return ReCaptcha Current instance for fluent interface
  224.      */
  225.     public function setScoreThreshold($threshold)
  226.     {
  227.         $this->threshold floatval($threshold);
  228.         return $this;
  229.     }
  230.     /**
  231.      * Provide a timeout in seconds to test against the challenge timestamp in verify()
  232.      *
  233.      * @param int $timeoutSeconds Expected hostname
  234.      * @return ReCaptcha Current instance for fluent interface
  235.      */
  236.     public function setChallengeTimeout($timeoutSeconds)
  237.     {
  238.         $this->timeoutSeconds $timeoutSeconds;
  239.         return $this;
  240.     }
  241. }