<?php
/**
* Built-in CAPTCHA (honeypot + math + rate limit).
*
* @package TonItaliaRegistration
*/
defined( 'ABSPATH' ) || exit;
/**
* Class TON_Reg_Captcha
*/
class TON_Reg_Captcha {
const NONCE_ACTION = 'ton_reg_form';
const FIELD_MATH = 'ton_reg_captcha_answer';
const FIELD_TOKEN = 'ton_reg_form_token';
const FIELD_HONEYPOT = 'ton_reg_website';
/**
* @return bool
*/
public static function is_enabled() {
return '1' === get_option( 'ton_reg_captcha_enabled', '1' );
}
/**
* @return string
*/
public static function create_token() {
$token = wp_generate_password( 32, false, false );
set_transient( self::token_key( $token ), time(), 30 * MINUTE_IN_SECONDS );
return $token;
}
/**
* @param string $token Token.
* @return string
*/
private static function token_key( $token ) {
return 'ton_reg_tok_' . md5( $token );
}
/**
* @param string $token Form token.
* @return array{a:int,b:int,question:string}
*/
public static function generate_challenge( $token ) {
$a = wp_rand( 2, 12 );
$b = wp_rand( 2, 12 );
$answer = $a + $b;
set_transient(
'ton_reg_cap_' . md5( $token ),
$answer,
30 * MINUTE_IN_SECONDS
);
return array(
'a' => $a,
'b' => $b,
'question' => sprintf(
/* translators: 1: number, 2: number */
__( 'Quanto fa %1$d + %2$d?', 'ton-italia-registration' ),
$a,
$b
),
);
}
/**
* @return bool
*/
public static function check_rate_limit() {
$ip = self::get_client_ip();
$key = 'ton_reg_rl_' . md5( $ip );
$max = max( 1, (int) get_option( 'ton_reg_rate_limit_max', 5 ) );
$window = max( 60, (int) get_option( 'ton_reg_rate_limit_window', 900 ) );
$count = (int) get_transient( $key );
if ( $count >= $max ) {
return false;
}
set_transient( $key, $count + 1, $window );
return true;
}
/**
* @param array<string,mixed> $post POST data.
* @return true|WP_Error
*/
public static function validate( $post ) {
if ( ! self::is_enabled() ) {
return true;
}
if ( ! empty( $post[ self::FIELD_HONEYPOT ] ) ) {
return new WP_Error( 'ton_reg_spam', __( 'Invio non valido.', 'ton-italia-registration' ) );
}
$token = isset( $post[ self::FIELD_TOKEN ] ) ? sanitize_text_field( wp_unslash( $post[ self::FIELD_TOKEN ] ) ) : '';
if ( ! $token || ! get_transient( self::token_key( $token ) ) ) {
return new WP_Error( 'ton_reg_token', __( 'Sessione scaduta. Ricarica la pagina e riprova.', 'ton-italia-registration' ) );
}
$issued = (int) get_transient( self::token_key( $token ) );
if ( time() - $issued < 3 ) {
return new WP_Error( 'ton_reg_fast', __( 'Attendi qualche secondo prima di inviare.', 'ton-italia-registration' ) );
}
$expected = get_transient( 'ton_reg_cap_' . md5( $token ) );
$answer = isset( $post[ self::FIELD_MATH ] ) ? (int) $post[ self::FIELD_MATH ] : -1;
if ( false === $expected || (int) $expected !== $answer ) {
return new WP_Error( 'ton_reg_captcha', __( 'Risposta di verifica non corretta.', 'ton-italia-registration' ) );
}
delete_transient( 'ton_reg_cap_' . md5( $token ) );
delete_transient( self::token_key( $token ) );
return true;
}
/**
* @return string
*/
public static function get_client_ip() {
$ip = '';
if ( ! empty( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) {
$parts = explode( ',', sanitize_text_field( wp_unslash( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) );
$ip = trim( $parts[0] );
} elseif ( ! empty( $_SERVER['REMOTE_ADDR'] ) ) {
$ip = sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ) );
}
return filter_var( $ip, FILTER_VALIDATE_IP ) ? $ip : '0.0.0.0';
}
}