*/ public static function defaults(): array { return array( 'captcha_provider' => '', 'keys' => array(), // provider id => [ site_key, secret_key ]. 'recaptcha_threshold' => 0.5, 'use_disallowed_list' => true, 'store_ip' => false, // IP addresses are personal data: opt-in. 'retention_days' => 0, // 0 = keep entries until deleted. 'delete_data_on_uninstall' => false, // Read by uninstall.php: keep data unless chosen. ); } /** * All settings merged with defaults. * * @return array */ public static function all(): array { $stored = get_option( self::OPTION, array() ); return array_merge( self::defaults(), is_array( $stored ) ? $stored : array() ); } /** * One setting. * * @param string $key Setting key. */ public static function get( string $key ): mixed { return self::all()[ $key ] ?? null; } /** * A provider key ('site_key' or 'secret_key'). wp-config.php constants win. * * @param string $provider Provider id. * @param string $which 'site_key' or 'secret_key'. */ public static function key( string $provider, string $which ): string { $constant = self::constant_name( $provider, $which ); if ( defined( $constant ) ) { return (string) constant( $constant ); } $keys = self::get( 'keys' ); return is_array( $keys ) && isset( $keys[ $provider ][ $which ] ) ? (string) $keys[ $provider ][ $which ] : ''; } /** * Name of the wp-config.php constant for a key. * * @param string $provider Provider id. * @param string $which 'site_key' or 'secret_key'. */ public static function constant_name( string $provider, string $which ): string { return 'TFLEXFORMS_' . strtoupper( preg_replace( '/[^a-z0-9]/i', '_', $provider ) ?? '' ) . '_' . strtoupper( $which ); } /** * Sanitizes the option. Blank secret fields keep the stored secret, so * the secret never has to be printed back into the settings page. * * @param mixed $value Submitted value. * @return array */ public static function sanitize( mixed $value ): array { $value = is_array( $value ) ? $value : array(); $current = self::all(); $provider = sanitize_key( (string) ( $value['captcha_provider'] ?? '' ) ); $clean = array( 'captcha_provider' => array_key_exists( $provider, Captcha::providers() ) ? $provider : '', 'keys' => array(), 'recaptcha_threshold' => min( 0.9, max( 0.1, round( (float) ( $value['recaptcha_threshold'] ?? 0.5 ), 1 ) ) ), 'use_disallowed_list' => ! empty( $value['use_disallowed_list'] ), 'store_ip' => ! empty( $value['store_ip'] ), 'retention_days' => max( 0, min( 3650, (int) ( $value['retention_days'] ?? 0 ) ) ), 'delete_data_on_uninstall' => ! empty( $value['delete_data_on_uninstall'] ), ); foreach ( array_keys( Captcha::providers() ) as $id ) { $submitted = isset( $value['keys'][ $id ] ) && is_array( $value['keys'][ $id ] ) ? $value['keys'][ $id ] : array(); $site_key = self::clean_key( (string) ( $submitted['site_key'] ?? '' ) ); $secret = self::clean_key( (string) ( $submitted['secret_key'] ?? '' ) ); $old = is_array( $current['keys'][ $id ] ?? null ) ? $current['keys'][ $id ] : array(); $clean['keys'][ $id ] = array( 'site_key' => $site_key, 'secret_key' => ! empty( $submitted['clear_secret'] ) ? '' : ( '' !== $secret ? $secret : (string) ( $old['secret_key'] ?? '' ) ), ); } return $clean; } /** * Keys are opaque tokens: keep only safe characters. * * @param string $key Raw key. */ private static function clean_key( string $key ): string { return substr( preg_replace( '/[^A-Za-z0-9_\-.]/', '', trim( $key ) ) ?? '', 0, 200 ); } }