# contact-forms/2.3.6/classes/Validation/Captcha3.php

Contact Forms by Cimatti, version 2.3.6. 120 lines.

- Page: https://pluginprobe.com/plugins/contact-forms/2.3.6/code/classes/Validation/Captcha3.php
- Raw: https://pluginprobe.com/plugins/contact-forms/2.3.6/raw/classes/Validation/Captcha3.php
- Modified: 2026-08-05T09:37:24+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/contact-forms/2.3.6/code/classes/Validation/Captcha3.php#L10-L20`.

```php
<?php
/**
 * reCAPTCHA v3 Validation
 *
 * The secret key, the expected action and the per-form spam action live on
 * the AccuaForm_Validation_CaptchaSpam base (see that class for the spam
 * action contract and the request-scoped flag registry shared with the
 * reCAPTCHA v2 validator); the minimum score is added here.
 *
 * @package Contact Forms
 */

// phpcs:disable WordPress.Security.NonceVerification, WordPress.Security.ValidatedSanitizedInput -- Server-side CAPTCHA validation requires POST data

class AccuaForm_Validation_Captcha3 extends AccuaForm_Validation_CaptchaSpam {
	protected $message = 'Error: Spam check failed. Please reload the page and retry.';

	/**
	 * Minimum score a submission must reach, resolved from the field instance
	 * override or the site-wide default before the form is rendered (see
	 * accua_forms_recaptcha3_score_threshold()). Lives on the validator, not
	 * on the Element, so it survives the encrypted-form serialization round
	 * trip.
	 *
	 * @var float
	 */
	protected $scoreThreshold = 0.5;

	/**
	 * Scores returned by Google during this request, keyed by the flag key
	 * (accuaform_{fid}). Recorded on pass and on fail alike so the submission
	 * handler can store the score of spam submissions too.
	 *
	 * @var array<string, float>
	 */
	protected static $scores = array();

	/**
	 * The score Google returned for the given form during this request.
	 *
	 * @param string $captcha_action The per-form flag key (accuaform_{fid}).
	 * @return float|null Null when no v3 verification ran, or when Google
	 *                    answered without a score.
	 */
	public static function getScore( $captcha_action ) {
		return isset( self::$scores[ $captcha_action ] ) ? self::$scores[ $captcha_action ] : null;
	}

	public function isValid( $value ) {
		if ( isset( $_POST['accua-forms-recaptcha3-response'] ) ) {
			$response = stripslashes_deep( $_POST['accua-forms-recaptcha3-response'] );
		} else {
			$response = (string) $value;
		}

		if ( '' === $response ) {
			return $this->failed();
		}

		$verify_url = 'https://www.google.com/recaptcha/api/siteverify';

		$verify_data = array(
			'secret'   => $this->privateKey,
			'response' => $response,
			'remoteip' => isset( $_SERVER['REMOTE_ADDR'] ) ? sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ) ) : '',
		);

		$response_obj = wp_remote_post(
			$verify_url,
			array(
				'body'    => $verify_data,
				'timeout' => 20,
			)
		);

		if ( is_wp_error( $response_obj ) ) {
			return $this->failed();
		}

		$body   = wp_remote_retrieve_body( $response_obj );
		$result = json_decode( $body, true );

		if ( empty( $result['success'] ) ) {
			return $this->failed();
		}

		// Reject tokens generated for a different action (token replay from another context).
		if ( ! isset( $result['action'] ) || $result['action'] !== $this->captchaAction ) {
			return $this->failed();
		}

		if ( ! isset( $result['score'] ) ) {
			return $this->failed();
		}

		$score = (float) $result['score'];

		// Keep the score for the submission handler, whatever the outcome.
		self::$scores[ $this->captchaAction ] = $score;

		/**
		 * Filter the minimum reCAPTCHA v3 score required to accept a submission.
		 *
		 * The default is the value configured by the administrator: the field
		 * instance override if it has one, otherwise the site-wide minimum
		 * score from the plugin settings page (0.5 out of the box).
		 *
		 * @param float  $threshold Minimum score (0.0 - 1.0).
		 * @param string $action    The reCAPTCHA action of the form being validated.
		 */
		$threshold = (float) apply_filters( 'accua_forms_recaptcha3_score_threshold', (float) $this->scoreThreshold, $this->captchaAction );

		if ( $score < $threshold ) {
			return $this->failed();
		}

		return true;
	}
}

```
