Plugin Directory

Changeset 3402920


Ignore:
Timestamp:
11/25/2025 11:38:59 PM (4 months ago)
Author:
codekraft
Message:

v0.7.2

Location:
cf7-antispam
Files:
175 added
26 edited

Legend:

Unmodified
Added
Removed
  • cf7-antispam/trunk/admin/CF7_AntiSpam_Admin_Customizations.php

    r3389259 r3402920  
    573573        /* Enable customizations */
    574574        add_settings_field(
     575            'cf7a_customizations_class',
     576            __( 'Your unique css class', 'cf7-antispam' ),
     577            array( $this, 'cf7a_customizations_class_callback' ),
     578            'cf7a-settings',
     579            'cf7a_customizations'
     580        );
     581
     582        /* Enable customizations */
     583        add_settings_field(
     584            'cf7a_customizations_prefix',
     585            __( 'Your unique fields prefix', 'cf7-antispam' ),
     586            array( $this, 'cf7a_customizations_prefix_callback' ),
     587            'cf7a-settings',
     588            'cf7a_customizations'
     589        );
     590
     591        /* Enable customizations */
     592        add_settings_field(
     593            'cf7a_cipher',
     594            __( 'The encryption method', 'cf7-antispam' ),
     595            array( $this, 'cf7a_customizations_cipher_callback' ),
     596            'cf7a-settings',
     597            'cf7a_customizations'
     598        );
     599
     600        /* Section Optimizations */
     601        add_settings_section(
     602            'cf7a_optimizations',
     603            __( 'Optimizations', 'cf7-antispam' ),
     604            array( $this, 'cf7a_optimizations' ),
     605            'cf7a-settings'
     606        );
     607
     608        /* Settings Script optimizations */
     609        add_settings_field(
     610            'cf7a_optimizations_scripts',
     611            __( 'Optimize scripts loading', 'cf7-antispam' ),
     612            array( $this, 'cf7a_optimizations_scripts_callback' ),
     613            'cf7a-settings',
     614            'cf7a_optimizations'
     615        );
     616
     617        /* Disable cf7 form reload if the page is cached */
     618        add_settings_field(
    575619            'cf7a_disable_reload',
    576620            __( 'Disable cf7 form reload if the page is cached', 'cf7-antispam' ),
    577621            array( $this, 'cf7a_disable_reload_callback' ),
    578622            'cf7a-settings',
    579             'cf7a_customizations'
    580         );
    581 
    582         /* Enable customizations */
    583         add_settings_field(
    584             'cf7a_customizations_class',
    585             __( 'Your unique css class', 'cf7-antispam' ),
    586             array( $this, 'cf7a_customizations_class_callback' ),
    587             'cf7a-settings',
    588             'cf7a_customizations'
    589         );
    590 
    591         /* Enable customizations */
    592         add_settings_field(
    593             'cf7a_customizations_prefix',
    594             __( 'Your unique fields prefix', 'cf7-antispam' ),
    595             array( $this, 'cf7a_customizations_prefix_callback' ),
    596             'cf7a-settings',
    597             'cf7a_customizations'
    598         );
    599 
    600         /* Enable customizations */
    601         add_settings_field(
    602             'cf7a_cipher',
    603             __( 'The encryption method', 'cf7-antispam' ),
    604             array( $this, 'cf7a_customizations_cipher_callback' ),
    605             'cf7a-settings',
    606             'cf7a_customizations'
     623            'cf7a_optimizations'
    607624        );
    608625
     
    10711088        $new_input['cf7a_enabled'] = isset( $input['cf7a_enabled'] ) ? 1 : 0;
    10721089
    1073         $new_input['cf7a_enable'] = isset( $input['cf7a_enable'] ) ? $input['cf7a_enable'] : $new_input['cf7a_enable'];
     1090        $new_input['cf7a_enable'] = $input['cf7a_enable'] ?? $new_input['cf7a_enable'];
    10741091
    10751092        /* bot fingerprint */
     
    12661283        }
    12671284
     1285        /* Optimizations */
     1286        $new_input['optimize_scripts_loading'] = !empty( $input['optimize_scripts_loading'] ) ? 1 : 0;
     1287        $new_input['cf7a_disable_reload'] = !empty( $input['cf7a_disable_reload'] ) ? 1 : 0;
     1288
    12681289        /* Customizations */
    1269         $new_input['cf7a_disable_reload'] = isset( $input['cf7a_disable_reload'] ) ? 1 : 0;
    1270 
    12711290        $input['cf7a_customizations_class']     = sanitize_html_class( $input['cf7a_customizations_class'] );
    12721291        $new_input['cf7a_customizations_class'] = ! empty( $input['cf7a_customizations_class'] ) ? sanitize_html_class( $input['cf7a_customizations_class'] ) : CF7ANTISPAM_HONEYPOT_CLASS;
     
    14151434        // the upload button for the database if the download is disabled
    14161435        printf( '<input type="button" id="geoip_force_download" class="button cf7a_action" data-action="force-geoip-download" data-callback="update-geoip-status" data-nonce="%s" value="%s" />',
    1417             wp_create_nonce( 'cf7a-nonce' ),
     1436            esc_attr(wp_create_nonce( 'cf7a-nonce' )),
    14181437            esc_attr__( 'Force Download', 'cf7-antispam' )
    14191438        );
     
    14281447            esc_html__( 'No file selected', 'cf7-antispam' )
    14291448        );
    1430         echo '<p class="geoip_dbfile text-xs"> Accepted formats: .mmdb or .tar.gz </p>';
     1449        printf( '<p class="geoip_dbfile text-xs">%s</p>', esc_html__( 'Accepted formats: .mmdb or .tar.gz', 'cf7-antispam' ) );
    14311450    }
    14321451
     
    17331752    }
    17341753
    1735 
    1736     /** It creates a checkbox with the id of "cf7a_disable_reload_callback" */
    1737     public function cf7a_disable_reload_callback() {
    1738         printf(
    1739             '<input type="checkbox" id="cf7a_disable_reload" name="cf7a_options[cf7a_disable_reload]" %s />',
    1740             ! empty( $this->options['cf7a_disable_reload'] ) ? 'checked="true"' : ''
    1741         );
    1742     }
    17431754    /** It creates a checkbox with the id of "cf7a_customizations_class_callback" */
    17441755    public function cf7a_customizations_class_callback() {
     
    17791790    }
    17801791
     1792    /** It prints the optimizations info */
     1793    public function cf7a_optimizations() {
     1794        printf( '<p>%s</p>', esc_html__( 'You can optimize the loading performance of the antispam scripts. Since optimization is a risky business, we do not recommend enabling this option without trying it first.', 'cf7-antispam' ) );
     1795    }
     1796
     1797    /** It creates a checkbox with the id of "optimize_scripts_loading" */
     1798    public function cf7a_optimizations_scripts_callback() {
     1799        printf(
     1800            '<input type="checkbox" id="optimize_scripts_loading" name="cf7a_options[optimize_scripts_loading]" %s />',
     1801            ! empty( $this->options['optimize_scripts_loading'] ) ? 'checked="true"' : ''
     1802        );
     1803    }
     1804
     1805    /** It creates a checkbox with the id of "cf7a_disable_reload_callback" */
     1806    public function cf7a_disable_reload_callback() {
     1807        printf(
     1808            '<input type="checkbox" id="cf7a_disable_reload" name="cf7a_options[cf7a_disable_reload]" %s />',
     1809            ! empty( $this->options['cf7a_disable_reload'] ) ? 'checked="true"' : ''
     1810        );
     1811    }
     1812
    17811813
    17821814    /** It creates a checkbox with the id of "cf7a_score_fingerprinting_callback" */
  • cf7-antispam/trunk/admin/CF7_AntiSpam_Admin_Display.php

    r3389259 r3402920  
    821821    }
    822822
     823    private function get_plugin_version( $plugin_file ) {
     824        if ( file_exists( $plugin_file ) ) {
     825            $plugin_data = get_plugin_data( $plugin_file );
     826            if ( ! empty( $plugin_data['Version'] ) ) {
     827                return $plugin_data['Version'];
     828            }
     829        }
     830        return 'Not installed';
     831    }
     832
    823833    /**
    824834     * It returns a string containing a formatted HTML table with the plugin's options
     
    827837     */
    828838    private function cf7a_get_debug_info_options() {
     839        global $wpdb;
     840        $cf7_plugin_file = WP_PLUGIN_DIR . '/contact-form-7/wp-contact-form-7.php';
     841        $flamingo_plugin_file = WP_PLUGIN_DIR . '/flamingo/flamingo.php';
     842        $debug_data = array(
     843            'cf7a_version' => CF7ANTISPAM_VERSION,
     844            'cf7a_options' => $this->options,
     845            'wp_version' => get_bloginfo( 'version' ),
     846            'contact_form_7_version' => $this->get_plugin_version($cf7_plugin_file),
     847            'flamingo_version' => $this->get_plugin_version($flamingo_plugin_file),
     848            'php_version' => PHP_VERSION,
     849            'mysql_version' => $wpdb->db_version(),
     850            'plugins' => array_map(function($plugin) {
     851                return $plugin['Name'] . ' (' . $plugin['Version'] . ')';
     852            }, get_plugins()),
     853            'wp_debug' => WP_DEBUG ? 'Enabled' : 'Disabled',
     854            'wp_debug_log' => WP_DEBUG_LOG ? 'Enabled' : 'Disabled',
     855            'wp_debug_display' => WP_DEBUG_DISPLAY ? 'Enabled' : 'Disabled',
     856            'wp_memory_limit' => WP_MEMORY_LIMIT,
     857            'php_memory_limit' => ini_get( 'memory_limit' ),
     858            'upload_max_size' => ini_get( 'upload_max_size' ),
     859            'post_max_size' => ini_get( 'post_max_size' ),
     860        );
    829861        printf( '<h2 class="title">%s</h2>', esc_html__( 'Options debug', 'cf7-antispam' ) );
    830862        printf(
     
    833865            esc_html(
    834866                htmlentities(
    835                     print_r( $this->options, true ) // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r
     867                    print_r( $debug_data, true ) // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r
    836868                )
    837869            )
  • cf7-antispam/trunk/admin/CF7_AntiSpam_Admin_Tools.php

    r3389259 r3402920  
    22
    33namespace CF7_AntiSpam\Admin;
    4 
    5 use CF7_AntiSpam\Core\CF7_AntiSpam;
    6 use CF7_AntiSpam\Core\CF7_AntiSpam_Filters;
    7 use CF7_AntiSpam\Core\CF7_AntiSpam_Flamingo;
    8 use CF7_AntiSpam\Engine\CF7_AntiSpam_Uninstaller;
    94
    105/**
     
    2419     * It sets a transient with the name of `cf7a_notice` and the value of the notice
    2520     *
    26      * @param string  $message The message you want to display.
    27      * @param string  $type error, warning, success, info.
     21     * @param string $message The message you want to display.
     22     * @param string $type error, warning, success, info.
    2823     * @param boolean $dismissible when the notice needs the close button.
    2924     */
    30     public static function cf7a_push_notice( $message = 'generic', $type = 'error', $dismissible = true ) {
     25    public static function cf7a_push_notice( string $message = 'generic', string $type = 'error', bool $dismissible = true ) {
    3126        $class  = "notice notice-$type";
    3227        $class .= $dismissible ? ' is-dismissible' : '';
     
    3530    }
    3631
     32    /**
     33     * It exports the blacklist
     34     */
    3735    public static function cf7a_export_blacklist() {
    3836        global $wpdb;
     
    6866        }
    6967    }
     68
     69    /**
     70     * It sends an email to the admin
     71     *
     72     * @param string $subject the mail message subject
     73     * @param string $recipient the mail recipient
     74     * @param string $body the mail message content
     75     * @param string $sender the mail message sender
     76     */
     77    public function send_email_to_admin( string $subject, string $recipient, string $body, string $sender ) {
     78        /**
     79         * Filter cf7-antispam before resend an email who was spammed
     80         *
     81         * @param string $body the mail message content
     82         * @param string $sender the mail message sender
     83         * @param string $subject the mail message subject
     84         * @param string $recipient the mail recipient
     85         *
     86         * @returns string the mail body content
     87         */
     88        $body = apply_filters( 'cf7a_before_resend_email', $body, $sender, $subject, $recipient );
     89
     90        // Set up headers correctly
     91        $site_name  = get_bloginfo( 'name' );
     92        $from_email = get_option( 'admin_email' );
     93
     94        $headers  = "From: {$site_name} <{$from_email}>\n";
     95        $headers .= "Content-Type: text/html\n";
     96        $headers .= "X-WPCF7-Content-Type: text/html\n";
     97        $headers .= "Reply-To: {$sender}\n";
     98
     99        /* send the email */
     100        return wp_mail( $recipient, $subject, $body, $headers );
     101    }
    70102}
  • cf7-antispam/trunk/cf7-antispam.php

    r3392568 r3402920  
    66 * Text Domain: cf7-antispam
    77 * Domain Path: /languages
    8  * Version: 0.7.1
     8 * Version: 0.7.2
    99 * License: GPLv2 or later
     10 * Requires Plugins: contact-form-7
    1011 *
    1112 * @package cf7-antispam
     
    2021define( 'CF7ANTISPAM_NAME', 'cf7-antispam' );
    2122
    22 define( 'CF7ANTISPAM_VERSION', '0.7.1' );
     23define( 'CF7ANTISPAM_VERSION', '0.7.2' );
    2324
    2425define( 'CF7ANTISPAM_PLUGIN', __FILE__ );
  • cf7-antispam/trunk/core/CF7_AntiSpam.php

    r3389259 r3402920  
    169169
    170170        /* the unspam routine */
    171         add_action( 'cf7a_cron', array( $plugin_antispam, 'cf7a_cron_unban' ) );
     171        $blacklist = new CF7_Antispam_Blacklist();
     172        add_action( 'cf7a_cron', array( $blacklist, 'cf7a_cron_unban' ) );
    172173
    173174        /* flamingo */
     
    260261            $plugin_frontend = new CF7_AntiSpam_Frontend( $this->get_plugin_name(), $this->get_version() );
    261262
    262             $this->loader->add_action( 'wp', $plugin_frontend, 'setup' );
     263            $plugin_frontend->setup();
     264            $plugin_frontend->load_scripts();
    263265        }
    264266    }
  • cf7-antispam/trunk/core/CF7_AntiSpam_Filters.php

    r3392568 r3402920  
    1212namespace CF7_AntiSpam\Core;
    1313
     14use CF7_AntiSpam\Admin\CF7_AntiSpam_Admin_Tools;
    1415use Exception;
    1516use WPCF7_Submission;
     
    2223    /**
    2324     * CF7_AntiSpam_Filters constructor.
     25     * Registers the individual spam checks to the custom filter hook.
    2426     */
    2527    public function __construct() {
    26     }
     28        // Priority 5: Whitelist checks (should run first to stop processing if safe)
     29        add_filter( 'cf7a_spam_check_chain', array( $this, 'filter_ip_whitelist' ), 5 );
     30
     31        // Priority 10: Standard checks
     32        add_filter( 'cf7a_spam_check_chain', array( $this, 'filter_empty_ip' ), 10 );
     33        add_filter( 'cf7a_spam_check_chain', array( $this, 'filter_bad_ip' ), 10 );
     34        add_filter( 'cf7a_spam_check_chain', array( $this, 'filter_ip_blacklist_history' ), 10 );
     35        add_filter( 'cf7a_spam_check_chain', array( $this, 'filter_honeyform' ), 10 );
     36
     37        // Checks that originally ran only if score < 1 (See logic inside methods)
     38        add_filter( 'cf7a_spam_check_chain', array( $this, 'filter_referrer_protocol' ), 10 );
     39        add_filter( 'cf7a_spam_check_chain', array( $this, 'filter_plugin_version' ), 10 );
     40        add_filter( 'cf7a_spam_check_chain', array( $this, 'filter_bot_fingerprint' ), 10 );
     41        add_filter( 'cf7a_spam_check_chain', array( $this, 'filter_bot_fingerprint_extras' ), 10 );
     42        add_filter( 'cf7a_spam_check_chain', array( $this, 'filter_language' ), 10 );
     43        add_filter( 'cf7a_spam_check_chain', array( $this, 'filter_geoip' ), 10 );
     44        add_filter( 'cf7a_spam_check_chain', array( $this, 'filter_time_submission' ), 10 );
     45        add_filter( 'cf7a_spam_check_chain', array( $this, 'filter_bad_email_strings' ), 10 );
     46        add_filter( 'cf7a_spam_check_chain', array( $this, 'filter_user_agent' ), 10 );
     47        add_filter( 'cf7a_spam_check_chain', array( $this, 'filter_bad_words' ), 10 );
     48        add_filter( 'cf7a_spam_check_chain', array( $this, 'filter_dnsbl' ), 10 );
     49        add_filter( 'cf7a_spam_check_chain', array( $this, 'filter_honeypot' ), 10 );
     50
     51        // Priority 20: Bayesian filter
     52        add_filter( 'cf7a_spam_check_chain', array( $this, 'filter_b8_bayesian' ), 20 );
     53    }
     54
     55    // ---------------------
     56    // STATIC HELPER METHODS
     57    // ---------------------
    2758
    2859    /**
     
    75106    public static function cf7a_check_dnsbl( $reverse_ip, $dnsbl ) {
    76107        return checkdnsrr( $reverse_ip . '.' . $dnsbl . '.', 'A' );
    77     }
    78 
    79     /* CF7_AntiSpam_Filters blacklists */
    80 
    81     /**
    82      * It takes an IP address as a parameter, validates it, and then returns the row from the database that matches that IP
    83      * address
    84      *
    85      * @param string $ip - The IP address to check.
    86      *
    87      * @return array|object|null - the row from the database that matches the IP address.
    88      */
    89     public static function cf7a_blacklist_get_ip( $ip ) {
    90         $ip = filter_var( $ip, FILTER_VALIDATE_IP );
    91         if ( $ip ) {
    92             global $wpdb;
    93             // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
    94             $r = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM %i WHERE ip = %s", $wpdb->prefix . 'cf7a_blacklist', $ip ) );
    95             if ( $r ) {
    96                 return $r;
    97             }
    98         }
    99 
    100         return null;
    101     }
    102 
    103     /**
    104      * It gets the row from the database where the id is equal to the id passed to the function
    105      *
    106      * @param int $id The ID of the blacklist item.
    107      *
    108      * @return object|false the row from the database that matches the id.
    109      */
    110     public function cf7a_blacklist_get_id( $id ) {
    111         if ( is_int( $id ) ) {
    112             global $wpdb;
    113             // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
    114             return $wpdb->get_row( $wpdb->prepare( "SELECT * FROM %i WHERE id = %s", $wpdb->prefix . 'cf7a_blacklist', $id ) );
    115         }
    116     }
    117 
    118     /**
    119      * It adds an IP address to the blacklist.
    120      *
    121      * @param string $ip The IP address to ban.
    122      * @param array  $reason The reason why the IP is being banned.
    123      * @param float  $spam_score This is the number of points that will be added to the IP's spam score.
    124      *
    125      * @return bool true if the given id was banned
    126      */
    127     public function cf7a_ban_by_ip( string $ip, array $reason = array(), $spam_score = 1 ): bool {
    128         $ip = filter_var( $ip, FILTER_VALIDATE_IP );
    129 
    130         if ( $ip ) {
    131             global $wpdb;
    132 
    133             $ip_row = self::cf7a_blacklist_get_ip( $ip );
    134 
    135             if ( $ip_row ) {
    136                 // if the ip is in the blacklist, update the status
    137                 $status = isset( $ip_row->status ) ? floatval( $ip_row->status ) + floatval( $spam_score ) : 1;
    138 
    139             } else {
    140                 // if the ip is not in the blacklist, add it and initialize the status
    141                 $status = floatval( $spam_score );
    142             }
    143 
    144             // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
    145             $r = $wpdb->replace(
    146                 $wpdb->prefix . 'cf7a_blacklist',
    147                 array(
    148                     'ip'     => $ip,
    149                     'status' => $status,
    150                     'meta'   => serialize(
    151                         array(
    152                             'reason' => $reason,
    153                             'meta'   => null,
    154                         )
    155                     ),
    156                 ),
    157                 array( '%s', '%d', '%s' )
    158             );
    159 
    160             if ( $r > - 1 ) {
    161                 return true;
    162             }
    163         }
    164 
    165         return false;
    166     }
    167 
    168     /**
    169      * It deletes the IP address from the database
    170      *
    171      * @param string $ip The IP address to unban.
    172      *
    173      * @return int|false The number of rows deleted.
    174      */
    175     public function cf7a_unban_by_ip( $ip ) {
    176         $ip = filter_var( $ip, FILTER_VALIDATE_IP );
    177 
    178         if ( $ip ) {
    179             global $wpdb;
    180 
    181             // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
    182             $r = $wpdb->delete(
    183                 $wpdb->prefix . 'cf7a_blacklist',
    184                 array(
    185                     'ip' => $ip,
    186                 ),
    187                 array(
    188                     '%s',
    189                 )
    190             );
    191 
    192             return ! is_wp_error( $r ) ? $r : $wpdb->last_error;
    193         }
    194 
    195         return false;
    196     }
    197 
    198     /**
    199      * It deletes a row from the database table
    200      *
    201      * @param int $id The ID of the entry to delete.
    202      *
    203      * @return int The number of rows affected by the query.
    204      */
    205     public function cf7a_unban_by_id( $id ) {
    206         $id = intval( $id );
    207 
    208         global $wpdb;
    209 
    210         // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
    211         $r = $wpdb->delete(
    212             $wpdb->prefix . 'cf7a_blacklist',
    213             array(
    214                 'id' => $id,
    215             ),
    216             array(
    217                 '%d',
    218             )
    219         );
    220 
    221         return ! is_wp_error( $r ) ? $r : $wpdb->last_error;
    222     }
    223 
    224     /**
    225      * It updates the status of all the users in the blacklist table by subtracting 1 from the status column.
    226      *
    227      * Then it deletes all the users whose status is 0.
    228      * The status column is the number of days the user is banned for.
    229      * So if the user is banned for 3 days, the status column will be 3. After the first day, the status column will be 2. After the second day, the status column will be 1. After the third day, the status column will be 0.
    230      * When the status column is 0, the user is unbanned.
    231      *
    232      * The function returns true if the user is unbanned.
    233      *
    234      * @return true.
    235      */
    236     public function cf7a_cron_unban() {
    237         global $wpdb;
    238 
    239         /* We remove 1 from the status column */
    240         $status_decrement = 1;
    241 
    242         /* Below 0 is not anymore a valid status for a blacklist entry, so we can remove it */
    243         $lower_bound = 0;
    244 
    245         $blacklist_table = $wpdb->prefix . 'cf7a_blacklist';
    246 
    247         /* removes a status count at each balcklisted ip */
    248         // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
    249         $updated = $wpdb->query( $wpdb->prepare( "UPDATE %i SET `status` = `status` - %d", $blacklist_table, $status_decrement ) );
    250         cf7a_log( "Status updated for blacklisted (score -1) - $updated users", 1 );
    251 
    252         /* when the line has 0 in status, we can remove it from the blacklist */
    253         // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
    254         $updated_deletion = $wpdb->delete(
    255             $blacklist_table,
    256             array( 'status' => $lower_bound ),
    257             array( '%d' )
    258         );
    259         cf7a_log( "Removed {$updated_deletion} users from blacklist", 1 );
    260 
    261         return true;
    262108    }
    263109
     
    368214    }
    369215
     216    // ------------------------
     217    // MAIN FILTER ORCHESTRATOR
     218    // ------------------------
    370219
    371220    /**
    372221     * CF7_AntiSpam_Filters The antispam filter
     222     *
     223     * @param boolean $spam - spam or not.
     224     *
     225     * @return boolean
     226     */
     227    /**
     228     * CF7_AntiSpam_Filters The antispam filter
     229     * Refactored to use a filter chain pipeline.
    373230     *
    374231     * @param boolean $spam - spam or not.
     
    390247        $contact_form = $submission->get_contact_form();
    391248
    392         /* get the tag used in the form */
     249        /* Get plugin options */
     250        $options = get_option( 'cf7a_options', array() );
     251
     252        /* Check the period of grace and, if it is expired, reset the error count */
     253        if ( !empty( $options['last_update_data']['errors'] ) ) {
     254            $period_of_grace = apply_filters('cf7a_period_of_grace', WEEK_IN_SECONDS);
     255            if ( time() - $options['last_update_data']['time'] > $period_of_grace ) {
     256                $options['last_update_data']['errors'] = array();
     257            }
     258            // then save the updated options to the database
     259            update_option( 'cf7a_options', $options );
     260        }
     261
     262        /* Get basic submission details */
    393263        $mail_tags = $contact_form->scan_form_tags();
    394 
    395         /* get the sender email field using the flamingo defined */
    396264        $email_tag = sanitize_title( cf7a_get_mail_meta( $contact_form->pref( 'flamingo_email' ) ) );
    397265        $emails    = isset( $posted_data[ $email_tag ] ) ? array( $posted_data[ $email_tag ] ) : $this->scan_email_tags( $mail_tags );
    398266
    399         /* Getting the message field(s) from the form. */
     267        /* Getting the message field(s) */
    400268        $message_tag  = sanitize_text_field( $contact_form->pref( 'flamingo_message' ) );
    401269        $message_meta = cf7a_get_mail_meta( $message_tag );
     
    404272        /**
    405273         * Let developers hack the message
    406          *
    407          * @param string $message the mail message content
    408          * @param array $posted_data the email metadata
    409274         */
    410275        $message = apply_filters( 'cf7a_message_before_processing', $message, $posted_data );
    411276
    412         /* this plugin options */
    413         $options = get_option( 'cf7a_options', array() );
    414         $prefix  = sanitize_html_class( $options['cf7a_customizations_prefix'] );
    415 
    416         /**
    417          * The data of the user who sent this email
    418          */
    419 
    420         /* IP */
    421         $real_remote_ip = isset( $_POST[ $prefix . 'address' ] ) ? cf7a_decrypt( sanitize_text_field( wp_unslash( $_POST[ $prefix . 'address' ] ) ), $options['cf7a_cipher'] ) : false;
     277        /* Prepare IP and basic user data */
     278        $prefix  = sanitize_text_field( $options['cf7a_customizations_prefix'] );
     279        // The right way to do this is BEFORE decrypting and THEN sanitize, because sanitized data are stripped of any special characters
     280        // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
     281        $real_remote_ip = isset( $_POST[ $prefix . 'address' ] ) ? sanitize_text_field( wp_unslash( cf7a_decrypt( $_POST[ $prefix . 'address' ], $options['cf7a_cipher'] ) ) ) : false;
    422282        $remote_ip      = $real_remote_ip ? filter_var( $real_remote_ip, FILTER_VALIDATE_IP ) : false;
    423283        $cf7_remote_ip  = filter_var( $submission->get_meta( 'remote_ip' ), FILTER_VALIDATE_IP );
    424 
    425         /* CF7A version */
    426         $cf7a_version = isset( $_POST[ $prefix . 'version' ] ) ? cf7a_decrypt( sanitize_text_field( wp_unslash( $_POST[ $prefix . 'version' ] ) ), $options['cf7a_cipher'] ) : false;
    427 
    428         /* client referer */
    429         $cf7a_referer  = isset( $_POST[ $prefix . 'referer' ] ) ? cf7a_decrypt( sanitize_text_field( wp_unslash( $_POST[ $prefix . 'referer' ] ) ), $options['cf7a_cipher'] ) : false;
    430         $cf7a_protocol = isset( $_POST[ $prefix . 'protocol' ] ) ? cf7a_decrypt( sanitize_text_field( wp_unslash( $_POST[ $prefix . 'protocol' ] ) ), $options['cf7a_cipher'] ) : false;
    431 
    432         /* CF7 user agent */
    433         $user_agent = sanitize_text_field( $submission->get_meta( 'user_agent' ) );
    434 
    435         /* Timestamp checks */
    436         $timestamp = isset( $_POST[ $prefix . '_timestamp' ] ) ? intval( cf7a_decrypt( sanitize_text_field( wp_unslash( $_POST[ $prefix . '_timestamp' ] ) ), $options['cf7a_cipher'] ) ) : 0;
    437 
    438         /* Can be cached so isn't safe to use -> $submission->get_meta( 'timestamp' ); */
    439         $time_now         = time();
    440         $time_elapsed_min = intval( $options['check_time_min'] );
    441         $time_elapsed_max = intval( $options['check_time_max'] );
    442 
    443         /* Checks sender has a blacklisted ip address */
    444         $bad_ip_list = isset( $options['bad_ip_list'] ) ? $options['bad_ip_list'] : array();
    445 
    446         /* Checks sender has a blacklisted ip address */
    447         $ip_whitelist = isset( $options['ip_whitelist'] ) ? $options['ip_whitelist'] : array();
    448 
    449         /* Checks if the mail contains bad words */
    450         $bad_words = isset( $options['bad_words_list'] ) ? $options['bad_words_list'] : array();
    451 
    452         /* Checks if the mail contains bad user agent */
    453         $bad_user_agent_list = isset( $options['bad_user_agent_list'] ) ? $options['bad_user_agent_list'] : array();
    454 
    455         /* Check sender mail has prohibited string */
    456         $bad_email_strings = isset( $options['bad_email_strings_list'] ) ? $options['bad_email_strings_list'] : array();
     284        $user_agent     = sanitize_text_field( $submission->get_meta( 'user_agent' ) );
     285
     286        // -------------------------------------------------------------
     287        // BUILD THE DATA OBJECT (Context)
     288        // -------------------------------------------------------------
     289        $spam_data = array(
     290            'submission'    => $submission,
     291            'options'       => $options,
     292            'posted_data'   => $posted_data,
     293            'remote_ip'     => $remote_ip,
     294            'cf7_remote_ip' => $cf7_remote_ip,
     295            'emails'        => $emails,
     296            'message'       => $message,
     297            'mail_tags'     => $mail_tags,
     298            'user_agent'    => $user_agent,
     299            // State trackers
     300            'spam_score'    => 0,
     301            'is_spam'       => $spam,
     302            'reasons'       => array(),
     303            'is_whitelisted'=> false, // Flag to stop processing
     304        );
    457305
    458306        /**
    459          * Scoring
     307         * RUN THE FILTER CHAIN
     308         * This triggers all the checks registered in __construct
    460309         */
    461 
    462         /* b8 threshold */
    463         $b8_threshold = floatval( $options['b8_threshold'] );
    464         $b8_threshold = $b8_threshold > 0 && $b8_threshold < 1 ? $b8_threshold : 1;
    465 
    466         /* cf7-antispam version check, fingerprinting, fingerprints extras (for each failed test) */
    467         $score_fingerprinting = floatval( $options['score']['_fingerprinting'] );
    468 
    469         /* time lower or higher than the limits entered */
    470         $score_time = floatval( $options['score']['_time'] );
    471 
    472         /* blacklisted ip (with bad ip list), bad string in email or in message fields, bad user agent */
    473         $score_bad_string = floatval( $options['score']['_bad_string'] );
    474 
    475         /* dsnbl score (for each server found) */
    476         $score_dnsbl = floatval( $options['score']['_dnsbl'] );
    477 
    478         /* honeypot */
    479         $score_honeypot = floatval( $options['score']['_honeypot'] );
    480 
    481         /* no http refer, language check fail */
    482         $score_warn = floatval( $options['score']['_warn'] );
    483 
    484         /* already blacklisted, language check fail, ip or user agent or timestamp fields missing */
    485         $score_detection = floatval( $options['score']['_detection'] );
    486 
    487         /* initialize the spam data collection */
    488         $reason     = array();
    489         $spam_score = 0;
     310        $spam_data = apply_filters( 'cf7a_spam_check_chain', $spam_data );
    490311
    491312        /**
    492          * Checks for IP and return immediately if it is whitelisted
     313         * BAYESIAN FILTER (B8)
     314         * Placed explicitly here to ensure it runs at the end of the function,
     315         * regardless of previous spam detection (unless whitelisted).
    493316         */
    494         if ( ! empty( $ip_whitelist ) ) {
    495             foreach ( $ip_whitelist as $good_ip ) {
    496                 $good_ip = filter_var( $good_ip, FILTER_VALIDATE_IP );
    497 
    498                 if ( false !== stripos( (string) $remote_ip, (string) $good_ip ) ) {
    499                     return false;
    500                 }
    501             }
    502         }
     317        $spam_data = apply_filters( 'cf7a_check_b8', $spam_data );
     318
     319        // Extract results
     320        $spam_score = $spam_data['spam_score'];
     321        $reason     = $spam_data['reasons'];
     322        $spam       = $spam_data['is_spam'];
     323        $remote_ip  = $spam_data['remote_ip'] ? $spam_data['remote_ip'] : $spam_data['cf7_remote_ip'];
    503324
    504325        /**
    505          * Checking if the IP address is empty. If it is empty, it will add a score of 10 to the spam score and add a reason to the reason array.
    506          */
    507         if ( ! $remote_ip ) {
    508             $remote_ip = $cf7_remote_ip ? $cf7_remote_ip : null;
    509 
    510             ++$spam_score;
    511             $spam            = true;
    512             $reason['no_ip'] = 'Address field empty';
    513 
    514             cf7a_log( "ip address field of $remote_ip is empty, this means it has been modified, removed or hacked! (i'm getting the real ip from http header)", 1 );
    515         }
    516 
    517         /**
    518          * Checks if the IP is filtered
    519          */
    520         if ( intval( $options['check_bad_ip'] ) === 1 ) {
    521             foreach ( $bad_ip_list as $bad_ip ) {
    522                 $bad_ip = filter_var( $bad_ip, FILTER_VALIDATE_IP );
    523 
    524                 if ( false !== stripos( (string) $remote_ip, (string) $bad_ip ) ) {
    525                     ++$spam_score;
    526                     $spam               = true;
    527                     $reason['bad_ip'][] = $bad_ip;
    528                 }
    529             }
    530 
    531             if ( ! empty( $reason['bad_ip'] ) ) {
    532                 $reason['bad_ip'] = implode( ', ', $reason['bad_ip'] );
    533 
    534                 cf7a_log( "The ip address $remote_ip is listed into bad ip list (contains {$reason['bad_ip']})", 1 );
    535             }
    536         }
    537 
    538         /**
    539          * Checking if the IP address was already blacklisted - no mercy 😎
    540          */
    541         if ( $remote_ip && $options['max_attempts'] ) {
    542             $ip_data        = self::cf7a_blacklist_get_ip( $remote_ip );
    543             $ip_data_status = isset( $ip_data->status ) ? intval( $ip_data->status ) : 0;
    544             $max_attempts   = intval( $options['max_attempts'] );
    545 
    546             /* if the current ip has tried more times than allowed */
    547             if ( $ip_data_status >= $max_attempts ) {
    548                 ++$spam_score;
    549                 $spam                        = true;
    550                 $reason['blacklisted score'] = $ip_data_status + $spam_score;
    551 
    552                 cf7a_log( "The $remote_ip is already blacklisted, status $ip_data_status", 1 );
    553             } elseif ( CF7ANTISPAM_DEBUG && $ip_data_status > 0 ) {
    554 
    555                 /* Wanr only if the number of attempts is higher than 0 but lower than the max attempts */
    556                 cf7a_log(
    557                     sprintf(
    558                         "The $remote_ip is already blacklisted (score $ip_data_status) but still has %d attempts left",
    559                         $max_attempts - $ip_data_status
    560                     ),
    561                     1
    562                 );
    563             }
    564         }
    565 
    566         /**
    567          * Checking if the honeyForm field is empty. If it is not empty, then it is a bot.
    568          */
    569         if ( intval( $options['check_honeyform'] ) === 1 ) {
    570             $form_class = sanitize_html_class( $options['cf7a_customizations_class'] );
    571 
    572             /* get the "marker" field */
    573             if ( isset( $_POST[ '_wpcf7_' . $form_class ] ) ) {
    574                 ++$spam_score;
    575                 $spam                = true;
    576                 $reason['honeyform'] = 'true';
    577             }
    578         }
    579 
    580         /**
    581          * If the mail was marked as spam no more checks are needed.
    582          * This will save server computing power, this ip has already been banned so there's no reason for further processing
    583          */
    584         if ( $spam_score < 1 && ! $spam ) {
    585             /**
    586              * Check the client http refer
    587              * it is much more likely that it is a bot that lands on the page without a referrer than a human that pastes in the address bar the url of the contact form.
    588              */
    589             if ( intval( $options['check_refer'] ) === 1 ) {
    590                 if ( ! $cf7a_referer ) {
    591                     $spam_score           += $score_warn;
    592                     $reason['no_referrer'] = 'client has referrer address';
    593 
    594                     cf7a_log( "the $remote_ip has reached the contact form page without any referrer", 1 );
    595                 }
    596             }
    597 
    598             if ( $cf7a_protocol ) {
    599                 if ( in_array( $cf7a_protocol, array( 'HTTP/1.0', 'HTTP/1.1', 'HTTP/1.2' ) ) ) {
    600                     $spam_score           += $score_warn;
    601                     $reason['no_protocol'] = 'client has a bot-like connection protocol';
    602 
    603                     cf7a_log( "the $remote_ip has a bot-like connection protocol (HTTP/1.X)", 1 );
    604                 }
    605             }
    606 
    607             /**
    608              * Check the CF7 AntiSpam version field
    609              */
    610             if ( ! $cf7a_version ) {
    611                 $spam_score             += $score_fingerprinting;
    612                 $reason['data_mismatch'] = "Version mismatch '$cf7a_version' != '" . CF7ANTISPAM_VERSION . "'";
    613 
    614                 cf7a_log( "Incorrect data submitted by $remote_ip in the hidden field _version, may have been modified, removed or hacked", 1 );
    615             }
    616 
    617             /**
    618              * If enabled fingerprints bots
    619              */
    620             if ( intval( $options['check_bot_fingerprint'] ) === 1 ) {
    621                 $bot_fingerprint = array(
    622                     'timezone'        => ! empty( $_POST[ $prefix . 'timezone' ] ) ? sanitize_text_field( wp_unslash( $_POST[ $prefix . 'timezone' ] ) ) : null,
    623                     'platform'        => ! empty( $_POST[ $prefix . 'platform' ] ) ? sanitize_text_field( wp_unslash( $_POST[ $prefix . 'platform' ] ) ) : null,
    624                     'screens'         => ! empty( $_POST[ $prefix . 'screens' ] ) ? sanitize_text_field( wp_unslash( $_POST[ $prefix . 'screens' ] ) ) : null,
    625                     'memory'          => ! empty( $_POST[ $prefix . 'memory' ] ) ? intval( $_POST[ $prefix . 'memory' ] ) : null,
    626                     'user_agent'      => ! empty( $_POST[ $prefix . 'user_agent' ] ) ? sanitize_text_field( wp_unslash( $_POST[ $prefix . 'user_agent' ] ) ) : null,
    627                     /* deprecated 👇 TODO: replace with a user agent parser */
    628                     'app_version'     => ! empty( $_POST[ $prefix . 'app_version' ] ) ? sanitize_text_field( wp_unslash( $_POST[ $prefix . 'app_version' ] ) ) : null,
    629                     'webdriver'       => ! empty( $_POST[ $prefix . 'webdriver' ] ) ? sanitize_text_field( wp_unslash( $_POST[ $prefix . 'webdriver' ] ) ) : null,
    630                     'session_storage' => ! empty( $_POST[ $prefix . 'session_storage' ] ) ? intval( $_POST[ $prefix . 'session_storage' ] ) : null,
    631                     'bot_fingerprint' => ! empty( $_POST[ $prefix . 'bot_fingerprint' ] ) ? sanitize_text_field( wp_unslash( $_POST[ $prefix . 'bot_fingerprint' ] ) ) : null,
    632                     'touch'           => ! empty( $_POST[ $prefix . 'touch' ] ),
    633                 );
    634 
    635                 $fails = array();
    636                 if ( ! $bot_fingerprint['timezone'] ) {
    637                     $fails[] = 'timezone';
    638                 }
    639                 if ( ! $bot_fingerprint['platform'] ) {
    640                     $fails[] = 'platform';
    641                 }
    642                 if ( ! $bot_fingerprint['screens'] ) {
    643                     $fails[] = 'screens';
    644                 }
    645                 if ( ! $bot_fingerprint['user_agent'] ) {
    646                     $fails[] = 'user_agent';
    647                 }
    648                 if ( ! $bot_fingerprint['app_version'] ) {
    649                     $fails[] = 'app_version';
    650                 }
    651                 if ( ! $bot_fingerprint['webdriver'] ) {
    652                     $fails[] = 'webdriver';
    653                 }
    654                 if ( ! $bot_fingerprint['session_storage'] ) {
    655                     $fails[] = 'session_storage';
    656                 }
    657                 if ( 5 !== strlen( $bot_fingerprint['bot_fingerprint'] ) ) {
    658                     $fails[] = 'bot_fingerprint';
    659                 }
    660 
    661                 /* navigator deviceMemory isn't available with Ios, FireFox and ie - https://developer.mozilla.org/en-US/docs/Web/API/Navigator/deviceMemory */
    662                 if ( isset( $_POST[ $prefix . 'isIos' ] ) || isset( $_POST[ $prefix . 'isFFox' ] ) || isset( $_POST[ $prefix . 'isIE' ] ) ) {
    663                     if ( $bot_fingerprint['memory'] ) {
    664                         $fails[] = 'memory_supported';
    665                     }
    666                 } elseif ( ! $bot_fingerprint['memory'] ) {
    667                     $fails[] = 'memory';
    668                 }
    669 
    670                 if ( isset( $_POST[ $prefix . 'isIos' ] ) || isset( $_POST[ $prefix . 'isAndroid' ] ) ) {
    671                     if ( ! $bot_fingerprint['touch'] ) {
    672                         $fails[] = 'touch';
    673                     }
    674                 }
    675 
    676                 /* increment the spam score if needed, then log the result */
    677                 if ( ! empty( $fails ) ) {
    678                     $spam_score               += count( $fails ) * $score_fingerprinting;
    679                     $reason['bot_fingerprint'] = implode( ', ', $fails );
    680 
    681                     cf7a_log( "The $remote_ip ip hasn't passed " . count( $fails ) . ' / ' . count( $bot_fingerprint ) . " of the bot fingerprint test ({$reason['bot_fingerprint']})", 1 );
    682                     cf7a_log( $bot_fingerprint, 2 );
    683                 }
    684             }
    685 
    686             /**
    687              * Bot fingerprints extras
    688              */
    689             if ( intval( $options['check_bot_fingerprint_extras'] ) === 1 ) {
    690                 $bot_fingerprint_extras = array(
    691                     'activity'               => ! empty( $_POST[ $prefix . 'activity' ] ) ? intval( $_POST[ $prefix . 'activity' ] ) : 0,
    692                     'mouseclick_activity'    => ! empty( $_POST[ $prefix . 'mouseclick_activity' ] ) && sanitize_text_field( wp_unslash( $_POST[ $prefix . 'mouseclick_activity' ] ) ) === 'passed',
    693                     'mousemove_activity'     => ! empty( $_POST[ $prefix . 'mousemove_activity' ] ) && sanitize_text_field( wp_unslash( $_POST[ $prefix . 'mousemove_activity' ] ) ) === 'passed',
    694                     'webgl'                  => ! empty( $_POST[ $prefix . 'webgl' ] ) && sanitize_text_field( wp_unslash( $_POST[ $prefix . 'webgl' ] ) ) === 'passed',
    695                     'webgl_render'           => ! empty( $_POST[ $prefix . 'webgl_render' ] ) && sanitize_text_field( wp_unslash( $_POST[ $prefix . 'webgl_render' ] ) ) === 'passed',
    696                     'bot_fingerprint_extras' => empty( $_POST[ $prefix . 'bot_fingerprint_extras' ] ),
    697                     // has to be empty!
    698                 );
    699 
    700                 $fails = array();
    701                 if ( $bot_fingerprint_extras['activity'] < 3 ) {
    702                     $fails[] = "activity {$bot_fingerprint_extras["activity"]}";
    703                 }
    704                 if ( empty( $bot_fingerprint_extras['mouseclick_activity'] ) ) {
    705                     $fails[] = 'mouseclick_activity';
    706                 }
    707                 if ( empty( $bot_fingerprint_extras['mousemove_activity'] ) ) {
    708                     $fails[] = 'mousemove_activity';
    709                 }
    710                 if ( empty( $bot_fingerprint_extras['webgl'] ) ) {
    711                     $fails[] = 'webgl';
    712                 }
    713                 if ( empty( $bot_fingerprint_extras['webgl_render'] ) ) {
    714                     $fails[] = 'webgl_render';
    715                 }
    716                 if ( empty( $bot_fingerprint_extras['bot_fingerprint_extras'] ) ) {
    717                     $fails[] = 'bot_fingerprint_extras';
    718                 }
    719 
    720                 if ( ! empty( $fails ) ) {
    721                     $spam_score                      += count( $fails ) * $score_fingerprinting;
    722                     $reason['bot_fingerprint_extras'] = implode( ', ', $fails );
    723 
    724                     cf7a_log( "The $remote_ip ip hasn't passed " . count( $fails ) . ' / ' . count( $bot_fingerprint_extras ) . " of the bot fingerprint extra test ({$reason['bot_fingerprint_extras']})", 1 );
    725                     cf7a_log( $bot_fingerprint_extras, 2 );
    726                 }
    727             }
    728 
    729             /**
    730              * Check the browser / headers language
    731              */
    732             if ( intval( $options['check_language'] ) === 1 ) {
    733                 /* prefix '_cf7a_' */
    734                 $languages                     = array();
    735                 $languages['browser_language'] = ! empty( $_POST[ $prefix . 'browser_language' ] ) ? sanitize_text_field( wp_unslash( $_POST[ $prefix . 'browser_language' ] ) ) : null;
    736                 $languages['accept_language']  = isset( $_POST[ $prefix . '_language' ] ) ? cf7a_decrypt( sanitize_text_field( wp_unslash( $_POST[ $prefix . '_language' ] ) ), $options['cf7a_cipher'] ) : null;
    737 
    738                 /**
    739                  * Language checks
    740                  */
    741                 if ( empty( $languages['browser_language'] ) ) {
    742                     $spam_score                += $score_detection;
    743                     $reason['browser_language'] = 'missing browser language';
    744                 } else {
    745                     $languages_locales    = cf7a_get_browser_languages_locales_array( $languages['browser_language'] );
    746                     $languages['browser'] = $languages_locales['languages'];
    747                 }
    748 
    749                 if ( empty( $languages['accept_language'] ) ) {
    750                     $spam_score              += $score_detection;
    751                     $reason['language_field'] = 'missing language field';
    752                 } else {
    753                     $languages['accept'] = cf7a_get_accept_language_array( $languages['accept_language'] );
    754                 }
    755 
    756                 if ( ! empty( $languages['accept'] ) && ! empty( $languages['browser'] ) ) {
    757                     if ( ! array_intersect( $languages['browser'], $languages['accept'] ) ) {
    758                         $spam_score += $score_detection;
    759 
    760                         /* checks if http accept language is the same of javascript navigator.languages */
    761                         $reason['language_incoherence'] = 'languages detected not coherent (' . implode( '-', $languages['browser'] ) . ' vs ' . implode( '-', $languages['accept'] ) . ')';
    762                     }
    763 
    764                     /* check if the language is allowed and if is disallowed */
    765                     $client_languages = array_unique( array_merge( $languages['browser'], $languages['accept'] ) );
    766 
    767                     /* extract options and assign them to local variables */
    768                     $languages_allowed    = isset( $options['languages_locales']['allowed'] ) ? $this->cf7a_get_languages_or_locales( $options['languages_locales']['allowed'], 'languages' ) : array();
    769                     $languages_disallowed = isset( $options['languages_locales']['disallowed'] ) ? $this->cf7a_get_languages_or_locales( $options['languages_locales']['disallowed'], 'languages' ) : array();
    770 
    771                     $language_disallowed = $this->cf7a_check_languages_locales_allowed( $client_languages, $languages_disallowed, $languages_allowed );
    772 
    773                     if ( false === $language_disallowed ) {
    774                         $spam_score                += $score_detection;
    775                         $reason['browser_language'] = implode( ', ', $client_languages );
    776                     }
    777                 }
    778             }
    779 
    780             /**
    781              * Geo-ip verification
    782              */
    783             if ( intval( $options['check_geo_location'] ) === 1 ) {
    784                 $geoip = new CF7_Antispam_Geoip();
    785 
    786                 $locales_allowed    = $this->cf7a_get_languages_or_locales( $options['languages_locales']['allowed'], 'locales' );
    787                 $locales_disallowed = $this->cf7a_get_languages_or_locales( $options['languages_locales']['disallowed'], 'locales' );
    788 
    789                 if ( ! empty( $geoip ) ) {
    790                     try {
    791                         /* check if the ip is available into geo-ip database, then create an array with county and continent */
    792                         $geoip_data      = $geoip->check_ip( $remote_ip );
    793                         $geoip_continent = isset( $geoip_data['continent'] ) ? ( $geoip_data['continent'] ) : false;
    794                         $geoip_country   = isset( $geoip_data['country'] ) ? ( $geoip_data['country'] ) : false;
    795                         $geo_data        = array_filter( array( $geoip_continent, $geoip_country ) );
    796 
    797                         if ( ! empty( $geo_data ) ) {
    798                             /*
    799                             then check if the detected country is among the allowed and disallowed languages */
    800                             // Check if the country is allowed by country by splitting browser headers 2nd arg since ISO is coherent
    801                             if ( false === $this->cf7a_check_languages_locales_allowed( $geo_data, $locales_disallowed, $locales_allowed ) ) {
    802                                 $reason['geo_ip'] = $geoip_continent . '-' . $geoip_country;
    803                                 $spam_score      += $score_warn;
    804 
    805                                 cf7a_log( "The $remote_ip is not allowed by geoip" . $reason['geo_ip'], 1 );
    806                             }
    807                         } else {
    808                             $reason['no_geo_ip'] = 'unknown ip';
    809                         }
    810                     } catch ( Exception $e ) {
    811                         cf7a_log( "unable to check geoip for $remote_ip - " . $e->getMessage(), 1 );
    812                     }
    813                 }
    814             }
    815 
    816             /**
    817              * Check if the time to submit the email
    818              */
    819             if ( intval( $options['check_time'] ) === 1 ) {
    820                 if ( ! $timestamp ) {
    821                     $spam_score         += $score_detection;
    822                     $reason['timestamp'] = 'undefined';
    823 
    824                     cf7a_log( "The $remote_ip ip _timestamp field is missing, probable form hacking attempt from $remote_ip", 1 );
    825                 } else {
    826                     $time_elapsed = $time_now - $timestamp;
    827 
    828                     /**
    829                      * Check if the time to submit the email il lower than expected
    830                      */
    831                     if ( 0 !== $time_elapsed_min && $time_elapsed < $time_elapsed_min ) {
    832                         $spam_score                += $score_time;
    833                         $reason['min_time_elapsed'] = $time_elapsed;
    834 
    835                         cf7a_log( "The $remote_ip ip took too little time to fill in the form - elapsed $time_elapsed seconds < $time_elapsed_min seconds expected", 1 );
    836                     }
    837 
    838                     /**
    839                      * Check if the time to submit the email il higher than expected
    840                      */
    841                     if ( 0 !== $time_elapsed_max && $time_elapsed > $time_elapsed_max ) {
    842                         $spam_score                += $score_time;
    843                         $reason['max_time_elapsed'] = $time_elapsed;
    844 
    845                         cf7a_log( "The $remote_ip ip took too much time to fill in the form - elapsed $time_elapsed seconds > $time_elapsed_max seconds expected", 1 );
    846                     }
    847                 }
    848             }
    849 
    850             /**
    851              * Check if e-mails contain prohibited words, for instance, check if the sender is the same as the website domain,
    852              * because it is an attempt to circumvent the controls, because the e-mail client cannot blacklist the e-mail itself,
    853              * we must prevent this.
    854              */
    855             if ( intval( $options['check_bad_email_strings'] ) === 1 && ! empty( $emails ) ) {
    856                 foreach ( $emails as $email ) {
    857                     foreach ( $bad_email_strings as $bad_email_string ) {
    858                         if ( false !== stripos( strtolower( $email ), strtolower( $bad_email_string ) ) ) {
    859                             $spam_score                   += $score_bad_string;
    860                             $reason['email_blacklisted'][] = $bad_email_string;
    861                         }
    862                     }
    863                 }
    864 
    865                 if ( isset( $reason['email_blacklisted'] ) ) {
    866                     $reason['email_blacklisted'] = implode( ',', $reason['email_blacklisted'] );
    867 
    868                     cf7a_log( "The ip address $remote_ip sent a mail using the email address {$reason['email_blacklisted']} that contains the bad string {$reason['email_blacklisted']}", 1 );
    869                 }
    870             }
    871 
    872             /**
    873              * Checks if the emails user agent is denied
    874              */
    875             if ( intval( $options['check_bad_user_agent'] ) === 1 ) {
    876                 if ( ! $user_agent ) {
    877                     $spam_score          += $score_detection;
    878                     $reason['user_agent'] = 'empty';
    879 
    880                     cf7a_log( "The $remote_ip ip user agent is empty, look like a spambot", 1 );
    881                 } else {
    882                     foreach ( $bad_user_agent_list as $bad_user_agent ) {
    883                         if ( false !== stripos( strtolower( $user_agent ), strtolower( $bad_user_agent ) ) ) {
    884                             $spam_score            += $score_bad_string;
    885                             $reason['user_agent'][] = $bad_user_agent;
    886                         }
    887                     }
    888 
    889                     if ( isset( $reason['user_agent'] ) && is_array( $reason['user_agent'] ) ) {
    890                         $reason['user_agent'] = implode( ', ', $reason['user_agent'] );
    891                         cf7a_log( "The $remote_ip ip user agent was listed into bad user agent list - $user_agent contains " . $reason['user_agent'], 1 );
    892                     }
    893                 }
    894             }
    895 
    896             /**
    897              * Search for prohibited words
    898              */
    899             if ( 1 === intval( $options['check_bad_words'] ) && '' !== $message ) {
    900 
    901                 /* to search strings into message without space and case-insensitive */
    902                 $message_compressed = $this->cf7a_simplify_text( $message );
    903 
    904                 foreach ( $bad_words as $bad_word ) {
    905                     if ( false !== stripos( $message_compressed, $this->cf7a_simplify_text( $bad_word ) ) ) {
    906                         $spam_score          += $score_bad_string;
    907                         $reason['bad_word'][] = $bad_word;
    908                     }
    909                 }
    910 
    911                 if ( ! empty( $reason['bad_word'] ) ) {
    912                     $reason['bad_word'] = implode( ',', $reason['bad_word'] );
    913 
    914                     cf7a_log( "$remote_ip has bad word in message " . $reason['bad_word'], 1 );
    915                 }
    916             }
    917 
    918             /**
    919              * Check the remote ip if is listed into Domain Name System Blacklists
    920              * DNS blacklist are spam blocking DNS like lists that allow to block messages from specific systems that have a history of sending spam
    921              * inspiration taken from https://gist.github.com/tbreuss/74da96ff5f976ce770e6628badbd7dfc
    922              */
    923             if ( intval( $options['check_dnsbl'] ) === 1 && $remote_ip ) {
    924                 $reverse_ip = '';
    925 
    926                 if ( filter_var( $remote_ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 ) ) {
    927                     $reverse_ip = $this->cf7a_reverse_ipv4( $remote_ip );
    928                 } elseif ( filter_var( $remote_ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6 ) ) {
    929                     $reverse_ip = $this->cf7a_reverse_ipv6( $remote_ip );
    930                 }
    931 
    932                 foreach ( $options['dnsbl_list'] as $dnsbl ) {
    933                     if ( $this->cf7a_check_dnsbl( $reverse_ip, $dnsbl ) ) {
    934                         $reason['dsnbl'][] = $dnsbl;
    935                         $spam_score       += $score_dnsbl;
    936                     }
    937                 }
    938 
    939                 if ( isset( $reason['dsnbl'] ) && is_array( $reason['dsnbl'] ) ) {
    940                     $dsnbl_count     = count( $reason['dsnbl'] );
    941                     $reason['dsnbl'] = implode( ', ', $reason['dsnbl'] );
    942 
    943                     cf7a_log( "$remote_ip has tried to send an email but is listed $dsnbl_count times in the Domain Name System Blacklists ({$reason['dsnbl']})", 1 );
    944                 }
    945             }
    946 
    947             /**
    948              * Checks Honeypots input if they are filled
    949              */
    950             if ( $options['check_honeypot'] ) {
    951 
    952                 /* collect the input "name" value of the type="text" tags of the submitted form */
    953                 foreach ( $mail_tags as $mail_tag ) {
    954                     if ( 'text' === $mail_tag['type'] || 'text*' === $mail_tag['type'] ) {
    955                         $mail_tag_text[] = $mail_tag['name'];
    956                     }
    957                 }
    958 
    959                 if ( ! empty( $mail_tag_text ) ) {
    960 
    961                     /* get the collection of the generated (fake) input name used as honeypots name value */
    962                     $input_names = cf7a_get_honeypot_input_names( $options['honeypot_input_names'] );
    963 
    964                     $mail_tag_count = count( $input_names );
    965 
    966                     for ( $i = 0; $i < $mail_tag_count; $i++ ) {
    967 
    968                         /* check if any posted input name value has a name from the honeypot names array, if yes the bot has fallen into the trap and filled the input */
    969                         $has_honeypot = ! empty( $_POST[ $input_names[ $i ] ] );
    970 
    971                         /* check only if it's set and if it is different from "" */
    972                         if ( $has_honeypot ) {
    973                             $spam_score          += $score_honeypot;
    974                             $reason['honeypot'][] = $input_names[ $i ];
    975                         }
    976                     }
    977 
    978                     if ( ! empty( $reason['honeypot'] ) ) {
    979                         $reason['honeypot'] = implode( ', ', $reason['honeypot'] );
    980 
    981                         cf7a_log( "The $remote_ip has filled the input honeypot(s) {$reason['honeypot']}", 1 );
    982                     }
    983                 }
    984             }
    985         }
    986 
    987         /**
    988          * Filter before Bayesian filter B8
     326         * Final filter before the ban
    989327         *
    990          * @param bool $spam true if the mail was detected as spam
    991          * @param array $message the mail message content
    992          * @param null|WPCF7_Submission $submission the mail message submission instance
    993          */
    994         $spam = apply_filters( 'cf7a_before_b8', $spam, $message, $submission );
    995 
    996         /**
    997          * B8 is a statistical "Bayesian" spam filter
    998          * https://nasauber.de/opensource/b8/
    999          */
    1000         $text = stripslashes( $message );
    1001         \assert( \is_string( $text ) );
    1002 
    1003         if ( $options['enable_b8'] && $message && ! isset( $reason['blacklisted'] ) ) {
    1004             $cf7a_b8 = new CF7_AntiSpam_B8();
    1005             $rating  = round( $cf7a_b8->cf7a_b8_classify( $text ), 2 );
    1006 
    1007             /* Checking the rating of the message, and if it is greater than the threshold */
    1008             if ( $rating >= $b8_threshold ) {
    1009                 $reason['b8'] = $rating;
    1010                 $spam_score  += $score_detection;
    1011 
    1012                 cf7a_log( "B8 rating $rating / 1", 1 );
    1013             }
    1014 
    1015             /* Checking if the spam score is greater than or equal to 1. If it is, it sets the spam variable to true. */
    1016             if ( $spam_score >= 1 ) {
    1017                 /* if B8 isn't enabled we only need to mark as spam and leave a log */
    1018                 cf7a_log( "$remote_ip will be rejected because suspected of spam! (score $spam_score / 1)", 1 );
    1019                 $cf7a_b8->cf7a_b8_learn_spam( $text );
    1020             } elseif ( $rating < $b8_threshold * 0.5 ) {
    1021                 /* the mail has been classified as ham and is below half the 'alert value', so we can let B8 learn what is considered (a probable) ham */
    1022                 cf7a_log( "B8 detect spamminess of $rating (below the half of the threshold of $b8_threshold) so the mail from $remote_ip will be marked as ham", 1 );
    1023                 $cf7a_b8->cf7a_b8_learn_ham( $text );
    1024             }
    1025         }
    1026 
    1027         /**
    1028          * Filter with the antispam results (before ban).
    1029          *
    1030          * @param boolean $spam true if the mail was detected as spam
    1031          * @param string $message the mail message content
    1032          * @param null|WPCF7_Submission $submission the mail message submission instance
     328         * @param bool $spam
     329         * @param string $message
     330         * @param WPCF7_Submission $submission
    1033331         */
    1034332        $spam = apply_filters( 'cf7a_additional_spam_filters', $spam, $message, $submission );
    1035333
    1036         /* if the spam score is lower than 1 the mail is ham so return the value as this is a filter */
    1037         if ( $spam_score < 1 ) {
    1038             return $spam;
    1039         }
    1040 
    1041         /* ...otherwise the mail is spam, taking the array $reason and compressing it into a string. */
     334        /* If the spam score is lower than 1 the mail is ham */
     335        if ( $spam_score < 1 && ! $spam ) {
     336            return $spam; // Usually false
     337        }
     338
     339        /* Prepare for ban/logging */
    1042340        $reasons_for_ban = cf7a_compress_array( $reason );
    1043341
    1044         /* If the auto-store ip is enabled (and NOT in extended debug mode) */
    1045         if ( $options['autostore_bad_ip'] ) {
    1046             if ( self::cf7a_ban_by_ip( $remote_ip, $reason, round( $spam_score ) ) ) {
    1047                 /* Log the antispam result in extended debug mode */
     342        /* If the auto-store ip is enabled */
     343        if ( isset($options['autostore_bad_ip']) && $options['autostore_bad_ip'] ) {
     344            $blacklist = new CF7_Antispam_Blacklist();
     345            if ( CF7_Antispam_Blacklist::cf7a_ban_by_ip( $remote_ip, $reason, round( $spam_score ) ) ) {
    1048346                cf7a_log( "Ban for $remote_ip - results - " . $reasons_for_ban, 2 );
    1049347            } else {
     
    1052350        }
    1053351
    1054         /* Store the ban reason into mail post metadata */
     352        /* Store the ban reason into mail post-metadata */
    1055353        $submission->add_spam_log(
    1056354            array(
     
    1060358        );
    1061359
    1062         /* case closed */
    1063 
    1064360        return true;
    1065361    }
     362
     363    // -------------------------
     364    // INDIVIDUAL FILTER METHODS
     365    // -------------------------
     366
     367    /**
     368     * Checks for IP whitelist.
     369     */
     370    public function filter_ip_whitelist( $data ) {
     371        $ip_whitelist = $data['options']['ip_whitelist'] ?? array();
     372
     373        if ( ! empty( $ip_whitelist ) && $data['remote_ip'] ) {
     374            foreach ( $ip_whitelist as $good_ip ) {
     375                $good_ip = filter_var( $good_ip, FILTER_VALIDATE_IP );
     376                if ( false !== stripos( (string) $data['remote_ip'], (string) $good_ip ) ) {
     377                    $data['is_whitelisted'] = true;
     378                    return $data;
     379                }
     380            }
     381        }
     382        return $data;
     383    }
     384
     385    /**
     386     * Checks if IP is empty.
     387     */
     388    public function filter_empty_ip( $data ) {
     389        if ( $data['is_whitelisted'] ) return $data;
     390
     391        if ( ! $data['remote_ip'] ) {
     392            // Fallback to CF7 IP if main is missing, but flag as spam
     393            $data['remote_ip'] = $data['cf7_remote_ip'] ? $data['cf7_remote_ip'] : null;
     394
     395            $data['spam_score']++;
     396            $data['is_spam'] = true;
     397            $data['reasons']['no_ip'] = 'Address field empty';
     398
     399            cf7a_log( "ip address field of {$data['remote_ip']} is empty, this means it has been modified, removed or hacked!", 1 );
     400        }
     401        return $data;
     402    }
     403
     404    /**
     405     * Checks against local bad IP list.
     406     */
     407    public function filter_bad_ip( $data ) {
     408        if ( $data['is_whitelisted'] ) return $data;
     409
     410        $options = $data['options'];
     411        $bad_ip_list = isset( $options['bad_ip_list'] ) ? $options['bad_ip_list'] : array();
     412
     413        if ( intval( $options['check_bad_ip'] ) === 1 && $data['remote_ip'] ) {
     414            foreach ( $bad_ip_list as $bad_ip ) {
     415                $bad_ip = filter_var( $bad_ip, FILTER_VALIDATE_IP );
     416                if ( false !== stripos( (string) $data['remote_ip'], (string) $bad_ip ) ) {
     417                    $data['spam_score']++;
     418                    $data['is_spam'] = true;
     419                    $data['reasons']['bad_ip'][] = $bad_ip;
     420                }
     421            }
     422
     423            if ( ! empty( $data['reasons']['bad_ip'] ) && is_array($data['reasons']['bad_ip']) ) {
     424                $ip_string = implode( ', ', $data['reasons']['bad_ip'] );
     425                $data['reasons']['bad_ip'] = $ip_string; // Flatten for log
     426                cf7a_log( "The ip address {$data['remote_ip']} is listed into bad ip list (contains $ip_string)", 1 );
     427            }
     428        }
     429        return $data;
     430    }
     431
     432    /**
     433     * Checks if IP is already in the database blacklist history.
     434     */
     435    public function filter_ip_blacklist_history( $data ) {
     436        if ( $data['is_whitelisted'] ) return $data;
     437
     438        $options = $data['options'];
     439        if ( $data['remote_ip'] && $options['max_attempts'] ) {
     440            $ip_data        = CF7_Antispam_Blacklist::cf7a_blacklist_get_ip( $data['remote_ip'] );
     441            $ip_data_status = isset( $ip_data->status ) ? intval( $ip_data->status ) : 0;
     442            $max_attempts   = intval( $options['max_attempts'] );
     443
     444            if ( $ip_data_status >= $max_attempts ) {
     445                $data['spam_score']++;
     446                $data['is_spam'] = true;
     447                $data['reasons']['blacklisted score'] = $ip_data_status + $data['spam_score'];
     448
     449                cf7a_log( "The {$data['remote_ip']} is already blacklisted, status $ip_data_status", 1 );
     450            } elseif ( defined('CF7ANTISPAM_DEBUG') && CF7ANTISPAM_DEBUG && $ip_data_status > 0 ) {
     451                cf7a_log( sprintf( "The {$data['remote_ip']} is already blacklisted (score $ip_data_status) but still has %d attempts left", $max_attempts - $ip_data_status ), 1 );
     452            }
     453        }
     454        return $data;
     455    }
     456
     457    /**
     458     * Checks the HoneyForm (CSS hidden field).
     459     */
     460    public function filter_honeyform( $data ) {
     461        if ( $data['is_whitelisted'] ) return $data;
     462
     463        $options = $data['options'];
     464        if ( intval( $options['check_honeyform'] ) === 1 ) {
     465            $form_class = sanitize_html_class( $options['cf7a_customizations_class'] );
     466
     467            if ( isset( $_POST[ '_wpcf7_' . $form_class ] ) ) {
     468                $data['spam_score']++;
     469                $data['is_spam'] = true;
     470                $data['reasons']['honeyform'] = 'true';
     471            }
     472        }
     473        return $data;
     474    }
     475
     476    /**
     477     * Checks Referrer and Protocol.
     478     * Note: In original code, this only runs if spam_score < 1.
     479     */
     480    public function filter_referrer_protocol( $data ) {
     481        if ( $data['is_whitelisted'] ) return $data;
     482        if ( $data['is_spam'] ) return $data;
     483
     484        $options = $data['options'];
     485        $prefix  = sanitize_text_field( $options['cf7a_customizations_prefix'] );
     486        $score_warn = floatval( $options['score']['_warn'] );
     487
     488        if ( intval( $options['check_refer'] ) === 1 ) {
     489            // The right way to do this is BEFORE decrypting and THEN sanitize, because sanitized data are stripped of any special characters
     490            // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
     491            $cf7a_referer  = isset( $_POST[ $prefix . 'referer' ] ) ?  sanitize_text_field( wp_unslash( cf7a_decrypt($_POST[ $prefix . 'referer' ], $options['cf7a_cipher'] ) ) ) : false;
     492            if ( ! $cf7a_referer ) {
     493                $data['spam_score'] += $score_warn;
     494                $data['reasons']['no_referrer'] = 'client has referrer address';
     495                cf7a_log( "the {$data['remote_ip']} has reached the contact form page without any referrer", 1 );
     496            }
     497        }
     498
     499        // The right way to do this is BEFORE decrypting and THEN sanitize, because sanitized data are stripped of any special characters
     500        // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
     501        $cf7a_protocol = isset( $_POST[ $prefix . 'protocol' ] ) ? sanitize_text_field( wp_unslash( cf7a_decrypt( $_POST[ $prefix . 'protocol' ], $options['cf7a_cipher'] ) ) ) : false;
     502        if ( $cf7a_protocol ) {
     503            if ( in_array( $cf7a_protocol, array( 'HTTP/1.0', 'HTTP/1.1', 'HTTP/1.2' ) ) ) {
     504                $data['spam_score'] += $score_warn;
     505                $data['reasons']['no_protocol'] = 'client has a bot-like connection protocol';
     506                cf7a_log( "the {$data['remote_ip']} has a bot-like connection protocol (HTTP/1.X)", 1 );
     507            }
     508        }
     509        return $data;
     510    }
     511
     512    /**
     513     * Checks Plugin Version match.
     514     */
     515    public function filter_plugin_version( $data ) {
     516        if ( $data['is_whitelisted'] ) return $data;
     517        if ( $data['is_spam'] ) return $data;
     518
     519        $options = $data['options'];
     520        $prefix  = sanitize_text_field( $options['cf7a_customizations_prefix'] );
     521        $score_fingerprinting = floatval( $options['score']['_fingerprinting'] );
     522
     523        // The right way to do this is BEFORE decrypting and THEN sanitize, because sanitized data are stripped of any special characters
     524        // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
     525        $cf7a_version = isset( $_POST[ $prefix . 'version' ] ) ? sanitize_text_field( wp_unslash( cf7a_decrypt( $_POST[ $prefix . 'version' ], $options['cf7a_cipher'] ) ) ) : false;
     526
     527        // CASE A: Version field is completely missing or empty -> SPAM
     528        if ( ! $cf7a_version ) {
     529            $data['spam_score'] += $score_fingerprinting;
     530            $data['reasons']['data_mismatch'] = sprintf( "Version mismatch (empty) != '%s'", CF7ANTISPAM_VERSION );
     531            cf7a_log( sprintf( "The 'version' field submitted by %s is empty", $data['remote_ip'] ), 1 );
     532
     533            return $data;
     534        }
     535
     536        // CASE B: Version matches current version -> OK
     537        if ( $cf7a_version === CF7ANTISPAM_VERSION ) {
     538            return $data;
     539        }
     540
     541        // CASE C: Version Mismatch logic (Cache vs Spam)
     542        // Retrieve update data stored during the last plugin update
     543        $last_update_data = $options['last_update_data'] ?? null;
     544
     545        // Check if we have update data and if the submitted version matches the PREVIOUS version
     546        $is_old_version_match = ( $last_update_data && isset( $last_update_data['old_version'] ) && $cf7a_version === $last_update_data['old_version'] );
     547
     548        // Check if the update happened less than a week ago
     549        $period_of_grace = apply_filters('cf7a_period_of_grace', WEEK_IN_SECONDS);
     550        $is_within_grace_period = ( $last_update_data && isset( $last_update_data['time'] ) && ( time() - $last_update_data['time'] ) < $period_of_grace );
     551
     552        if ( $is_old_version_match && $is_within_grace_period ) {
     553
     554            // --- CACHE ISSUE DETECTED (FALLBACK) ---
     555            // Do NOT mark as spam. This is likely a cached user.
     556
     557            cf7a_log( "Cache mismatch detected for IP {$data['remote_ip']}. Submitted: $cf7a_version. Expected: " . CF7ANTISPAM_VERSION, 1 );
     558
     559            // Record the error
     560            if ( ! isset( $options['last_update_data']['errors'] ) ) {
     561                $options['last_update_data']['errors'] = array();
     562            }
     563
     564            // Add error details
     565            $options['last_update_data']['errors'][] = array(
     566                'ip'   => $data['remote_ip'],
     567                'time' => time(),
     568            );
     569
     570            $error_count = count( $options['last_update_data']['errors'] );
     571
     572            // Check trigger for email notification (Exactly on the 5th error)
     573            $cf7a_period_of_grace_max_attempts = intval(apply_filters( 'cf7a_period_of_grace_max_attempts', 5));
     574            if ( $cf7a_period_of_grace_max_attempts === $error_count || $error_count * 3 === $cf7a_period_of_grace_max_attempts ) {
     575                $this->send_cache_warning_email( $options['last_update_data'] );
     576                cf7a_log( "Cache warning email sent to admin.", 1 );
     577            }
     578
     579            // SAVE OPTIONS: We must save the error count to the database
     580            // Update the local $options variable first so subsequent filters use it if needed (though unlikely)
     581            $data['options'] = $options;
     582
     583            // Persist to DB
     584            update_option( 'cf7a_options', $options );
     585
     586        } else {
     587
     588            // --- REAL SPAM / INVALID VERSION ---
     589            // Either the grace period expired, or the version is completely random
     590
     591            $data['spam_score'] += $score_fingerprinting;
     592            $data['reasons']['data_mismatch'] = "Version mismatch '$cf7a_version' != '" . CF7ANTISPAM_VERSION . "'";
     593            cf7a_log( "The 'version' field submitted by {$data['remote_ip']} is mismatching (expired grace period or invalid)", 1 );
     594        }
     595
     596        return $data;
     597    }
     598
     599    /**
     600     * Checks Browser Fingerprint (JS based).
     601     */
     602    public function filter_bot_fingerprint( $data ) {
     603        if ( $data['is_whitelisted'] ) return $data;
     604        if ( $data['is_spam'] ) return $data;
     605
     606        $options = $data['options'];
     607        if ( intval( $options['check_bot_fingerprint'] ) !== 1 ) return $data;
     608
     609        $prefix  = sanitize_text_field( $options['cf7a_customizations_prefix'] );
     610        $score_fingerprinting = floatval( $options['score']['_fingerprinting'] );
     611
     612        $bot_fingerprint = array(
     613            'timezone'        => ! empty( $_POST[ $prefix . 'timezone' ] ) ? sanitize_text_field( wp_unslash( $_POST[ $prefix . 'timezone' ] ) ) : null,
     614            'platform'        => ! empty( $_POST[ $prefix . 'platform' ] ) ? sanitize_text_field( wp_unslash( $_POST[ $prefix . 'platform' ] ) ) : null,
     615            'screens'         => ! empty( $_POST[ $prefix . 'screens' ] ) ? sanitize_text_field( wp_unslash( $_POST[ $prefix . 'screens' ] ) ) : null,
     616            'memory'          => ! empty( $_POST[ $prefix . 'memory' ] ) ? intval( $_POST[ $prefix . 'memory' ] ) : null,
     617            'user_agent'      => ! empty( $_POST[ $prefix . 'user_agent' ] ) ? sanitize_text_field( wp_unslash( $_POST[ $prefix . 'user_agent' ] ) ) : null,
     618            'app_version'     => ! empty( $_POST[ $prefix . 'app_version' ] ) ? sanitize_text_field( wp_unslash( $_POST[ $prefix . 'app_version' ] ) ) : null,
     619            'webdriver'       => ! empty( $_POST[ $prefix . 'webdriver' ] ) ? sanitize_text_field( wp_unslash( $_POST[ $prefix . 'webdriver' ] ) ) : null,
     620            'session_storage' => ! empty( $_POST[ $prefix . 'session_storage' ] ) ? intval( $_POST[ $prefix . 'session_storage' ] ) : null,
     621            'bot_fingerprint' => ! empty( $_POST[ $prefix . 'bot_fingerprint' ] ) ? sanitize_text_field( wp_unslash( $_POST[ $prefix . 'bot_fingerprint' ] ) ) : null,
     622            'touch'           => ! empty( $_POST[ $prefix . 'touch' ] ),
     623        );
     624
     625        $fails = array();
     626        if ( ! $bot_fingerprint['timezone'] ) $fails[] = 'timezone';
     627        if ( ! $bot_fingerprint['platform'] ) $fails[] = 'platform';
     628        if ( ! $bot_fingerprint['screens'] ) $fails[] = 'screens';
     629        if ( ! $bot_fingerprint['user_agent'] ) $fails[] = 'user_agent';
     630        if ( ! $bot_fingerprint['app_version'] ) $fails[] = 'app_version';
     631        if ( ! $bot_fingerprint['webdriver'] ) $fails[] = 'webdriver';
     632        if ( ! $bot_fingerprint['session_storage'] ) $fails[] = 'session_storage';
     633        if ( 5 !== strlen( $bot_fingerprint['bot_fingerprint'] ) ) $fails[] = 'bot_fingerprint';
     634
     635        if ( isset( $_POST[ $prefix . 'isIos' ] ) || isset( $_POST[ $prefix . 'isFFox' ] ) || isset( $_POST[ $prefix . 'isIE' ] ) ) {
     636            if ( $bot_fingerprint['memory'] ) $fails[] = 'memory_supported';
     637        } elseif ( ! $bot_fingerprint['memory'] ) {
     638            $fails[] = 'memory';
     639        }
     640
     641        if ( isset( $_POST[ $prefix . 'isIos' ] ) || isset( $_POST[ $prefix . 'isAndroid' ] ) ) {
     642            if ( ! $bot_fingerprint['touch'] ) $fails[] = 'touch';
     643        }
     644
     645        if ( ! empty( $fails ) ) {
     646            $data['spam_score'] += count( $fails ) * $score_fingerprinting;
     647            $data['reasons']['bot_fingerprint'] = implode( ', ', $fails );
     648            cf7a_log( "The {$data['remote_ip']} ip hasn't passed fingerprint test ({$data['reasons']['bot_fingerprint']})", 1 );
     649        }
     650
     651        return $data;
     652    }
     653
     654    /**
     655     * Checks Bot Fingerprint Extras (User activity).
     656     */
     657    public function filter_bot_fingerprint_extras( $data ) {
     658        if ( $data['is_whitelisted'] ) return $data;
     659        if ( $data['is_spam'] ) return $data;
     660
     661        $options = $data['options'];
     662        if ( intval( $options['check_bot_fingerprint_extras'] ) !== 1 ) return $data;
     663
     664        $prefix  = sanitize_text_field( $options['cf7a_customizations_prefix'] );
     665        $score_fingerprinting = floatval( $options['score']['_fingerprinting'] );
     666
     667        $extras = array(
     668            'activity'               => ! empty( $_POST[ $prefix . 'activity' ] ) ? intval( $_POST[ $prefix . 'activity' ] ) : 0,
     669            'mouseclick_activity'    => ! empty( $_POST[ $prefix . 'mouseclick_activity' ] ) && sanitize_text_field( wp_unslash( $_POST[ $prefix . 'mouseclick_activity' ] ) ) === 'passed',
     670            'mousemove_activity'     => ! empty( $_POST[ $prefix . 'mousemove_activity' ] ) && sanitize_text_field( wp_unslash( $_POST[ $prefix . 'mousemove_activity' ] ) ) === 'passed',
     671            'webgl'                  => ! empty( $_POST[ $prefix . 'webgl' ] ) && sanitize_text_field( wp_unslash( $_POST[ $prefix . 'webgl' ] ) ) === 'passed',
     672            'webgl_render'           => ! empty( $_POST[ $prefix . 'webgl_render' ] ) && sanitize_text_field( wp_unslash( $_POST[ $prefix . 'webgl_render' ] ) ) === 'passed',
     673            'bot_fingerprint_extras' => empty( $_POST[ $prefix . 'bot_fingerprint_extras' ] ),
     674        );
     675
     676        $fails = array();
     677        if ( $extras['activity'] < 3 ) $fails[] = "activity {$extras["activity"]}";
     678        if ( empty( $extras['mouseclick_activity'] ) ) $fails[] = 'mouseclick_activity';
     679        if ( empty( $extras['mousemove_activity'] ) ) $fails[] = 'mousemove_activity';
     680        if ( empty( $extras['webgl'] ) ) $fails[] = 'webgl';
     681        if ( empty( $extras['webgl_render'] ) ) $fails[] = 'webgl_render';
     682        if ( empty( $extras['bot_fingerprint_extras'] ) ) $fails[] = 'bot_fingerprint_extras';
     683
     684        if ( ! empty( $fails ) ) {
     685            $data['spam_score'] += count( $fails ) * $score_fingerprinting;
     686            $data['reasons']['bot_fingerprint_extras'] = implode( ', ', $fails );
     687            cf7a_log( "The {$data['remote_ip']} ip hasn't passed fingerprint extra test", 1 );
     688        }
     689
     690        return $data;
     691    }
     692
     693    /**
     694     * Checks Language consistency.
     695     */
     696    public function filter_language( $data ) {
     697        if ( $data['is_whitelisted'] ) return $data;
     698        if ( $data['is_spam'] ) return $data;
     699
     700        $options = $data['options'];
     701        if ( intval( $options['check_language'] ) !== 1 ) return $data;
     702
     703        $prefix  = sanitize_text_field( $options['cf7a_customizations_prefix'] );
     704        $score_detection = floatval( $options['score']['_detection'] );
     705
     706        $languages = array();
     707        $languages['browser_language'] = ! empty( $_POST[ $prefix . 'browser_language' ] ) ? sanitize_text_field( wp_unslash( $_POST[ $prefix . 'browser_language' ] ) ) : null;
     708
     709        // The right way to do this is BEFORE decrypting and THEN sanitize, because sanitized data are stripped of any special characters
     710        // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
     711        $languages['accept_language']  = isset( $_POST[ $prefix . '_language' ] ) ? sanitize_text_field( wp_unslash( cf7a_decrypt( $_POST[ $prefix . '_language' ], $options['cf7a_cipher'] ) ) ) : null;
     712
     713        if ( empty( $languages['browser_language'] ) ) {
     714            $data['spam_score'] += $score_detection;
     715            $data['reasons']['browser_language'] = 'missing browser language';
     716        } else {
     717            $languages_locales    = cf7a_get_browser_languages_locales_array( $languages['browser_language'] );
     718            $languages['browser'] = $languages_locales['languages'];
     719        }
     720
     721        if ( empty( $languages['accept_language'] ) ) {
     722            $data['spam_score'] += $score_detection;
     723            $data['reasons']['language_field'] = 'missing language field';
     724        } else {
     725            $languages['accept'] = cf7a_get_accept_language_array( $languages['accept_language'] );
     726        }
     727
     728        if ( ! empty( $languages['accept'] ) && ! empty( $languages['browser'] ) ) {
     729            if ( ! array_intersect( $languages['browser'], $languages['accept'] ) ) {
     730                $data['spam_score'] += $score_detection;
     731                $data['reasons']['language_incoherence'] = 'languages detected not coherent';
     732            }
     733
     734            $client_languages = array_unique( array_merge( $languages['browser'], $languages['accept'] ) );
     735            $languages_allowed    = isset( $options['languages_locales']['allowed'] ) ? $this->cf7a_get_languages_or_locales( $options['languages_locales']['allowed'], 'languages' ) : array();
     736            $languages_disallowed = isset( $options['languages_locales']['disallowed'] ) ? $this->cf7a_get_languages_or_locales( $options['languages_locales']['disallowed'], 'languages' ) : array();
     737
     738            $language_disallowed = $this->cf7a_check_languages_locales_allowed( $client_languages, $languages_disallowed, $languages_allowed );
     739
     740            if ( false === $language_disallowed ) {
     741                $data['spam_score'] += $score_detection;
     742                $data['reasons']['browser_language'] = implode( ', ', $client_languages );
     743            }
     744        }
     745        return $data;
     746    }
     747
     748    /**
     749     * Checks GeoIP Location.
     750     */
     751    public function filter_geoip( $data ) {
     752        if ( $data['is_whitelisted'] ) return $data;
     753        if ( $data['is_spam'] ) return $data;
     754
     755        $options = $data['options'];
     756        if ( intval( $options['check_geo_location'] ) !== 1 ) return $data;
     757
     758        $geoip = new CF7_Antispam_Geoip();
     759        $score_warn = floatval( $options['score']['_warn'] );
     760        $locales_allowed    = $this->cf7a_get_languages_or_locales( $options['languages_locales']['allowed'], 'locales' );
     761        $locales_disallowed = $this->cf7a_get_languages_or_locales( $options['languages_locales']['disallowed'], 'locales' );
     762
     763        if ( ! empty( $geoip ) ) {
     764            try {
     765                $geoip_data      = $geoip->check_ip( $data['remote_ip'] );
     766                $geoip_continent = isset( $geoip_data['continent'] ) ? ( $geoip_data['continent'] ) : false;
     767                $geoip_country   = isset( $geoip_data['country'] ) ? ( $geoip_data['country'] ) : false;
     768                $geo_data        = array_filter( array( $geoip_continent, $geoip_country ) );
     769
     770                if ( ! empty( $geo_data ) ) {
     771                    if ( false === $this->cf7a_check_languages_locales_allowed( $geo_data, $locales_disallowed, $locales_allowed ) ) {
     772                        $data['reasons']['geo_ip'] = $geoip_continent . '-' . $geoip_country;
     773                        $data['spam_score'] += $score_warn;
     774                        cf7a_log( "The {$data['remote_ip']} is not allowed by geoip" . $data['reasons']['geo_ip'], 1 );
     775                    }
     776                } else {
     777                    $data['reasons']['no_geo_ip'] = 'unknown ip';
     778                }
     779            } catch ( Exception $e ) {
     780                cf7a_log( "unable to check geoip for {$data['remote_ip']} - " . $e->getMessage(), 1 );
     781            }
     782        }
     783        return $data;
     784    }
     785
     786    /**
     787     * Checks Time of submission.
     788     */
     789    public function filter_time_submission( $data ) {
     790        if ( $data['is_whitelisted'] ) return $data;
     791        if ( $data['is_spam'] ) return $data;
     792
     793        $options = $data['options'];
     794        if ( intval( $options['check_time'] ) !== 1 ) return $data;
     795
     796        $prefix  = sanitize_text_field( $options['cf7a_customizations_prefix'] );
     797
     798        $score_time = floatval( $options['score']['_time'] );
     799        $score_detection = floatval( $options['score']['_detection'] );
     800
     801        // The right way to do this is BEFORE decrypting and THEN sanitize, because sanitized data are stripped of any special characters
     802        // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
     803        $timestamp = isset( $_POST[ $prefix . '_timestamp' ] ) ? intval( cf7a_decrypt( $_POST[ $prefix . '_timestamp' ], $options['cf7a_cipher'] ) ) : 0;
     804        $time_now         = time();
     805        $time_elapsed_min = intval( $options['check_time_min'] );
     806        $time_elapsed_max = intval( $options['check_time_max'] );
     807
     808        if ( ! $timestamp ) {
     809            $data['spam_score'] += $score_detection;
     810            $data['reasons']['timestamp'] = 'missing field';
     811            cf7a_log( "The {$data['remote_ip']} ip _timestamp field is missing", 1 );
     812        } else {
     813            $time_elapsed = $time_now - $timestamp;
     814
     815            if ( 0 !== $time_elapsed_min && $time_elapsed < $time_elapsed_min ) {
     816                $data['spam_score'] += $score_time;
     817                $data['reasons']['min_time_elapsed'] = $time_elapsed;
     818                cf7a_log( "The {$data['remote_ip']} ip took too little time ($time_elapsed s)", 1 );
     819            }
     820
     821            if ( 0 !== $time_elapsed_max && $time_elapsed > $time_elapsed_max ) {
     822                $data['spam_score'] += $score_time;
     823                $data['reasons']['max_time_elapsed'] = $time_elapsed;
     824                cf7a_log( "The {$data['remote_ip']} ip took too much time ($time_elapsed s)", 1 );
     825            }
     826        }
     827        return $data;
     828    }
     829
     830    /**
     831     * Checks for bad strings inside the email address.
     832     */
     833    public function filter_bad_email_strings( $data ) {
     834        if ( $data['is_whitelisted'] ) return $data;
     835        if ( $data['is_spam'] ) return $data;
     836
     837        $options = $data['options'];
     838        if ( intval( $options['check_bad_email_strings'] ) !== 1 || empty( $data['emails'] ) ) return $data;
     839
     840        $score_bad_string = floatval( $options['score']['_bad_string'] );
     841        $bad_email_strings = isset( $options['bad_email_strings_list'] ) ? $options['bad_email_strings_list'] : array();
     842
     843        foreach ( $data['emails'] as $email ) {
     844            foreach ( $bad_email_strings as $bad_email_string ) {
     845                if ( false !== stripos( strtolower( $email ), strtolower( $bad_email_string ) ) ) {
     846                    $data['spam_score'] += $score_bad_string;
     847                    $data['reasons']['email_blacklisted'][] = $bad_email_string;
     848                }
     849            }
     850        }
     851
     852        if ( isset( $data['reasons']['email_blacklisted'] ) && is_array($data['reasons']['email_blacklisted']) ) {
     853            $data['reasons']['email_blacklisted'] = implode( ',', $data['reasons']['email_blacklisted'] );
     854            cf7a_log( "The ip address {$data['remote_ip']} sent a mail using bad string {$data['reasons']['email_blacklisted']}", 1 );
     855        }
     856
     857        return $data;
     858    }
     859
     860    /**
     861     * Checks User Agent.
     862     */
     863    public function filter_user_agent( $data ) {
     864        if ( $data['is_whitelisted'] ) return $data;
     865        if ( $data['is_spam'] ) return $data;
     866
     867        $options = $data['options'];
     868        if ( intval( $options['check_bad_user_agent'] ) !== 1 ) return $data;
     869
     870        $score_detection = floatval( $options['score']['_detection'] );
     871        $score_bad_string = floatval( $options['score']['_bad_string'] );
     872        $bad_user_agent_list = isset( $options['bad_user_agent_list'] ) ? $options['bad_user_agent_list'] : array();
     873
     874        if ( ! $data['user_agent'] ) {
     875            $data['spam_score'] += $score_detection;
     876            $data['reasons']['user_agent'] = 'empty';
     877            cf7a_log( "The {$data['remote_ip']} ip user agent is empty", 1 );
     878        } else {
     879            foreach ( $bad_user_agent_list as $bad_user_agent ) {
     880                if ( false !== stripos( strtolower( $data['user_agent'] ), strtolower( $bad_user_agent ) ) ) {
     881                    $data['spam_score'] += $score_bad_string;
     882                    $data['reasons']['user_agent'][] = $bad_user_agent;
     883                }
     884            }
     885
     886            if ( isset( $data['reasons']['user_agent'] ) && is_array( $data['reasons']['user_agent'] ) ) {
     887                $data['reasons']['user_agent'] = implode( ', ', $data['reasons']['user_agent'] );
     888                cf7a_log( "The {$data['remote_ip']} ip user agent was listed into bad user agent list", 1 );
     889            }
     890        }
     891        return $data;
     892    }
     893
     894    /**
     895     * Checks for bad words in message.
     896     */
     897    public function filter_bad_words( $data ) {
     898        if ( $data['is_whitelisted'] ) return $data;
     899        if ( $data['is_spam'] ) return $data;
     900
     901        $options = $data['options'];
     902        if ( intval( $options['check_bad_words'] ) !== 1 || '' === $data['message'] ) return $data;
     903
     904        $score_bad_string = floatval( $options['score']['_bad_string'] );
     905        $bad_words = $options['bad_words_list'] ?? array();
     906        $message_compressed = $this->cf7a_simplify_text( $data['message'] );
     907
     908        foreach ( $bad_words as $bad_word ) {
     909            if ( false !== stripos( $message_compressed, $this->cf7a_simplify_text( $bad_word ) ) ) {
     910                $data['spam_score'] += $score_bad_string;
     911                $data['reasons']['bad_word'][] = $bad_word;
     912            }
     913        }
     914
     915        if ( ! empty( $data['reasons']['bad_word'] ) && is_array($data['reasons']['bad_word']) ) {
     916            $data['reasons']['bad_word'] = implode( ',', $data['reasons']['bad_word'] );
     917            cf7a_log( "{$data['remote_ip']} has bad word in message " . $data['reasons']['bad_word'], 1 );
     918        }
     919        return $data;
     920    }
     921
     922    /**
     923     * Checks DNS Blacklist.
     924     */
     925    public function filter_dnsbl( $data ) {
     926        if ( $data['is_whitelisted'] ) return $data;
     927        if ( $data['is_spam'] ) return $data;
     928
     929        $options = $data['options'];
     930        if ( intval( $options['check_dnsbl'] ) !== 1 || ! $data['remote_ip'] ) return $data;
     931
     932        $score_dnsbl = floatval( $options['score']['_dnsbl'] );
     933        $reverse_ip = '';
     934
     935        if ( filter_var( $data['remote_ip'], FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 ) ) {
     936            $reverse_ip = $this->cf7a_reverse_ipv4( $data['remote_ip'] );
     937        } elseif ( filter_var( $data['remote_ip'], FILTER_VALIDATE_IP, FILTER_FLAG_IPV6 ) ) {
     938            $reverse_ip = $this->cf7a_reverse_ipv6( $data['remote_ip'] );
     939        }
     940
     941        foreach ( $options['dnsbl_list'] as $dnsbl ) {
     942            if ( $this->cf7a_check_dnsbl( $reverse_ip, $dnsbl ) ) {
     943                $data['reasons']['dsnbl'][] = $dnsbl;
     944                $data['spam_score'] += $score_dnsbl;
     945            }
     946        }
     947
     948        if ( isset( $data['reasons']['dsnbl'] ) && is_array( $data['reasons']['dsnbl'] ) ) {
     949            $data['reasons']['dsnbl'] = implode( ', ', $data['reasons']['dsnbl'] );
     950            cf7a_log( "{$data['remote_ip']} is listed in DNSBL ({$data['reasons']['dsnbl']})", 1 );
     951        }
     952        return $data;
     953    }
     954
     955    /**
     956     * Checks visible honeypot fields.
     957     */
     958    public function filter_honeypot( $data ) {
     959        if ( $data['is_whitelisted'] ) return $data;
     960        if ( $data['is_spam'] ) return $data;
     961
     962        $options = $data['options'];
     963        if ( ! $options['check_honeypot'] ) return $data;
     964
     965        $mail_tag_text = array();
     966        foreach ( $data['mail_tags'] as $mail_tag ) {
     967            if ( 'text' === $mail_tag['type'] || 'text*' === $mail_tag['type'] ) {
     968                $mail_tag_text[] = $mail_tag['name'];
     969            }
     970        }
     971
     972        if ( ! empty( $mail_tag_text ) ) {
     973            $input_names = cf7a_get_honeypot_input_names( $options['honeypot_input_names'] );
     974            $mail_tag_count = count( $input_names );
     975            $score_honeypot = floatval( $options['score']['_honeypot'] );
     976
     977            for ( $i = 0; $i < $mail_tag_count; $i++ ) {
     978                $has_honeypot = ! empty( $_POST[ $input_names[ $i ] ] );
     979                if ( $has_honeypot ) {
     980                    $data['spam_score'] += $score_honeypot;
     981                    $data['reasons']['honeypot'][] = $input_names[ $i ];
     982                }
     983            }
     984
     985            if ( ! empty( $data['reasons']['honeypot'] ) && is_array($data['reasons']['honeypot']) ) {
     986                $data['reasons']['honeypot'] = implode( ', ', $data['reasons']['honeypot'] );
     987                cf7a_log( "The {$data['remote_ip']} has filled the input honeypot(s) {$data['reasons']['honeypot']}", 1 );
     988            }
     989        }
     990        return $data;
     991    }
     992
     993    /**
     994     * Checks B8 Bayesian Filter.
     995     * Now hooks into 'cf7a_check_b8'.
     996     */
     997    public function filter_b8_bayesian( $data ) {
     998        // Even if requested "at the end", we usually skip B8 if the user is explicitly Whitelisted.
     999        if ( $data['is_whitelisted'] ) return $data;
     1000
     1001        $options = $data['options'];
     1002        $text = stripslashes( $data['message'] );
     1003        \assert( \is_string( $text ) );
     1004
     1005        // Ensure B8 is enabled and there is a message to check
     1006        if ( $options['enable_b8'] && $data['message'] ) {
     1007            $b8_threshold = floatval( $options['b8_threshold'] );
     1008            $b8_threshold = $b8_threshold > 0 && $b8_threshold < 1 ? $b8_threshold : 1;
     1009            $score_detection = floatval( $options['score']['_detection'] );
     1010
     1011            $cf7a_b8 = new CF7_AntiSpam_B8();
     1012            $rating  = round( $cf7a_b8->cf7a_b8_classify( $text ), 2 );
     1013
     1014            // If the rating is high, add to spam score
     1015            if ( $rating >= $b8_threshold ) {
     1016                $data['reasons']['b8'] = $rating;
     1017                $data['spam_score'] += $score_detection;
     1018                $data['is_spam'] = true;
     1019                cf7a_log( "B8 rating $rating / 1", 1 );
     1020            }
     1021
     1022            // LEARNING LOGIC:
     1023            // Use the accumulated spam_score from previous filters to decide how to teach B8.
     1024
     1025            if ( $data['spam_score'] >= 1 || $data['is_spam'] ) {
     1026                // If previous filters OR B8 itself marked it as spam -> Learn Spam
     1027                cf7a_log( "{$data['remote_ip']} detected as spam (score {$data['spam_score']}), learning as SPAM.", 1 );
     1028                $cf7a_b8->cf7a_b8_learn_spam( $text );
     1029            } elseif ( $rating < $b8_threshold * 0.5 ) {
     1030                // If no spam detected and B8 thinks it's safe -> Learn Ham
     1031                cf7a_log( "B8 detected spamminess of $rating (below threshold), learning as HAM.", 1 );
     1032                $cf7a_b8->cf7a_b8_learn_ham( $text );
     1033            }
     1034        }
     1035        return $data;
     1036    }
     1037
     1038    /**
     1039     * Sends an email to the admin, warning them to clear the cache.
     1040     * @param array $update_data the array of data to be sent to the admin
     1041     * @return void
     1042     */
     1043    private function send_cache_warning_email( $update_data ): void {
     1044        $tools = new CF7_AntiSpam_Admin_Tools();
     1045        $recipient = get_option( 'admin_email' );
     1046        $body = sprintf(
     1047            "Hello Admin,\n\nWe detected 5 users trying to submit forms with the old version (%s) instead of the new one (%s).\n\nThis usually means your website cache (or CDN) hasn't been cleared after the last update.\n\nPlease purge your site cache immediately to prevent legitimate users from being flagged as spam.\n\nTime of update: %s",
     1048            $update_data['old_version'],
     1049            $update_data['new_version'],
     1050            gmdate( 'Y-m-d H:i:s', $update_data['time'] )
     1051        );
     1052        $subject = 'CF7 AntiSpam - Cache Warning Alert';
     1053
     1054        $tools->send_email_to_admin( $subject, $recipient, $body, $recipient );
     1055    }
    10661056}
  • cf7-antispam/trunk/core/CF7_AntiSpam_Flamingo.php

    r3389259 r3402920  
    33namespace CF7_AntiSpam\Core;
    44
     5use CF7_AntiSpam\Admin\CF7_AntiSpam_Admin_Tools;
    56use WP_Query;
    67use WPCF7_ContactForm;
     
    110111                        $rating = ! empty( $flamingo_post->meta['_cf7a_b8_classification'] ) ? $flamingo_post->meta['_cf7a_b8_classification'] : $b8->cf7a_b8_classify( $message );
    111112
    112                         $filters = new CF7_AntiSpam_Filters();
    113 
    114113                        if ( ! $flamingo_post->spam && 'spam' === $action ) {
    115114                            $b8->cf7a_b8_unlearn_ham( $message );
     
    117116
    118117                            if ( $options['autostore_bad_ip'] ) {
    119                                 $filters->cf7a_ban_by_ip( $flamingo_post->meta['remote_ip'], 'flamingo ban' );
     118                                CF7_Antispam_Blacklist::cf7a_ban_by_ip( $flamingo_post->meta['remote_ip'], 'flamingo ban' );
    120119                            }
    121120                        } elseif ( $flamingo_post->spam && 'ham' === $action ) {
     
    124123
    125124                            if ( $options['autostore_bad_ip'] ) {
    126                                 $filters->cf7a_unban_by_ip( $flamingo_post->meta['remote_ip'] );
     125                                CF7_Antispam_Blacklist::cf7a_unban_by_ip( $flamingo_post->meta['remote_ip'] );
    127126                            }
    128127                        }
     
    211210     * @return array { success: boolean, message: string }
    212211     */
    213     public function cf7a_resend_mail( $mail_id ) {
     212    public function cf7a_resend_mail( int $mail_id ): array {
    214213        $flamingo_data = new Flamingo_Inbound_Message( $mail_id );
    215214        $message = self::cf7a_get_mail_field( $flamingo_data, 'message' );
     
    267266        }
    268267
    269         /**
    270          * Filter cf7-antispam before resend an email who was spammed
    271          *
    272          * @param string $body the mail message content
    273          * @param string $sender the mail message sender
    274          * @param string $subject the mail message subject
    275          * @param string $recipient the mail recipient
    276          *
    277          * @returns string the mail body content
    278          */
    279         $body = apply_filters( 'cf7a_before_resend_email', $body, $sender, $subject, $recipient );
    280 
    281         // Set up headers correctly
    282         $site_name  = get_bloginfo( 'name' );
    283         $from_email = get_option( 'admin_email' );
    284 
    285         $headers  = "From: {$site_name} <{$from_email}>\n";
    286         $headers .= "Content-Type: text/html\n";
    287         $headers .= "X-WPCF7-Content-Type: text/html\n";
    288         $headers .= "Reply-To: {$sender}\n";
    289 
    290         /* send the email */
    291         $result = wp_mail( $recipient, $subject, $body, $headers );
     268        $tools = new CF7_AntiSpam_Admin_Tools();
     269        $result = $tools->send_email_to_admin( $subject, $recipient, $body, $sender );
     270
    292271        if ( $result ) {
    293272            return array( 'success'=> true, 'message' => __( 'Email sent with success', 'cf7-antispam' ) );
     
    298277
    299278    /**
    300      * Parse CF7 mail tags in recipient field
     279     * Parse CF7 mail tags in the recipient field
    301280     *
    302281     * @param string                   $recipient The recipient string that may contain CF7 tags
  • cf7-antispam/trunk/core/CF7_AntiSpam_Frontend.php

    r3389259 r3402920  
    2828     * @var      string $plugin_name The ID of this plugin.
    2929     */
    30     private $plugin_name;
     30    private string $plugin_name;
    3131
    3232    /**
     
    3737     * @var      string $version The current version of this plugin.
    3838     */
    39     private $version;
     39    private string $version;
    4040
    4141    /**
     
    4646     * @var      array    $options    options of this plugin.
    4747     */
    48     private $options;
     48    private array $options;
    4949
    5050    /**
     
    6262    }
    6363
     64    /**
     65     * Checks if the contact form 7 shortcode exists in the current post
     66     *
     67     * @return bool
     68     */
     69    private function cf7_shortcode_exists() {
     70        global $post;
     71        return is_a( $post, 'WP_Post' ) && has_shortcode( $post->post_content, 'contact-form-7' );
     72        // Register the contact form antispam scripts
     73    }
     74
     75
     76    /**
     77     * Handles loading scripts
     78     *
     79     * @return void
     80     */
     81    public function load_scripts() {
     82        // Register the contact form antispam scripts
     83        add_action('wp_enqueue_scripts', array($this, 'register_scripts'));
     84
     85        // Select the hook to use based on the User's choice
     86        $hook = !empty($this->options['optimize_scripts_loading']) ? 'wpcf7_enqueue_scripts' : 'wp_enqueue_scripts';
     87
     88        // enqueue CF7 antispam scripts only if contact form 7 wpcf7_enqueue_scripts is called
     89        add_action( $hook, array( $this, 'enqueue_scripts' ));
     90    }
     91
    6492    public function setup() {
    65         if ( ! $this->cf7_shortcode_exists() ) {
    66             return;
    67         }
    68 
    6993        /* It adds hidden fields to the form */
    7094        add_filter( 'wpcf7_form_hidden_fields', array( $this, 'cf7a_add_hidden_fields' ), 1 );
    7195        add_filter( 'wpcf7_config_validator_available_error_codes', array( $this, 'cf7a_remove_cf7_error_message' ), 10, 2 );
    7296
    73         /* adds the javascript script to frontend */
    74         add_action( 'wp_footer', array( $this, 'enqueue_scripts' ) );
    7597
    7698        /* It adds a hidden field to the form with a unique value that is encrypted with a cipher */
     
    120142            add_action( 'wp_footer', array( $this, 'cf7a_add_honeypot_css' ), 11 );
    121143        }
    122     }
    123 
    124     private function cf7_shortcode_exists() {
    125         global $post;
    126         return is_a( $post, 'WP_Post' ) && has_shortcode( $post->post_content, 'contact-form-7' );
    127144    }
    128145
     
    354371     *
    355372     * @param array $fields the array of hidden fields that will be added to the form.
     373     * @return array the array of hidden fields that will be added to the form.
     374     *               the returned fields are: version, address, referer, protocol
     375     *               the optional fields are: language, timestamp, hash
     376     *               the optional fields are added based on the options set in the plugin
     377     *               the fields are encrypted with the cipher set in the plugin
    356378     */
    357379    public function cf7a_add_hidden_fields( $fields ) {
     
    386408                $prefix . 'version'  => '1.0',
    387409                $prefix . 'address'  => cf7a_crypt( cf7a_get_real_ip(), $this->options['cf7a_cipher'] ),
    388                 $prefix . 'referer'  => cf7a_crypt( $referrer ? $referrer : 'no referer', $this->options['cf7a_cipher'] ),
    389                 $prefix . 'protocol' => cf7a_crypt( $protocol ? $protocol : 'protocol missing', $this->options['cf7a_cipher'] ),
     410                $prefix . 'referer'  => cf7a_crypt( $referrer ? $referrer : '', $this->options['cf7a_cipher'] ),
     411                $prefix . 'protocol' => cf7a_crypt( $protocol ? $protocol : '', $this->options['cf7a_cipher'] ),
    390412            )
    391413        );
     
    515537     * @since    0.1.0
    516538     */
    517     public function enqueue_scripts() {
    518 
     539    public function register_scripts() {
    519540        /**
    520541         *
     
    530551        $asset = include CF7ANTISPAM_PLUGIN_DIR . '/build/script.asset.php';
    531552        wp_register_script( $this->plugin_name, CF7ANTISPAM_PLUGIN_URL . '/build/script.js', $asset['dependencies'], $asset['version'], true );
    532         wp_enqueue_script( $this->plugin_name );
    533553
    534554        wp_localize_script(
     
    541561            )
    542562        );
     563    }
     564
     565    /**
     566     * Register the JavaScript for the admin area.
     567     *
     568     * @since    0.1.0
     569     */
     570    public function enqueue_scripts() {
     571        wp_enqueue_script( $this->plugin_name );
    543572    }
    544573
  • cf7-antispam/trunk/core/CF7_Antispam_Blacklist.php

    r3389259 r3402920  
    2424
    2525    /**
     26     * It takes an IP address as a parameter, validates it, and then returns the row from the database that matches that IP
     27     * address
     28     *
     29     * @param string $ip - The IP address to check.
     30     *
     31     * @return array|object|null - the row from the database that matches the IP address.
     32     */
     33    public static function cf7a_blacklist_get_ip( $ip ) {
     34        $ip = filter_var( $ip, FILTER_VALIDATE_IP );
     35        if ( $ip ) {
     36            global $wpdb;
     37            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
     38            $r = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM %i WHERE ip = %s", $wpdb->prefix . 'cf7a_blacklist', $ip ) );
     39            if ( $r ) {
     40                return $r;
     41            }
     42        }
     43
     44        return null;
     45    }
     46
     47    /**
     48     * It adds an IP address to the blacklist.
     49     *
     50     * @param string $ip The IP address to ban.
     51     * @param array $reason The reason why the IP is being banned.
     52     * @param int $spam_score This is the number of points that will be added to the IP's spam score.
     53     *
     54     * @return bool true if the given id was banned
     55     */
     56    public static function cf7a_ban_by_ip( string $ip, array $reason = array(), $spam_score = 1 ): bool {
     57        $ip = filter_var( $ip, FILTER_VALIDATE_IP );
     58
     59        if ( $ip ) {
     60            global $wpdb;
     61
     62            $ip_row = CF7_Antispam_Blacklist::cf7a_blacklist_get_ip( $ip );
     63
     64            if ( $ip_row ) {
     65                // if the ip is in the blacklist, update the status
     66                $status = isset( $ip_row->status ) ? floatval( $ip_row->status ) + floatval( $spam_score ) : 1;
     67
     68            } else {
     69                // if the ip is not in the blacklist, add it and initialize the status
     70                $status = floatval( $spam_score );
     71            }
     72
     73            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
     74            $r = $wpdb->replace( $wpdb->prefix . 'cf7a_blacklist', array(
     75                    'ip'     => $ip,
     76                    'status' => $status,
     77                    'meta'   => serialize( array(
     78                            'reason' => $reason,
     79                            'meta'   => null,
     80                        ) ),
     81                ), array( '%s', '%d', '%s' ) );
     82
     83            if ( $r > - 1 ) {
     84                return true;
     85            }
     86        }
     87
     88        return false;
     89    }
     90
     91    /**
     92     * It deletes the IP address from the database
     93     *
     94     * @param string $ip The IP address to unban.
     95     *
     96     * @return int|false The number of rows deleted.
     97     */
     98    public static function cf7a_unban_by_ip( $ip ) {
     99        $ip = filter_var( $ip, FILTER_VALIDATE_IP );
     100
     101        if ( $ip ) {
     102            global $wpdb;
     103
     104            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
     105            $r = $wpdb->delete( $wpdb->prefix . 'cf7a_blacklist', array(
     106                    'ip' => $ip,
     107                ), array(
     108                    '%s',
     109                ) );
     110
     111            return ! is_wp_error( $r ) ? $r : $wpdb->last_error;
     112        }
     113
     114        return false;
     115    }
     116
     117    /**
    26118     * Get all blacklist data from database.
    27119     *
     
    53145     * @return   object|null The blacklist entry or null if not found
    54146     */
    55     public function cf7a_blacklist_get_id( $id ) {
     147    public function cf7a_blacklist_get_id( int $id ) {
    56148        global $wpdb;
    57149
     
    108200            // Add the IP to the permanent banlist
    109201            if ( CF7_AntiSpam::update_plugin_option( 'bad_ip_list', array_merge( $current_bad_ips, array( $ban_ip->ip ) ) ) ) {
    110                 // Remove from temporary blacklist
    111202                $this->cf7a_unban_by_id( $id );
    112203            }
     
    315406        );
    316407    }
     408
     409    /**
     410     * It updates the status of all the users in the blacklist table by subtracting 1 from the status column.
     411     *
     412     * Then it deletes all the users whose status is 0.
     413     * The status column is the number of days the user is banned for.
     414     * So if the user is banned for 3 days, the status column will be 3. After the first day, the status column will be 2. After the second day, the status column will be 1. After the third day, the status column will be 0.
     415     * When the status column is 0, the user is unbanned.
     416     *
     417     * The function returns true if the user is unbanned.
     418     *
     419     * @return true.
     420     */
     421    public function cf7a_cron_unban() {
     422        global $wpdb;
     423
     424        /* We remove 1 from the status column */
     425        $status_decrement = 1;
     426
     427        /* Below 0 is not anymore a valid status for a blacklist entry, so we can remove it */
     428        $lower_bound = 0;
     429
     430        $blacklist_table = $wpdb->prefix . 'cf7a_blacklist';
     431
     432        /* removes a status count at each balcklisted ip */
     433        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
     434        $updated = $wpdb->query( $wpdb->prepare( "UPDATE %i SET `status` = `status` - %d", $blacklist_table, $status_decrement ) );
     435        cf7a_log( "Status updated for blacklisted (score -1) - $updated users", 1 );
     436
     437        /* when the line has 0 in status, we can remove it from the blacklist */
     438        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
     439        $updated_deletion = $wpdb->delete(
     440            $blacklist_table,
     441            array( 'status' => $lower_bound ),
     442            array( '%d' )
     443        );
     444        cf7a_log( "Removed {$updated_deletion} users from blacklist", 1 );
     445
     446        return true;
     447    }
    317448}
  • cf7-antispam/trunk/core/functions.php

    r3389259 r3402920  
    251251 * @return string The decrypted value.
    252252 */
    253 function cf7a_decrypt( $value, $cipher = 'aes-256-cbc' ) {
    254     if ( ! extension_loaded( 'openssl' ) ) {
     253function cf7a_decrypt( string $value, string $cipher = 'aes-256-cbc' ): string {
     254    try {
     255        if ( ! extension_loaded( 'openssl' ) ) {
     256            return $value;
     257        }
     258
     259        return openssl_decrypt( $value, $cipher, wp_salt( 'nonce' ), $options = 0, substr( wp_salt( 'nonce' ), 0, 16 ) );
     260    } catch ( Exception $e ) {
    255261        return $value;
    256262    }
    257 
    258     return openssl_decrypt( $value, $cipher, wp_salt( 'nonce' ), $options = 0, substr( wp_salt( 'nonce' ), 0, 16 ) );
    259263}
    260264
     
    360364                        $v = '[]';
    361365                    } else {
    362                         // Converte array in formato leggibile
     366                        // Convert array to readable format
    363367                        $v = '[' . implode(
    364                             ', ',
    365                             array_map(
    366                                 function ( $item ) {
    367                                     return is_array( $item ) ? json_encode( $item ) : (string) $item;
    368                                 },
    369                                 $v
    370                             )
    371                         ) . ']';
     368                                ', ',
     369                                array_map(
     370                                    function ( $item ) {
     371                                        return is_array( $item ) ? json_encode( $item ) : (string) $item;
     372                                    },
     373                                    $v
     374                                )
     375                            ) . ']';
    372376                    }
    373377                } elseif ( is_object( $v ) ) {
  • cf7-antispam/trunk/engine/CF7_AntiSpam_Activator.php

    r3394913 r3402920  
    4646            'cf7a_cipher'                      => 'aes-128-cbc',
    4747            'cf7a_score_preset'                => 'weak',
    48             'cf7a_disable_reload'              => true,
    49             'check_bot_fingerprint'            => true,
    50             'check_bot_fingerprint_extras'     => true,
    51             'append_on_submit'                 => true,
     48            'cf7a_disable_reload'              => false,
     49            'optimize_scripts_loading'         => false,
     50            'check_bot_fingerprint'            => false,
     51            'check_bot_fingerprint_extras'     => false,
     52            'append_on_submit'                 => false,
    5253            'check_time'                       => true,
    5354            'check_time_min'                   => 6,
     
    214215
    215216    /**
     217     * Store the update data
     218     *
     219     * @param array $options - the options array.
     220     */
     221    private static function store_update_data( $options ) {
     222        /* update the plugin update time field */
     223        $options['last_update_data'] = array(
     224            'time' => time(),
     225            'old_version' => $options['cf7a_version'] ?? 'unknown',
     226            'new_version' => CF7ANTISPAM_VERSION,
     227            'errors' => array(),
     228        );
     229        return $options;
     230    }
     231
     232    /**
    216233     *  Create or Update the CF7 Antispam options
    217234     *
     
    236253
    237254        } else {
    238 
    239             /* update the plugin options but add the new options automatically */
     255            /* if the plugin is already installed, update the plugin options automatically */
    240256            if ( isset( $options['cf7a_version'] ) ) {
    241                 unset( $options['cf7a_version'] );
     257
     258                /* update the plugin last update time field if the current version is set (so we are updating the plugin and not installing it) */
     259                $options = self::store_update_data( $options );
     260
     261                /* remove the version field */
     262                $options['cf7a_version'] = CF7ANTISPAM_VERSION;
    242263            }
    243264
  • cf7-antispam/trunk/languages/cf7-antispam.pot

    r3389259 r3402920  
    33msgid ""
    44msgstr ""
    5 "Project-Id-Version: AntiSpam for Contact Form 7 0.7.0\n"
     5"Project-Id-Version: AntiSpam for Contact Form 7 0.7.2\n"
    66"Report-Msgid-Bugs-To: https://wordpress.org/support/plugins/cf7-antispam\n"
    77"MIME-Version: 1.0\n"
     
    99"Content-Type: text/plain; charset=iso-8859-1\n"
    1010"Plural-Forms: nplurals=2; plural=(n!=1);\n"
    11 "POT-Creation-Date: 2025-10-22T23:23:52.135Z\n"
     11"POT-Creation-Date: 2025-11-25T22:42:09.543Z\n"
    1212"PO-Revision-Date: 2025-MO-DA HO:MI+ZONE\n"
    1313"Last-Translator: Codekraft <erik@codekraft.it>\n"
     
    3737msgstr ""
    3838
    39 #: engine/CF7_AntiSpam_Activator.php:255
     39#: engine/CF7_AntiSpam_Activator.php:276
    4040msgid ""
    4141"CF7 AntiSpam updated successful! Please flush cache to refresh hidden form "
     
    5151msgstr ""
    5252
    53 #: core/functions.php:295
    54 #: core/CF7_AntiSpam_Flamingo.php:482
     53#: core/functions.php:299
     54#: core/CF7_AntiSpam_Flamingo.php:461
    5555msgid "none"
    5656msgstr ""
    5757
    5858# warn because not yet banned but already listed
    59 #: core/functions.php:318
    60 msgid "??"
    61 msgstr ""
    62 
    63 # champion of spammer (>100 mail)
    6459#: core/functions.php:322
    6560msgid "??"
    6661msgstr ""
    6762
     63# champion of spammer (>100 mail)
     64#: core/functions.php:326
     65msgid "??"
     66msgstr ""
     67
    6868#: core/CF7_Antispam_Service.php:78
     69#: admin/CF7_AntiSpam_Admin_Core.php:80
    6970#: admin/CF7_AntiSpam_Admin_Core.php:81
    70 #: admin/CF7_AntiSpam_Admin_Core.php:82
    7171msgid "Antispam"
    7272msgstr ""
     
    112112msgstr ""
    113113
    114 #: core/CF7_AntiSpam_Rest_Api.php:98
     114#: core/CF7_AntiSpam_Rest_Api.php:101
    115115msgid "You cannot view the plugin status."
    116116msgstr ""
    117117
    118 #: core/CF7_AntiSpam_Rest_Api.php:134
    119 #: core/CF7_AntiSpam_Rest_Api.php:175
    120 #: core/CF7_AntiSpam_Rest_Api.php:213
    121 #: core/CF7_AntiSpam_Rest_Api.php:251
    122 #: core/CF7_AntiSpam_Rest_Api.php:289
     118#: core/CF7_AntiSpam_Rest_Api.php:115
     119#: core/CF7_AntiSpam_Rest_Api.php:172
     120#: core/CF7_AntiSpam_Rest_Api.php:215
     121#: core/CF7_AntiSpam_Rest_Api.php:248
     122#: core/CF7_AntiSpam_Rest_Api.php:286
     123#: core/CF7_AntiSpam_Rest_Api.php:324
     124#: core/CF7_AntiSpam_Rest_Api.php:362
     125#: core/CF7_AntiSpam_Rest_Api.php:400
     126#: core/CF7_AntiSpam_Rest_Api.php:451
     127#: core/CF7_AntiSpam_Rest_Api.php:486
    123128msgid "Invalid nonce"
    124129msgstr ""
    125130
    126 #: core/CF7_AntiSpam_Rest_Api.php:145
     131#: core/CF7_AntiSpam_Rest_Api.php:127
     132msgid "Error: unable to download GeoIP database"
     133msgstr ""
     134
     135#: core/CF7_AntiSpam_Rest_Api.php:135
     136msgid "GeoIP database downloaded successfully"
     137msgstr ""
     138
     139#: core/CF7_AntiSpam_Rest_Api.php:185
    127140msgid "Error: unable to resend email with id %s."
    128141msgstr ""
    129142
    130143# %s is the mail id.
    131 #: core/CF7_AntiSpam_Rest_Api.php:157
     144#: core/CF7_AntiSpam_Rest_Api.php:197
    132145msgid "Ops! something went wrong... unable to resend email with id %s"
    133146msgstr ""
    134147
    135 #: core/CF7_AntiSpam_Rest_Api.php:187
     148#: core/CF7_AntiSpam_Rest_Api.php:229
     149msgid "Nothing to update"
     150msgstr ""
     151
     152#: core/CF7_AntiSpam_Rest_Api.php:232
     153msgid "Contact Form 7 Antispam Options and Database updated successfully!"
     154msgstr ""
     155
     156#: core/CF7_AntiSpam_Rest_Api.php:260
    136157msgid "Success: ip blacklist cleaned"
    137158msgstr ""
    138159
    139 #: core/CF7_AntiSpam_Rest_Api.php:194
     160#: core/CF7_AntiSpam_Rest_Api.php:267
    140161msgid "Error: unable to clean blacklist. Please refresh and try again!"
    141162msgstr ""
    142163
    143 #: core/CF7_AntiSpam_Rest_Api.php:225
     164#: core/CF7_AntiSpam_Rest_Api.php:298
    144165msgid "b8 dictionary reset successful"
    145166msgstr ""
    146167
    147 #: core/CF7_AntiSpam_Rest_Api.php:232
     168#: core/CF7_AntiSpam_Rest_Api.php:305
    148169msgid ""
    149170"Something goes wrong while deleting b8 dictionary. Please refresh and try "
     
    151172msgstr ""
    152173
    153 #: core/CF7_AntiSpam_Rest_Api.php:263
     174#: core/CF7_AntiSpam_Rest_Api.php:336
    154175msgid ""
    155176"CF7 AntiSpam fully reinitialized with success. You need to rebuild B8 "
     
    157178msgstr ""
    158179
    159 #: core/CF7_AntiSpam_Rest_Api.php:270
     180#: core/CF7_AntiSpam_Rest_Api.php:343
    160181msgid "Ops! something went wrong... Please refresh and try again!"
    161182msgstr ""
    162183
    163 #: core/CF7_AntiSpam_Rest_Api.php:300
     184#: core/CF7_AntiSpam_Rest_Api.php:373
    164185msgid "b8 dictionary rebuild successful"
    165186msgstr ""
    166187
    167 #: core/CF7_AntiSpam_Rest_Api.php:307
     188#: core/CF7_AntiSpam_Rest_Api.php:380
    168189msgid ""
    169190"Something goes wrong while rebuilding b8 dictionary. Please refresh and try "
     
    171192msgstr ""
    172193
    173 #: core/CF7_Antispam_Geoip.php:275
    174 #: core/CF7_Antispam_Geoip.php:290
    175 msgid ""
    176 "Unable to download the geo-ip database, please check that the key provided "
    177 "is correct! "
    178 msgstr ""
    179 
    180 #: core/CF7_Antispam_Geoip.php:310
    181 msgid "GEO-IP Database file decompression failed"
    182 msgstr ""
    183 
    184 #: core/CF7_Antispam_Geoip.php:330
    185 msgid "GEO-IP decompressed database copy failed"
    186 msgstr ""
    187 
    188 #: core/CF7_AntiSpam_Frontend.php:571
     194#: core/CF7_AntiSpam_Rest_Api.php:411
     195#: core/CF7_AntiSpam_Rest_Api.php:462
     196msgid "Invalid ID"
     197msgstr ""
     198
     199# %s is the ip address.
     200#: core/CF7_AntiSpam_Rest_Api.php:424
     201msgid "Success: ip %s unbanned"
     202msgstr ""
     203
     204# %s is the ip address.
     205#: core/CF7_AntiSpam_Rest_Api.php:432
     206msgid "Error: unable to unban %s"
     207msgstr ""
     208
     209#: core/CF7_AntiSpam_Rest_Api.php:497
     210msgid "Blacklist exported successfully"
     211msgstr ""
     212
     213#: core/CF7_Antispam_Geoip.php:407
     214msgid ""
     215"Unable to download the geo-ip database. Please check that the key is "
     216"correct!"
     217msgstr ""
     218
     219#: core/CF7_Antispam_Geoip.php:752
     220msgid "GEO-IP Database extraction failed"
     221msgstr ""
     222
     223#: core/CF7_AntiSpam_Frontend.php:600
    189224msgid "Missing hash."
    190225msgstr ""
    191226
    192 #: core/CF7_AntiSpam_Frontend.php:576
     227#: core/CF7_AntiSpam_Frontend.php:605
    193228msgid "Something went wrong. Please reload the page."
    194229msgstr ""
    195230
    196231# % is the number of seconds to wait
    197 #: core/CF7_AntiSpam_Frontend.php:583
     232#: core/CF7_AntiSpam_Frontend.php:612
    198233msgid "Slow down, please wait %s seconds before resending."
    199234msgstr ""
    200235
    201 #: core/CF7_AntiSpam_Flamingo.php:108
     236#: core/CF7_AntiSpam_Flamingo.php:109
    202237msgid "%s has no message text so can't be analyzed"
    203238msgstr ""
    204239
    205240# %1$s is the mail "from" field (the sender). %2$s spam/ham. %3$s and %4$s the rating of the processed email (like 0.6/1)
    206 #: core/CF7_AntiSpam_Flamingo.php:137
     241#: core/CF7_AntiSpam_Flamingo.php:136
    207242msgid ""
    208243"b8 has learned this e-mail from %1$s was %2$s - score before/after: "
     
    210245msgstr ""
    211246
    212 #: core/CF7_AntiSpam_Flamingo.php:218
     247#: core/CF7_AntiSpam_Flamingo.php:217
    213248msgid "Cannot find the original post"
    214249msgstr ""
    215250
    216 #: core/CF7_AntiSpam_Flamingo.php:293
     251#: core/CF7_AntiSpam_Flamingo.php:272
    217252msgid "Email sent with success"
    218253msgstr ""
    219254
    220 #: core/CF7_AntiSpam_Flamingo.php:296
     255#: core/CF7_AntiSpam_Flamingo.php:275
    221256msgid "Ops! something went wrong... unable to resend email"
    222257msgstr ""
    223258
    224 #: core/CF7_AntiSpam_Flamingo.php:464
     259#: core/CF7_AntiSpam_Flamingo.php:443
    225260msgid "D8 classification"
    226261msgstr ""
    227262
    228 #: core/CF7_AntiSpam_Flamingo.php:465
     263#: core/CF7_AntiSpam_Flamingo.php:444
    229264msgid "CF7-AntiSpam actions"
    230265msgstr ""
    231266
    232 #: core/CF7_AntiSpam_Flamingo.php:507
     267#: core/CF7_AntiSpam_Flamingo.php:486
    233268msgid "Do you want to resend this email?"
    234269msgstr ""
    235270
    236 #: core/CF7_AntiSpam_Flamingo.php:508
     271#: core/CF7_AntiSpam_Flamingo.php:487
    237272msgid "Resend Email"
    238273msgstr ""
    239274
    240 #: core/CF7_AntiSpam.php:271
     275# the %1$s is the user id and %2$s is the ip address.
     276#: core/CF7_Antispam_Blacklist.php:209
     277msgid "Ban forever id %1$s (ip %2$s) successful"
     278msgstr ""
     279
     280# the %1$s is the user id and %2$s is the ip address.
     281#: core/CF7_Antispam_Blacklist.php:219
     282msgid "Error: unable to ban forever id %1$s (ip %2$s)"
     283msgstr ""
     284
     285#: core/CF7_AntiSpam.php:282
    241286msgid "CF7 AntiSpam need "
    242287msgstr ""
    243288
    244 #: core/CF7_AntiSpam.php:273
     289#: core/CF7_AntiSpam.php:284
    245290msgid "Contact Form 7"
    246291msgstr ""
    247292
    248 #: core/CF7_AntiSpam.php:274
     293#: core/CF7_AntiSpam.php:285
    249294msgid " installed and enabled in order to work."
    250295msgstr ""
    251296
    252297# %1$s overall spam attempts, %2$s since last report
    253 #: core/CF7_AntiSpam.php:393
     298#: core/CF7_AntiSpam.php:406
    254299msgid "%1$s overall spam attempts, %2$s since last report"
    255 msgstr ""
    256 
    257 #: admin/CF7_AntiSpam_Admin_Tools.php:80
    258 msgid "Success: ip %s unbanned"
    259 msgstr ""
    260 
    261 #: admin/CF7_AntiSpam_Admin_Tools.php:83
    262 msgid "Error: unable to unban %s"
    263 msgstr ""
    264 
    265 # the %1$s is the user id and %2$s is the ip address.
    266 #: admin/CF7_AntiSpam_Admin_Tools.php:107
    267 msgid "Ban forever id %1$s (ip %2$s) successful"
    268 msgstr ""
    269 
    270 # the %1$s is the user id and %2$s is the ip address.
    271 #: admin/CF7_AntiSpam_Admin_Tools.php:116
    272 msgid "Error: unable to ban forever id %1$s (ip %2$s)"
    273300msgstr ""
    274301
     
    297324msgstr ""
    298325
    299 #: admin/CF7_AntiSpam_Admin_Display.php:147
     326#: admin/CF7_AntiSpam_Admin_Display.php:159
    300327msgid "Dismiss"
    301328msgstr ""
    302329
    303 #: admin/CF7_AntiSpam_Admin_Display.php:150
     330#: admin/CF7_AntiSpam_Admin_Display.php:162
    304331msgid "Before you cry over spilt mail&#8230;"
    305332msgstr ""
    306333
    307 #: admin/CF7_AntiSpam_Admin_Display.php:151
     334#: admin/CF7_AntiSpam_Admin_Display.php:163
    308335msgid ""
    309336"Contact Form 7 doesn&#8217;t store submitted messages anywhere. Therefore, "
     
    313340
    314341# %s: link labeled 'Flamingo'
    315 #: admin/CF7_AntiSpam_Admin_Display.php:156
     342#: admin/CF7_AntiSpam_Admin_Display.php:168
    316343msgid ""
    317344"Install a message storage plugin before this happens to you. %s saves all "
     
    320347msgstr ""
    321348
    322 #: admin/CF7_AntiSpam_Admin_Display.php:157
     349#: admin/CF7_AntiSpam_Admin_Display.php:169
    323350msgid "Flamingo"
    324351msgstr ""
    325352
    326 #: admin/CF7_AntiSpam_Admin_Display.php:164
     353#: admin/CF7_AntiSpam_Admin_Display.php:176
    327354msgid "PLEASE don't forget to add "
    328355msgstr ""
    329356
    330 #: admin/CF7_AntiSpam_Admin_Display.php:165
     357#: admin/CF7_AntiSpam_Admin_Display.php:177
    331358msgid "flamingo_message: \"[your-message]\" "
    332359msgstr ""
    333360
    334 #: admin/CF7_AntiSpam_Admin_Display.php:170
     361#: admin/CF7_AntiSpam_Admin_Display.php:182
    335362msgid "Please replace "
    336363msgstr ""
    337364
    338 #: admin/CF7_AntiSpam_Admin_Display.php:172
     365#: admin/CF7_AntiSpam_Admin_Display.php:184
    339366msgid ""
    340367"with the message field used in your form because that is the field scanned "
     
    342369msgstr ""
    343370
    344 #: admin/CF7_AntiSpam_Admin_Display.php:173
     371#: admin/CF7_AntiSpam_Admin_Display.php:185
    345372msgid "additional settings section"
    346373msgstr ""
    347374
    348 #: admin/CF7_AntiSpam_Admin_Display.php:174
     375#: admin/CF7_AntiSpam_Admin_Display.php:186
    349376msgid "to enable the most advanced protection we can offer! Thank you!"
    350377msgstr ""
    351378
    352 #: admin/CF7_AntiSpam_Admin_Display.php:186
     379#: admin/CF7_AntiSpam_Admin_Display.php:198
    353380msgid "Email Statistics"
    354381msgstr ""
    355382
    356 #: admin/CF7_AntiSpam_Admin_Display.php:307
     383#: admin/CF7_AntiSpam_Admin_Display.php:345
    357384msgid "Warning Count Ranges"
    358385msgstr ""
    359386
    360 #: admin/CF7_AntiSpam_Admin_Display.php:311
     387#: admin/CF7_AntiSpam_Admin_Display.php:349
    361388msgid "Total Blocked IPs"
    362389msgstr ""
    363390
    364 #: admin/CF7_AntiSpam_Admin_Display.php:325
     391#: admin/CF7_AntiSpam_Admin_Display.php:363
    365392msgid "No warning data available"
    366393msgstr ""
    367394
    368 #: admin/CF7_AntiSpam_Admin_Display.php:332
     395#: admin/CF7_AntiSpam_Admin_Display.php:370
    369396msgid "B8 Wordlist"
    370397msgstr ""
    371398
    372 #: admin/CF7_AntiSpam_Admin_Display.php:337
     399#: admin/CF7_AntiSpam_Admin_Display.php:375
    373400msgid "Top Spam Words"
    374401msgstr ""
    375402
    376 #: admin/CF7_AntiSpam_Admin_Display.php:348
     403#: admin/CF7_AntiSpam_Admin_Display.php:386
    377404msgid "No spam words available"
    378405msgstr ""
    379406
    380 #: admin/CF7_AntiSpam_Admin_Display.php:354
     407#: admin/CF7_AntiSpam_Admin_Display.php:392
    381408msgid "Top Ham Words"
    382409msgstr ""
    383410
    384 #: admin/CF7_AntiSpam_Admin_Display.php:365
     411#: admin/CF7_AntiSpam_Admin_Display.php:403
    385412msgid "No ham words available"
    386413msgstr ""
    387414
    388 #: admin/CF7_AntiSpam_Admin_Display.php:374
     415#: admin/CF7_AntiSpam_Admin_Display.php:412
    389416msgid "Top Block Reasons"
    390417msgstr ""
    391418
    392419# %d is the number of unique reasons
    393 #: admin/CF7_AntiSpam_Admin_Display.php:394
     420#: admin/CF7_AntiSpam_Admin_Display.php:432
    394421msgid "Total unique reasons: %d"
    395422msgstr ""
    396423
    397 #: admin/CF7_AntiSpam_Admin_Display.php:406
     424#: admin/CF7_AntiSpam_Admin_Display.php:444
    398425msgid "No reason data available"
    399426msgstr ""
    400427
    401 #: admin/CF7_AntiSpam_Admin_Display.php:451
     428#: admin/CF7_AntiSpam_Admin_Display.php:489
    402429msgid "Do you know,that you can save settings simply using the shortcut [Ctrl + S]."
    403430msgstr ""
    404431
    405 #: admin/CF7_AntiSpam_Admin_Display.php:452
     432#: admin/CF7_AntiSpam_Admin_Display.php:490
    406433msgid ""
    407434"In the CF7-Antispam settings page you can enter values in textarea using "
     
    410437msgstr ""
    411438
    412 #: admin/CF7_AntiSpam_Admin_Display.php:456
     439#: admin/CF7_AntiSpam_Admin_Display.php:494
    413440msgid ""
    414441"It is always a good practice to NOT name \"contact\" the slug of the page "
     
    416443msgstr ""
    417444
    418 #: admin/CF7_AntiSpam_Admin_Display.php:457
     445#: admin/CF7_AntiSpam_Admin_Display.php:495
    419446msgid "contacts"
    420447msgstr ""
    421448
    422 #: admin/CF7_AntiSpam_Admin_Display.php:458
     449#: admin/CF7_AntiSpam_Admin_Display.php:496
    423450msgid "Give a try"
    424451msgstr ""
    425452
    426 #: admin/CF7_AntiSpam_Admin_Display.php:463
     453#: admin/CF7_AntiSpam_Admin_Display.php:501
    427454msgid "As Flamingo also CF7-Antispam can handle"
    428455msgstr ""
    429456
    430 #: admin/CF7_AntiSpam_Admin_Display.php:465
     457#: admin/CF7_AntiSpam_Admin_Display.php:503
    431458msgid "fields with multiple tags"
    432459msgstr ""
    433460
    434 #: admin/CF7_AntiSpam_Admin_Display.php:466
     461#: admin/CF7_AntiSpam_Admin_Display.php:504
    435462msgid ""
    436463"In this way, you can scan as a message multiple fields at once (subject "
     
    438465msgstr ""
    439466
    440 #: admin/CF7_AntiSpam_Admin_Display.php:486
     467#: admin/CF7_AntiSpam_Admin_Display.php:524
    441468msgid "Tip:"
    442469msgstr ""
    443470
    444 #: admin/CF7_AntiSpam_Admin_Display.php:500
     471#: admin/CF7_AntiSpam_Admin_Display.php:538
    445472msgid "Plugin Settings"
    446473msgstr ""
    447474
    448 #: admin/CF7_AntiSpam_Admin_Display.php:525
     475#: admin/CF7_AntiSpam_Admin_Display.php:555
    449476msgid "Export blacklist"
    450477msgstr ""
    451478
    452 #: admin/CF7_AntiSpam_Admin_Display.php:528
     479#: admin/CF7_AntiSpam_Admin_Display.php:566
    453480msgid "Blacklisted IPs"
    454481msgstr ""
    455482
    456 #: admin/CF7_AntiSpam_Admin_Display.php:529
     483#: admin/CF7_AntiSpam_Admin_Display.php:567
    457484msgid "Here you can see all the IPs that have been blacklisted by the plugin."
    458485msgstr ""
    459486
    460 #: admin/CF7_AntiSpam_Admin_Display.php:541
     487#: admin/CF7_AntiSpam_Admin_Display.php:579
    461488msgid "Export/Import Options"
    462489msgstr ""
    463490
    464 #: admin/CF7_AntiSpam_Admin_Display.php:553
     491#: admin/CF7_AntiSpam_Admin_Display.php:591
    465492msgid "Advanced Tools"
    466493msgstr ""
    467494
    468 #: admin/CF7_AntiSpam_Admin_Display.php:554
     495#: admin/CF7_AntiSpam_Admin_Display.php:592
    469496msgid ""
    470497"This section contains features that completely change what is stored in the "
     
    472499msgstr ""
    473500
    474 #: admin/CF7_AntiSpam_Admin_Display.php:568
     501#: admin/CF7_AntiSpam_Admin_Display.php:606
     502#: admin/CF7_AntiSpam_Admin_Display.php:608
     503msgid "Update Database"
     504msgstr ""
     505
     506#: admin/CF7_AntiSpam_Admin_Display.php:607
     507msgid ""
     508"If something has gone wrong during updates, you can perform a forced "
     509"database and options update."
     510msgstr ""
     511
     512#: admin/CF7_AntiSpam_Admin_Display.php:611
    475513msgid "Danger Zone"
    476514msgstr ""
    477515
    478 #: admin/CF7_AntiSpam_Admin_Display.php:569
     516#: admin/CF7_AntiSpam_Admin_Display.php:612
    479517msgid ""
    480518"These actions are irreversible. Please make sure you know what you are "
     
    482520msgstr ""
    483521
    484 #: admin/CF7_AntiSpam_Admin_Display.php:571
     522#: admin/CF7_AntiSpam_Admin_Display.php:614
    485523msgid "Blacklist Reset"
    486524msgstr ""
    487525
    488 #: admin/CF7_AntiSpam_Admin_Display.php:572
     526#: admin/CF7_AntiSpam_Admin_Display.php:615
    489527msgid "Remove all blacklisted IPs from the database."
    490528msgstr ""
    491529
    492 #: admin/CF7_AntiSpam_Admin_Display.php:573
     530#: admin/CF7_AntiSpam_Admin_Display.php:616
    493531msgid "Remove all blacklisted IP"
    494532msgstr ""
    495533
    496 #: admin/CF7_AntiSpam_Admin_Display.php:575
     534#: admin/CF7_AntiSpam_Admin_Display.php:618
    497535msgid "Dictionary Reset"
    498536msgstr ""
    499537
    500 #: admin/CF7_AntiSpam_Admin_Display.php:576
     538#: admin/CF7_AntiSpam_Admin_Display.php:619
    501539msgid "Reset the entire b8 dictionary used for spam detection."
    502540msgstr ""
    503541
    504 #: admin/CF7_AntiSpam_Admin_Display.php:577
     542#: admin/CF7_AntiSpam_Admin_Display.php:620
    505543msgid "Reset b8 dictionary"
    506544msgstr ""
    507545
    508 #: admin/CF7_AntiSpam_Admin_Display.php:579
     546#: admin/CF7_AntiSpam_Admin_Display.php:622
    509547msgid "Rebuild Dictionary"
    510548msgstr ""
    511549
    512 #: admin/CF7_AntiSpam_Admin_Display.php:580
     550#: admin/CF7_AntiSpam_Admin_Display.php:623
    513551msgid "Reanalyze all Flamingo inbound emails to rebuild the dictionary."
    514552msgstr ""
    515553
    516 #: admin/CF7_AntiSpam_Admin_Display.php:581
     554#: admin/CF7_AntiSpam_Admin_Display.php:624
    517555msgid "Rebuild b8 dictionary"
    518556msgstr ""
    519557
    520 #: admin/CF7_AntiSpam_Admin_Display.php:583
     558#: admin/CF7_AntiSpam_Admin_Display.php:626
    521559msgid "Full Reset"
    522560msgstr ""
    523561
    524 #: admin/CF7_AntiSpam_Admin_Display.php:584
     562#: admin/CF7_AntiSpam_Admin_Display.php:627
    525563msgid "Completely reset the plugin to its initial state."
    526564msgstr ""
    527565
    528 #: admin/CF7_AntiSpam_Admin_Display.php:585
     566#: admin/CF7_AntiSpam_Admin_Display.php:628
    529567msgid "Are you sure? This will reset the plugin to its initial state."
    530568msgstr ""
    531569
    532 #: admin/CF7_AntiSpam_Admin_Display.php:585
     570#: admin/CF7_AntiSpam_Admin_Display.php:628
    533571msgid "FULL RESET"
    534572msgstr ""
    535573
    536 #: admin/CF7_AntiSpam_Admin_Display.php:605
     574#: admin/CF7_AntiSpam_Admin_Display.php:648
    537575msgid "Copy or paste here the settings to import it or export it"
    538576msgstr ""
    539577
    540 #: admin/CF7_AntiSpam_Admin_Display.php:622
     578#: admin/CF7_AntiSpam_Admin_Display.php:665
    541579msgid "Debug Information"
    542580msgstr ""
    543581
    544 #: admin/CF7_AntiSpam_Admin_Display.php:623
     582#: admin/CF7_AntiSpam_Admin_Display.php:666
    545583msgid ""
    546584"Debug information is only visible when WP_DEBUG or CF7ANTISPAM_DEBUG are "
     
    548586msgstr ""
    549587
    550 #: admin/CF7_AntiSpam_Admin_Display.php:653
     588#: admin/CF7_AntiSpam_Admin_Display.php:696
    551589msgid "[unban ip]"
    552590msgstr ""
    553591
    554 #: admin/CF7_AntiSpam_Admin_Display.php:655
     592#: admin/CF7_AntiSpam_Admin_Display.php:699
    555593msgid "[ban forever]"
    556594msgstr ""
    557595
     596#: admin/CF7_AntiSpam_Admin_Display.php:701
     597msgid "First seen on"
     598msgstr ""
     599
    558600# %d is the number of blacklisted IPs
    559 #: admin/CF7_AntiSpam_Admin_Display.php:679
     601#: admin/CF7_AntiSpam_Admin_Display.php:730
    560602msgid "Showing %d blacklisted IPs"
    561603msgstr ""
    562604
    563 #: admin/CF7_AntiSpam_Admin_Display.php:684
     605#: admin/CF7_AntiSpam_Admin_Display.php:735
    564606msgid "No blacklisted IPs found."
    565607msgstr ""
    566608
    567 #: admin/CF7_AntiSpam_Admin_Display.php:707
    568 #: admin/CF7_AntiSpam_Admin_Display.php:714
     609#: admin/CF7_AntiSpam_Admin_Display.php:758
     610#: admin/CF7_AntiSpam_Admin_Display.php:765
    569611msgid "is enabled"
    570612msgstr ""
    571613
    572 #: admin/CF7_AntiSpam_Admin_Display.php:719
     614#: admin/CF7_AntiSpam_Admin_Display.php:770
    573615msgid "Your ip address"
    574616msgstr ""
    575617
    576 #: admin/CF7_AntiSpam_Admin_Display.php:725
     618#: admin/CF7_AntiSpam_Admin_Display.php:776
    577619msgid "is disabled, use CF7ANTISPAM_DEBUG_EXTENDED to enable it if needed"
    578620msgstr ""
    579621
    580 #: admin/CF7_AntiSpam_Admin_Display.php:741
    581 #: admin/CF7_AntiSpam_Admin_Display.php:750
     622#: admin/CF7_AntiSpam_Admin_Display.php:792
     623#: admin/CF7_AntiSpam_Admin_Display.php:801
    582624msgid "is disabled"
    583625msgstr ""
    584626
    585 #: admin/CF7_AntiSpam_Admin_Display.php:768
     627#: admin/CF7_AntiSpam_Admin_Display.php:819
    586628msgid "Waiting for Rest API Status..."
    587629msgstr ""
    588630
    589 #: admin/CF7_AntiSpam_Admin_Display.php:778
     631#: admin/CF7_AntiSpam_Admin_Display.php:861
    590632msgid "Options debug"
    591633msgstr ""
    592634
    593 #: admin/CF7_AntiSpam_Admin_Display.php:781
     635#: admin/CF7_AntiSpam_Admin_Display.php:864
    594636msgid "The plugin options are:"
    595637msgstr ""
    596638
    597 #: admin/CF7_AntiSpam_Admin_Display.php:815
     639#: admin/CF7_AntiSpam_Admin_Display.php:898
    598640msgid "spam"
    599641msgstr ""
    600642
    601 #: admin/CF7_AntiSpam_Admin_Display.php:815
     643#: admin/CF7_AntiSpam_Admin_Display.php:898
    602644msgid "ham"
    603645msgstr ""
    604646
    605 #: admin/CF7_AntiSpam_Admin_Display.php:823
     647#: admin/CF7_AntiSpam_Admin_Display.php:906
    606648msgid "DNSBL performance test:"
    607649msgstr ""
    608650
    609 #: admin/CF7_AntiSpam_Admin_Display.php:824
     651#: admin/CF7_AntiSpam_Admin_Display.php:907
    610652msgid ""
    611653"Results below 0.01 are fine, OK/Spam indicates the status of your ip on "
     
    613655msgstr ""
    614656
    615 #: admin/CF7_AntiSpam_Admin_Display.php:825
    616 #: admin/CF7_AntiSpam_Admin_Display.php:881
    617 #: admin/CF7_AntiSpam_Admin_Display.php:892
     657#: admin/CF7_AntiSpam_Admin_Display.php:908
     658#: admin/CF7_AntiSpam_Admin_Display.php:964
     659#: admin/CF7_AntiSpam_Admin_Display.php:975
    618660msgid "Your IP address"
    619661msgstr ""
    620662
    621 #: admin/CF7_AntiSpam_Admin_Display.php:848
     663#: admin/CF7_AntiSpam_Admin_Display.php:931
    622664msgid "not set"
    623665msgstr ""
    624666
    625 #: admin/CF7_AntiSpam_Admin_Display.php:860
    626 #: admin/CF7_AntiSpam_Admin_Display.php:903
     667#: admin/CF7_AntiSpam_Admin_Display.php:943
     668#: admin/CF7_AntiSpam_Admin_Display.php:986
    627669msgid "Geo-IP test"
    628670msgstr ""
    629671
    630 #: admin/CF7_AntiSpam_Admin_Display.php:868
    631 #: admin/CF7_AntiSpam_Admin_Display.php:889
     672#: admin/CF7_AntiSpam_Admin_Display.php:951
     673#: admin/CF7_AntiSpam_Admin_Display.php:972
    632674msgid "Geo-IP"
    633675msgstr ""
    634676
    635 #: admin/CF7_AntiSpam_Admin_Display.php:869
     677#: admin/CF7_AntiSpam_Admin_Display.php:952
    636678msgid "Enabled"
    637679msgstr ""
    638680
    639 #: admin/CF7_AntiSpam_Admin_Display.php:869
     681#: admin/CF7_AntiSpam_Admin_Display.php:952
    640682msgid "Geo-ip database next scheduled update: "
    641683msgstr ""
    642684
    643 #: admin/CF7_AntiSpam_Admin_Display.php:890
     685#: admin/CF7_AntiSpam_Admin_Display.php:973
    644686msgid "is disabled."
    645687msgstr ""
    646688
    647 #: admin/CF7_AntiSpam_Admin_Display.php:891
     689#: admin/CF7_AntiSpam_Admin_Display.php:974
    648690msgid ""
    649691"To enable it, please go to the settings page and enable the \"Detect "
     
    651693msgstr ""
    652694
    653 #: admin/CF7_AntiSpam_Admin_Display.php:904
     695#: admin/CF7_AntiSpam_Admin_Display.php:987
    654696msgid "Geo-IP Test Error"
    655697msgstr ""
    656698
    657 #: admin/CF7_AntiSpam_Admin_Customizations.php:46
     699#: admin/CF7_AntiSpam_Admin_Customizations.php:55
    658700msgid "Administrators only"
    659701msgstr ""
    660702
    661 #: admin/CF7_AntiSpam_Admin_Customizations.php:70
     703#: admin/CF7_AntiSpam_Admin_Customizations.php:81
    662704msgid "Ban automatically spammers"
    663705msgstr ""
    664706
    665 #: admin/CF7_AntiSpam_Admin_Customizations.php:78
     707#: admin/CF7_AntiSpam_Admin_Customizations.php:89
    666708msgid "Automatic spammer IP Blacklist"
    667709msgstr ""
    668710
    669 #: admin/CF7_AntiSpam_Admin_Customizations.php:87
     711#: admin/CF7_AntiSpam_Admin_Customizations.php:98
    670712msgid "Mail blocked before Ban"
    671713msgstr ""
    672714
    673 #: admin/CF7_AntiSpam_Admin_Customizations.php:96
     715#: admin/CF7_AntiSpam_Admin_Customizations.php:107
    674716msgid "Automatic Unban"
    675717msgstr ""
    676718
    677 #: admin/CF7_AntiSpam_Admin_Customizations.php:105
     719#: admin/CF7_AntiSpam_Admin_Customizations.php:116
    678720msgid "Bot Fingerprinting"
    679721msgstr ""
    680722
    681 #: admin/CF7_AntiSpam_Admin_Customizations.php:113
     723#: admin/CF7_AntiSpam_Admin_Customizations.php:124
    682724msgid "Enable anti-bot checks"
    683725msgstr ""
    684726
    685 #: admin/CF7_AntiSpam_Admin_Customizations.php:122
     727#: admin/CF7_AntiSpam_Admin_Customizations.php:133
    686728msgid "Enable anti-bot extra checks"
    687729msgstr ""
    688730
    689 #: admin/CF7_AntiSpam_Admin_Customizations.php:131
     731#: admin/CF7_AntiSpam_Admin_Customizations.php:142
    690732msgid "Append hidden fields on submit"
    691733msgstr ""
    692734
    693 #: admin/CF7_AntiSpam_Admin_Customizations.php:140
     735#: admin/CF7_AntiSpam_Admin_Customizations.php:151
    694736msgid "GeoIP"
    695737msgstr ""
    696738
    697 #: admin/CF7_AntiSpam_Admin_Customizations.php:148
     739#: admin/CF7_AntiSpam_Admin_Customizations.php:159
    698740msgid "Enable automatic download"
    699741msgstr ""
    700742
    701 #: admin/CF7_AntiSpam_Admin_Customizations.php:157
     743#: admin/CF7_AntiSpam_Admin_Customizations.php:171
     744msgid "MaxMind Update Key"
     745msgstr ""
     746
     747#: admin/CF7_AntiSpam_Admin_Customizations.php:181
     748msgid "Force database download"
     749msgstr ""
     750
     751#: admin/CF7_AntiSpam_Admin_Customizations.php:192
     752msgid "Database manual upload"
     753msgstr ""
     754
     755#: admin/CF7_AntiSpam_Admin_Customizations.php:202
    702756msgid "Database available"
    703757msgstr ""
    704758
    705 #: admin/CF7_AntiSpam_Admin_Customizations.php:169
    706 msgid "MaxMind Update Key"
    707 msgstr ""
    708 
    709 #: admin/CF7_AntiSpam_Admin_Customizations.php:178
     759#: admin/CF7_AntiSpam_Admin_Customizations.php:211
    710760msgid "Language Checks"
    711761msgstr ""
    712762
    713 #: admin/CF7_AntiSpam_Admin_Customizations.php:186
     763#: admin/CF7_AntiSpam_Admin_Customizations.php:219
    714764msgid "Check Browser Language"
    715765msgstr ""
    716766
    717 #: admin/CF7_AntiSpam_Admin_Customizations.php:195
     767#: admin/CF7_AntiSpam_Admin_Customizations.php:228
    718768msgid "Detect location using GeoIP"
    719769msgstr ""
    720770
    721 #: admin/CF7_AntiSpam_Admin_Customizations.php:204
     771#: admin/CF7_AntiSpam_Admin_Customizations.php:237
    722772msgid "Allowed browser Languages"
    723773msgstr ""
    724774
    725 #: admin/CF7_AntiSpam_Admin_Customizations.php:213
     775#: admin/CF7_AntiSpam_Admin_Customizations.php:246
    726776msgid "Disallowed browser Languages"
    727777msgstr ""
    728778
    729 #: admin/CF7_AntiSpam_Admin_Customizations.php:222
     779#: admin/CF7_AntiSpam_Admin_Customizations.php:255
    730780msgid "Time checks"
    731781msgstr ""
    732782
    733 #: admin/CF7_AntiSpam_Admin_Customizations.php:230
     783#: admin/CF7_AntiSpam_Admin_Customizations.php:263
    734784msgid "Check the elapsed time"
    735785msgstr ""
    736786
    737 #: admin/CF7_AntiSpam_Admin_Customizations.php:239
     787#: admin/CF7_AntiSpam_Admin_Customizations.php:272
    738788msgid "Minimum elapsed time"
    739789msgstr ""
    740790
    741 #: admin/CF7_AntiSpam_Admin_Customizations.php:248
     791#: admin/CF7_AntiSpam_Admin_Customizations.php:281
    742792msgid "Maximum elapsed time"
    743793msgstr ""
    744794
    745 #: admin/CF7_AntiSpam_Admin_Customizations.php:257
     795#: admin/CF7_AntiSpam_Admin_Customizations.php:290
    746796msgid "Bad IP Address"
    747797msgstr ""
    748798
    749 #: admin/CF7_AntiSpam_Admin_Customizations.php:265
     799#: admin/CF7_AntiSpam_Admin_Customizations.php:298
    750800msgid "Check HTTP referrer"
    751801msgstr ""
    752802
    753 #: admin/CF7_AntiSpam_Admin_Customizations.php:274
     803#: admin/CF7_AntiSpam_Admin_Customizations.php:307
    754804msgid "Check Bad IP Address"
    755805msgstr ""
    756806
    757 #: admin/CF7_AntiSpam_Admin_Customizations.php:283
     807#: admin/CF7_AntiSpam_Admin_Customizations.php:316
    758808msgid "Bad IP Address List"
    759809msgstr ""
    760810
    761 #: admin/CF7_AntiSpam_Admin_Customizations.php:292
     811#: admin/CF7_AntiSpam_Admin_Customizations.php:325
    762812msgid "IP Whitelist"
    763813msgstr ""
    764814
    765 #: admin/CF7_AntiSpam_Admin_Customizations.php:301
     815#: admin/CF7_AntiSpam_Admin_Customizations.php:334
    766816msgid "Bad words"
    767817msgstr ""
    768818
    769 #: admin/CF7_AntiSpam_Admin_Customizations.php:309
     819#: admin/CF7_AntiSpam_Admin_Customizations.php:342
    770820msgid "Check the message for prohibited words"
    771821msgstr ""
    772822
    773 #: admin/CF7_AntiSpam_Admin_Customizations.php:318
     823#: admin/CF7_AntiSpam_Admin_Customizations.php:351
    774824msgid "Bad words List"
    775825msgstr ""
    776826
    777 #: admin/CF7_AntiSpam_Admin_Customizations.php:327
     827#: admin/CF7_AntiSpam_Admin_Customizations.php:360
    778828msgid "Bad email strings"
    779829msgstr ""
    780830
    781 #: admin/CF7_AntiSpam_Admin_Customizations.php:335
     831#: admin/CF7_AntiSpam_Admin_Customizations.php:368
    782832msgid "Check the email for prohibited words"
    783833msgstr ""
    784834
    785 #: admin/CF7_AntiSpam_Admin_Customizations.php:344
     835#: admin/CF7_AntiSpam_Admin_Customizations.php:377
    786836msgid "Email prohibited words"
    787837msgstr ""
    788838
    789 #: admin/CF7_AntiSpam_Admin_Customizations.php:353
     839#: admin/CF7_AntiSpam_Admin_Customizations.php:386
    790840msgid "User Agent blacklist"
    791841msgstr ""
    792842
    793 #: admin/CF7_AntiSpam_Admin_Customizations.php:361
     843#: admin/CF7_AntiSpam_Admin_Customizations.php:394
    794844msgid "Enable User Agent blacklist"
    795845msgstr ""
    796846
    797 #: admin/CF7_AntiSpam_Admin_Customizations.php:370
     847#: admin/CF7_AntiSpam_Admin_Customizations.php:403
    798848msgid "Disallowed user agents"
    799849msgstr ""
    800850
    801 #: admin/CF7_AntiSpam_Admin_Customizations.php:379
     851#: admin/CF7_AntiSpam_Admin_Customizations.php:412
    802852msgid "DNS Blacklists"
    803853msgstr ""
    804854
    805 #: admin/CF7_AntiSpam_Admin_Customizations.php:387
     855#: admin/CF7_AntiSpam_Admin_Customizations.php:420
    806856msgid "Check IP on DNS blocklist"
    807857msgstr ""
    808858
    809 #: admin/CF7_AntiSpam_Admin_Customizations.php:396
     859#: admin/CF7_AntiSpam_Admin_Customizations.php:429
    810860msgid "DNS blocklist servers"
    811861msgstr ""
    812862
    813 #: admin/CF7_AntiSpam_Admin_Customizations.php:405
     863#: admin/CF7_AntiSpam_Admin_Customizations.php:438
    814864msgid "Honeypot"
    815865msgstr ""
    816866
    817 #: admin/CF7_AntiSpam_Admin_Customizations.php:413
     867#: admin/CF7_AntiSpam_Admin_Customizations.php:446
    818868msgid "Add some fake input inside the form"
    819869msgstr ""
    820870
    821 #: admin/CF7_AntiSpam_Admin_Customizations.php:422
     871#: admin/CF7_AntiSpam_Admin_Customizations.php:455
    822872msgid "Name for the honeypots inputs[*]"
    823873msgstr ""
    824874
    825 #: admin/CF7_AntiSpam_Admin_Customizations.php:431
     875#: admin/CF7_AntiSpam_Admin_Customizations.php:464
    826876msgid "Honeyform <span class=\"label alert monospace\">[experimental]</span>"
    827877msgstr ""
    828878
    829 #: admin/CF7_AntiSpam_Admin_Customizations.php:439
     879#: admin/CF7_AntiSpam_Admin_Customizations.php:472
    830880msgid "Add an hidden form inside the page content"
    831881msgstr ""
    832882
    833 #: admin/CF7_AntiSpam_Admin_Customizations.php:448
     883#: admin/CF7_AntiSpam_Admin_Customizations.php:481
    834884msgid "Select where the honeyform will be placed"
    835885msgstr ""
    836886
    837 #: admin/CF7_AntiSpam_Admin_Customizations.php:457
     887#: admin/CF7_AntiSpam_Admin_Customizations.php:490
    838888msgid "Exclude pages"
    839889msgstr ""
    840890
    841 #: admin/CF7_AntiSpam_Admin_Customizations.php:466
     891#: admin/CF7_AntiSpam_Admin_Customizations.php:499
    842892msgid "Mailbox Protection"
    843893msgstr ""
    844894
    845 #: admin/CF7_AntiSpam_Admin_Customizations.php:474
     895#: admin/CF7_AntiSpam_Admin_Customizations.php:507
    846896msgid "Avoid multiple send"
    847897msgstr ""
    848898
    849 #: admin/CF7_AntiSpam_Admin_Customizations.php:483
     899#: admin/CF7_AntiSpam_Admin_Customizations.php:516
    850900msgid "Identity Protection"
    851901msgstr ""
    852902
    853 #: admin/CF7_AntiSpam_Admin_Customizations.php:491
     903#: admin/CF7_AntiSpam_Admin_Customizations.php:524
    854904msgid "Enforce user protection"
    855905msgstr ""
    856906
    857 #: admin/CF7_AntiSpam_Admin_Customizations.php:500
     907#: admin/CF7_AntiSpam_Admin_Customizations.php:533
    858908msgid "Enforce WordPress protection"
    859909msgstr ""
    860910
    861 #: admin/CF7_AntiSpam_Admin_Customizations.php:509
     911#: admin/CF7_AntiSpam_Admin_Customizations.php:542
    862912msgid "B8 statistical \"Bayesian\" spam filter"
    863913msgstr ""
    864914
    865 #: admin/CF7_AntiSpam_Admin_Customizations.php:517
     915#: admin/CF7_AntiSpam_Admin_Customizations.php:550
    866916msgid "Enable B8"
    867917msgstr ""
    868918
    869 #: admin/CF7_AntiSpam_Admin_Customizations.php:526
     919#: admin/CF7_AntiSpam_Admin_Customizations.php:559
    870920msgid "B8 spam threshold"
    871921msgstr ""
    872922
    873 #: admin/CF7_AntiSpam_Admin_Customizations.php:535
     923#: admin/CF7_AntiSpam_Admin_Customizations.php:568
    874924msgid "Spam filter customizations"
    875925msgstr ""
    876926
    877 #: admin/CF7_AntiSpam_Admin_Customizations.php:543
     927#: admin/CF7_AntiSpam_Admin_Customizations.php:576
     928msgid "Your unique css class"
     929msgstr ""
     930
     931#: admin/CF7_AntiSpam_Admin_Customizations.php:585
     932msgid "Your unique fields prefix"
     933msgstr ""
     934
     935#: admin/CF7_AntiSpam_Admin_Customizations.php:594
     936msgid "The encryption method"
     937msgstr ""
     938
     939#: admin/CF7_AntiSpam_Admin_Customizations.php:603
     940msgid "Optimizations"
     941msgstr ""
     942
     943#: admin/CF7_AntiSpam_Admin_Customizations.php:611
     944msgid "Optimize scripts loading"
     945msgstr ""
     946
     947#: admin/CF7_AntiSpam_Admin_Customizations.php:620
    878948msgid "Disable cf7 form reload if the page is cached"
    879949msgstr ""
    880950
    881 #: admin/CF7_AntiSpam_Admin_Customizations.php:552
    882 msgid "Your unique css class"
    883 msgstr ""
    884 
    885 #: admin/CF7_AntiSpam_Admin_Customizations.php:561
    886 msgid "Your unique fields prefix"
    887 msgstr ""
    888 
    889 #: admin/CF7_AntiSpam_Admin_Customizations.php:570
    890 msgid "The encryption method"
    891 msgstr ""
    892 
    893 #: admin/CF7_AntiSpam_Admin_Customizations.php:579
     951#: admin/CF7_AntiSpam_Admin_Customizations.php:629
    894952msgid "Spam Score Rating"
    895953msgstr ""
    896954
    897 #: admin/CF7_AntiSpam_Admin_Customizations.php:587
     955#: admin/CF7_AntiSpam_Admin_Customizations.php:637
    898956msgid "Anti-spam control level"
    899957msgstr ""
    900958
    901 #: admin/CF7_AntiSpam_Admin_Customizations.php:596
     959#: admin/CF7_AntiSpam_Admin_Customizations.php:646
    902960msgid "Enable advanced settings"
    903961msgstr ""
    904962
    905 #: admin/CF7_AntiSpam_Admin_Customizations.php:605
     963#: admin/CF7_AntiSpam_Admin_Customizations.php:655
    906964msgid "Scoring Tweaks (1 = Ban)"
    907965msgstr ""
    908966
    909 #: admin/CF7_AntiSpam_Admin_Customizations.php:613
     967#: admin/CF7_AntiSpam_Admin_Customizations.php:663
    910968msgid "Bot fingerprinting score <small>(for each failed test)</small>"
    911969msgstr ""
    912970
    913 #: admin/CF7_AntiSpam_Admin_Customizations.php:622
     971#: admin/CF7_AntiSpam_Admin_Customizations.php:672
    914972msgid "Time checks score"
    915973msgstr ""
    916974
    917 #: admin/CF7_AntiSpam_Admin_Customizations.php:631
     975#: admin/CF7_AntiSpam_Admin_Customizations.php:681
    918976msgid "String found"
    919977msgstr ""
    920978
    921 #: admin/CF7_AntiSpam_Admin_Customizations.php:640
     979#: admin/CF7_AntiSpam_Admin_Customizations.php:690
    922980msgid "DNSBL score <small>(for each server)</small>"
    923981msgstr ""
    924982
    925 #: admin/CF7_AntiSpam_Admin_Customizations.php:649
     983#: admin/CF7_AntiSpam_Admin_Customizations.php:699
    926984msgid "Honeypot fill score <small>(for each fail)</small>"
    927985msgstr ""
    928986
    929 #: admin/CF7_AntiSpam_Admin_Customizations.php:658
     987#: admin/CF7_AntiSpam_Admin_Customizations.php:708
    930988msgid "Bot detected"
    931989msgstr ""
    932990
    933 #: admin/CF7_AntiSpam_Admin_Customizations.php:667
     991#: admin/CF7_AntiSpam_Admin_Customizations.php:717
    934992msgid "Bot warn"
    935993msgstr ""
    936994
    937 #: admin/CF7_AntiSpam_Admin_Customizations.php:678
     995#: admin/CF7_AntiSpam_Admin_Customizations.php:728
    938996msgid "How many failed attempts before being banned"
    939997msgstr ""
    940998
    941 #: admin/CF7_AntiSpam_Admin_Customizations.php:682
     999#: admin/CF7_AntiSpam_Admin_Customizations.php:733
    9421000msgid "Next scheduled unban event:"
    9431001msgstr ""
    9441002
    945 #: admin/CF7_AntiSpam_Admin_Customizations.php:693
     1003#: admin/CF7_AntiSpam_Admin_Customizations.php:744
    9461004msgid ""
    9471005"Fingerprinting is a method used for exploiting data from browser in order "
     
    9511009msgstr ""
    9521010
    953 #: admin/CF7_AntiSpam_Admin_Customizations.php:694
     1011#: admin/CF7_AntiSpam_Admin_Customizations.php:745
    9541012msgid ""
    9551013"The last option, append on submit, causes fingerprinting to take place "
     
    9581016msgstr ""
    9591017
    960 #: admin/CF7_AntiSpam_Admin_Customizations.php:702
     1018#: admin/CF7_AntiSpam_Admin_Customizations.php:753
    9611019msgid ""
    9621020"Checks that the form has been submitted within a reasonable timeframe, "
     
    9641022msgstr ""
    9651023
    966 #: admin/CF7_AntiSpam_Admin_Customizations.php:703
     1024#: admin/CF7_AntiSpam_Admin_Customizations.php:754
    9671025msgid ""
    9681026"Just set a few seconds as the minimum time (bots usually take 5 seconds at "
     
    9701028msgstr ""
    9711029
    972 #: admin/CF7_AntiSpam_Admin_Customizations.php:704
     1030#: admin/CF7_AntiSpam_Admin_Customizations.php:755
    9731031msgid ""
    9741032"* A small note.... If you use a caching system for the contact page make "
     
    9771035msgstr ""
    9781036
    979 #: admin/CF7_AntiSpam_Admin_Customizations.php:705
     1037#: admin/CF7_AntiSpam_Admin_Customizations.php:756
    9801038msgid "Values in seconds, 0 to disable"
    9811039msgstr ""
    9821040
    983 #: admin/CF7_AntiSpam_Admin_Customizations.php:713
     1041#: admin/CF7_AntiSpam_Admin_Customizations.php:764
    9841042msgid "Detect user location using MaxMind GeoIP2 database."
    9851043msgstr ""
    9861044
    987 #: admin/CF7_AntiSpam_Admin_Customizations.php:714
     1045#: admin/CF7_AntiSpam_Admin_Customizations.php:765
    9881046msgid "In order to enable this functionality you need to agree at  "
    9891047msgstr ""
    9901048
    991 #: admin/CF7_AntiSpam_Admin_Customizations.php:715
     1049#: admin/CF7_AntiSpam_Admin_Customizations.php:766
    9921050msgid "GeoLite2 End User License Agreement"
    9931051msgstr ""
    9941052
    995 #: admin/CF7_AntiSpam_Admin_Customizations.php:716
     1053#: admin/CF7_AntiSpam_Admin_Customizations.php:767
    9961054msgid "and sign up "
    9971055msgstr ""
    9981056
    999 #: admin/CF7_AntiSpam_Admin_Customizations.php:717
     1057#: admin/CF7_AntiSpam_Admin_Customizations.php:768
    10001058msgid "GeoLite2 Downloadable Databases"
    10011059msgstr ""
    10021060
    1003 #: admin/CF7_AntiSpam_Admin_Customizations.php:718
     1061#: admin/CF7_AntiSpam_Admin_Customizations.php:769
    10041062msgid ""
    10051063"After registration you will get a key, paste it into the input below and "
     
    10081066msgstr ""
    10091067
    1010 #: admin/CF7_AntiSpam_Admin_Customizations.php:724
     1068#: admin/CF7_AntiSpam_Admin_Customizations.php:775
    10111069msgid "Recommended - define a key your config.php the key in this way: "
    10121070msgstr ""
    10131071
    1014 #: admin/CF7_AntiSpam_Admin_Customizations.php:737
     1072#: admin/CF7_AntiSpam_Admin_Customizations.php:788
    10151073msgid ""
    10161074"Check the user browser language / user keyboard. Add a country code / "
     
    10211079msgstr ""
    10221080
    1023 #: admin/CF7_AntiSpam_Admin_Customizations.php:738
     1081#: admin/CF7_AntiSpam_Admin_Customizations.php:789
    10241082msgid ""
    10251083"The browser language detection and country detection are separated, you can "
     
    10271085msgstr ""
    10281086
    1029 #: admin/CF7_AntiSpam_Admin_Customizations.php:739
     1087#: admin/CF7_AntiSpam_Admin_Customizations.php:790
    10301088msgid ""
    10311089"The language detection must be lower case, while the country detection "
     
    10331091msgstr ""
    10341092
    1035 #: admin/CF7_AntiSpam_Admin_Customizations.php:740
     1093#: admin/CF7_AntiSpam_Admin_Customizations.php:791
    10361094msgid "If you are unsure please consult these ISO standards:"
    10371095msgstr ""
    10381096
    1039 #: admin/CF7_AntiSpam_Admin_Customizations.php:741
     1097#: admin/CF7_AntiSpam_Admin_Customizations.php:792
    10401098msgid "- Language codes (use ctrl+f for search) "
    10411099msgstr ""
    10421100
    1043 #: admin/CF7_AntiSpam_Admin_Customizations.php:742
     1101#: admin/CF7_AntiSpam_Admin_Customizations.php:793
    10441102msgid "- Country codes (refer to \"Alpha-2 code\"), "
    10451103msgstr ""
    10461104
    1047 #: admin/CF7_AntiSpam_Admin_Customizations.php:748
     1105#: admin/CF7_AntiSpam_Admin_Customizations.php:799
    10481106msgid ""
    10491107"After an ip check via the http headers, it is checked that the ip is not "
     
    10511109msgstr ""
    10521110
    1053 #: admin/CF7_AntiSpam_Admin_Customizations.php:753
     1111#: admin/CF7_AntiSpam_Admin_Customizations.php:804
    10541112msgid ""
    10551113"Check if the mail message contains \"bad\" words, all e-mails containing "
     
    10571115msgstr ""
    10581116
    1059 #: admin/CF7_AntiSpam_Admin_Customizations.php:758
     1117#: admin/CF7_AntiSpam_Admin_Customizations.php:809
    10601118msgid ""
    10611119"Check if the mail content contains a word and in this case flag this mail, "
     
    10631121msgstr ""
    10641122
    1065 #: admin/CF7_AntiSpam_Admin_Customizations.php:763
     1123#: admin/CF7_AntiSpam_Admin_Customizations.php:814
    10661124msgid ""
    10671125"Enter a list of forbidden user agents, one per line. When the string match "
     
    10691127msgstr ""
    10701128
    1071 #: admin/CF7_AntiSpam_Admin_Customizations.php:768
     1129#: admin/CF7_AntiSpam_Admin_Customizations.php:819
    10721130msgid ""
    10731131"Check sender ip on DNS Blacklists, DNSBL are real-time lists of "
     
    10801138
    10811139# %s%s%s - a spam score of xyz will be added
    1082 #: admin/CF7_AntiSpam_Admin_Customizations.php:770
     1140#: admin/CF7_AntiSpam_Admin_Customizations.php:821
    10831141msgid ""
    10841142"?? Use FEW servers, those you tested reliable, and consider that for each "
     
    10871145
    10881146# %s%s%s - a spam score of xyz will be added
    1089 #: admin/CF7_AntiSpam_Admin_Customizations.php:770
     1147#: admin/CF7_AntiSpam_Admin_Customizations.php:821
    10901148msgid " will be added to the spam rating, 1 equal spam."
    10911149msgstr ""
    10921150
    1093 #: admin/CF7_AntiSpam_Admin_Customizations.php:773
     1151#: admin/CF7_AntiSpam_Admin_Customizations.php:824
    10941152msgid "Here a you can find a list of servers: "
    10951153msgstr ""
    10961154
    1097 #: admin/CF7_AntiSpam_Admin_Customizations.php:783
     1155#: admin/CF7_AntiSpam_Admin_Customizations.php:834
    10981156msgid ""
    10991157"the honeypot is a \"trap\" field that is hidden with css or js from the "
     
    11021160msgstr ""
    11031161
    1104 #: admin/CF7_AntiSpam_Admin_Customizations.php:784
     1162#: admin/CF7_AntiSpam_Admin_Customizations.php:835
    11051163msgid ""
    11061164"Please check the list below because the name MUST differ from the cf7 tag "
     
    11081166msgstr ""
    11091167
    1110 #: admin/CF7_AntiSpam_Admin_Customizations.php:790
     1168#: admin/CF7_AntiSpam_Admin_Customizations.php:841
    11111169msgid ""
    11121170"Instead of relying on trap fields, we utilize honeyforms, that are forms "
     
    11151173msgstr ""
    11161174
    1117 #: admin/CF7_AntiSpam_Admin_Customizations.php:796
     1175#: admin/CF7_AntiSpam_Admin_Customizations.php:847
    11181176msgid ""
    11191177"When activated, this feature prevents consecutive email deliveries to the "
     
    11211179msgstr ""
    11221180
    1123 #: admin/CF7_AntiSpam_Admin_Customizations.php:796
     1181#: admin/CF7_AntiSpam_Admin_Customizations.php:847
    11241182msgid ""
    11251183" seconds has been set as the resend timeout, check the documentation if you "
     
    11271185msgstr ""
    11281186
    1129 #: admin/CF7_AntiSpam_Admin_Customizations.php:801
     1187#: admin/CF7_AntiSpam_Admin_Customizations.php:852
    11301188msgid ""
    11311189"After monitoring and analysing some bots, I noticed that it is necessary to "
     
    11351193msgstr ""
    11361194
    1137 #: admin/CF7_AntiSpam_Admin_Customizations.php:806
     1195#: admin/CF7_AntiSpam_Admin_Customizations.php:857
    11381196msgid ""
    11391197"Tells you whether a text is spam or not, using statistical text analysis of "
     
    11411199msgstr ""
    11421200
    1143 #: admin/CF7_AntiSpam_Admin_Customizations.php:813
    1144 msgid "RECOMMENDED: create your own and unique css class and customized fields name"
    1145 msgstr ""
    1146 
    1147 #: admin/CF7_AntiSpam_Admin_Customizations.php:814
    1148 msgid ""
    1149 "You can also choose in encryption method. But, After changing cypher do a "
    1150 "couple of tests because a small amount of them aren't compatible with the "
    1151 "format of the form data."
    1152 msgstr ""
    1153 
    1154 #: admin/CF7_AntiSpam_Admin_Customizations.php:820
     1201#: admin/CF7_AntiSpam_Admin_Customizations.php:858
     1202msgid ""
     1203"The threshold value is the minimum score required for a text to be "
     1204"considered spam. 1 is spam. 0 is not spam. If the threshold value is too "
     1205"low, you may receive false positives, while if it is too high, you may miss "
     1206"some spam."
     1207msgstr ""
     1208
     1209#: admin/CF7_AntiSpam_Admin_Customizations.php:865
     1210msgid "RECOMMENDED: Site related configuration"
     1211msgstr ""
     1212
     1213#: admin/CF7_AntiSpam_Admin_Customizations.php:866
     1214msgid ""
     1215"create your own and unique css class and customized fields name. "
     1216"Optionally, you can choose in encryption method. But, After changing cypher "
     1217"do a couple of tests because a small amount of them aren't compatible with "
     1218"the format of the form data."
     1219msgstr ""
     1220
     1221#: admin/CF7_AntiSpam_Admin_Customizations.php:872
    11551222msgid ""
    11561223"The calculation system of antispam for contact form 7 works like this: each "
     
    11611228msgstr ""
    11621229
    1163 #: admin/CF7_AntiSpam_Admin_Customizations.php:825
     1230#: admin/CF7_AntiSpam_Admin_Customizations.php:877
    11641231msgid "In this section you will find some advanced settings to manage the database"
    11651232msgstr ""
    11661233
    1167 #: admin/CF7_AntiSpam_Admin_Customizations.php:1350
     1234# %s is the error message
     1235#: admin/CF7_AntiSpam_Admin_Customizations.php:1142
     1236msgid "Error uploading file: %s"
     1237msgstr ""
     1238
     1239#: admin/CF7_AntiSpam_Admin_Customizations.php:1153
     1240msgid "GeoIP database uploaded successfully."
     1241msgstr ""
     1242
     1243#: admin/CF7_AntiSpam_Admin_Customizations.php:1157
     1244msgid "Error processing the uploaded file."
     1245msgstr ""
     1246
     1247#: admin/CF7_AntiSpam_Admin_Customizations.php:1437
     1248msgid "Force Download"
     1249msgstr ""
     1250
     1251#: admin/CF7_AntiSpam_Admin_Customizations.php:1446
     1252msgid "Choose DB File..."
     1253msgstr ""
     1254
     1255#: admin/CF7_AntiSpam_Admin_Customizations.php:1447
     1256msgid "No file selected"
     1257msgstr ""
     1258
     1259#: admin/CF7_AntiSpam_Admin_Customizations.php:1449
     1260msgid "Accepted formats: .mmdb or .tar.gz"
     1261msgstr ""
     1262
     1263#: admin/CF7_AntiSpam_Admin_Customizations.php:1468
    11681264msgid "KEY provided"
    11691265msgstr ""
    11701266
    1171 #: admin/CF7_AntiSpam_Admin_Customizations.php:1590
     1267#: admin/CF7_AntiSpam_Admin_Customizations.php:1708
    11721268msgid "Add"
    11731269msgstr ""
    11741270
    1175 #: admin/CF7_AntiSpam_Admin_Customizations.php:1592
     1271#: admin/CF7_AntiSpam_Admin_Customizations.php:1710
    11761272msgid "Remove"
    11771273msgstr ""
    11781274
    1179 #: admin/CF7_AntiSpam_Admin_Core.php:100
     1275#: admin/CF7_AntiSpam_Admin_Customizations.php:1794
     1276msgid ""
     1277"You can optimize the loading performance of the antispam scripts. Since "
     1278"optimization is a risky business, we do not recommend enabling this option "
     1279"without trying it first."
     1280msgstr ""
     1281
     1282#: admin/CF7_AntiSpam_Admin_Core.php:99
    11801283msgid "Antispam Settings"
    11811284msgstr ""
    11821285
    1183 #: admin/CF7_AntiSpam_Admin_Core.php:102
     1286#: admin/CF7_AntiSpam_Admin_Core.php:101
    11841287msgid "Activate Contact Form 7 integration"
    11851288msgstr ""
    11861289
    1187 #: admin/CF7_AntiSpam_Admin_Core.php:135
     1290#: admin/CF7_AntiSpam_Admin_Core.php:134
    11881291msgid "Antispam setting updated with success"
    11891292msgstr ""
    11901293
    1191 #: admin/CF7_AntiSpam_Admin_Core.php:200
     1294#: admin/CF7_AntiSpam_Admin_Core.php:199
    11921295msgid "Are you sure?"
    11931296msgstr ""
    11941297
    1195 #: admin/CF7_AntiSpam_Admin_Core.php:227
     1298#: admin/CF7_AntiSpam_Admin_Core.php:226
    11961299msgid "Stats for CF7 Antispam"
    11971300msgstr ""
     
    12131316msgstr ""
    12141317
    1215 #: src/settings/settings.ts:226
     1318#: src/settings/settings.ts:150
    12161319msgid "Status"
    12171320msgstr ""
    12181321
    1219 #: src/settings/settings.ts:226
     1322#: src/settings/settings.ts:150
    12201323msgid "CF7 Antispam plugin version is"
    12211324msgstr ""
    12221325
    1223 #: src/settings/settings.ts:226
     1326#: src/settings/settings.ts:150
    12241327msgid "Request timestamp"
    12251328msgstr ""
  • cf7-antispam/trunk/readme.txt

    r3392568 r3402920  
    55Tested up to: 6.8
    66Requires PHP: 7.4
    7 Stable tag: 0.7.1
     7Stable tag: 0.7.2
    88License: GPLv2 or later
    99License URI: https://www.gnu.org/licenses/gpl-2.0.html
     
    172172
    173173== Changelog ==
     174
     175= 0.7.2 =
     176* Update fallback (thanks for the idea to @lemurnick)
     177* Fix for missing enqueue in some cases (thanks to @ohhcee, @o2xav, @WORX Developer for the feedbacks)
     178* Blacklist filters cleanup
     179* Registers the spam checks individually
     180* Updated encrypt/decrypt function
    174181
    175182= 0.7.1 =
  • cf7-antispam/trunk/vendor/composer/installed.json

    r3392568 r3402920  
    8282            "source": {
    8383                "type": "git",
    84                 "url": "git@github.com:maxmind/GeoIP2-php.git",
     84                "url": "https://github.com/maxmind/GeoIP2-php.git",
    8585                "reference": "6a41d8fbd6b90052bc34dff3b4252d0f88067b23"
    8686            },
     
    131131                "maxmind"
    132132            ],
     133            "support": {
     134                "issues": "https://github.com/maxmind/GeoIP2-php/issues",
     135                "source": "https://github.com/maxmind/GeoIP2-php/tree/v2.13.0"
     136            },
    133137            "install-path": "../geoip2/geoip2"
    134138        },
    135139        {
    136140            "name": "maxmind-db/reader",
    137             "version": "v1.12.1",
    138             "version_normalized": "1.12.1.0",
     141            "version": "v1.13.1",
     142            "version_normalized": "1.13.1.0",
    139143            "source": {
    140144                "type": "git",
    141145                "url": "https://github.com/maxmind/MaxMind-DB-Reader-php.git",
    142                 "reference": "815939e006b7e68062b540ec9e86aaa8be2b6ce4"
    143             },
    144             "dist": {
    145                 "type": "zip",
    146                 "url": "https://api.github.com/repos/maxmind/MaxMind-DB-Reader-php/zipball/815939e006b7e68062b540ec9e86aaa8be2b6ce4",
    147                 "reference": "815939e006b7e68062b540ec9e86aaa8be2b6ce4",
     146                "reference": "2194f58d0f024ce923e685cdf92af3daf9951908"
     147            },
     148            "dist": {
     149                "type": "zip",
     150                "url": "https://api.github.com/repos/maxmind/MaxMind-DB-Reader-php/zipball/2194f58d0f024ce923e685cdf92af3daf9951908",
     151                "reference": "2194f58d0f024ce923e685cdf92af3daf9951908",
    148152                "shasum": ""
    149153            },
     
    158162                "phpstan/phpstan": "*",
    159163                "phpunit/phpunit": ">=8.0.0,<10.0.0",
    160                 "squizlabs/php_codesniffer": "3.*"
     164                "squizlabs/php_codesniffer": "4.*"
    161165            },
    162166            "suggest": {
    163167                "ext-bcmath": "bcmath or gmp is required for decoding larger integers with the pure PHP decoder",
    164168                "ext-gmp": "bcmath or gmp is required for decoding larger integers with the pure PHP decoder",
    165                 "ext-maxminddb": "A C-based database decoder that provides significantly faster lookups"
    166             },
    167             "time": "2025-05-05T20:56:32+00:00",
     169                "ext-maxminddb": "A C-based database decoder that provides significantly faster lookups",
     170                "maxmind-db/reader-ext": "C extension for significantly faster IP lookups (install via PIE: pie install maxmind-db/reader-ext)"
     171            },
     172            "time": "2025-11-21T22:24:26+00:00",
    168173            "type": "library",
    169174            "installation-source": "dist",
     
    195200            "support": {
    196201                "issues": "https://github.com/maxmind/MaxMind-DB-Reader-php/issues",
    197                 "source": "https://github.com/maxmind/MaxMind-DB-Reader-php/tree/v1.12.1"
     202                "source": "https://github.com/maxmind/MaxMind-DB-Reader-php/tree/v1.13.1"
    198203            },
    199204            "install-path": "../maxmind-db/reader"
     
    201206        {
    202207            "name": "maxmind/web-service-common",
    203             "version": "v0.10.0",
    204             "version_normalized": "0.10.0.0",
     208            "version": "v0.11.0",
     209            "version_normalized": "0.11.0.0",
    205210            "source": {
    206211                "type": "git",
    207212                "url": "https://github.com/maxmind/web-service-common-php.git",
    208                 "reference": "d7c7c42fc31bff26e0ded73a6e187bcfb193f9c4"
    209             },
    210             "dist": {
    211                 "type": "zip",
    212                 "url": "https://api.github.com/repos/maxmind/web-service-common-php/zipball/d7c7c42fc31bff26e0ded73a6e187bcfb193f9c4",
    213                 "reference": "d7c7c42fc31bff26e0ded73a6e187bcfb193f9c4",
     213                "reference": "5b9e3d3472213361eebdb3ab8879e91b8952091b"
     214            },
     215            "dist": {
     216                "type": "zip",
     217                "url": "https://api.github.com/repos/maxmind/web-service-common-php/zipball/5b9e3d3472213361eebdb3ab8879e91b8952091b",
     218                "reference": "5b9e3d3472213361eebdb3ab8879e91b8952091b",
    214219                "shasum": ""
    215220            },
     
    224229                "phpstan/phpstan": "*",
    225230                "phpunit/phpunit": "^8.0 || ^9.0",
    226                 "squizlabs/php_codesniffer": "3.*"
    227             },
    228             "time": "2024-11-14T23:14:52+00:00",
     231                "squizlabs/php_codesniffer": "4.*"
     232            },
     233            "time": "2025-11-20T18:33:17+00:00",
    229234            "type": "library",
    230235            "installation-source": "dist",
     
    249254            "support": {
    250255                "issues": "https://github.com/maxmind/web-service-common-php/issues",
    251                 "source": "https://github.com/maxmind/web-service-common-php/tree/v0.10.0"
     256                "source": "https://github.com/maxmind/web-service-common-php/tree/v0.11.0"
    252257            },
    253258            "install-path": "../maxmind/web-service-common"
  • cf7-antispam/trunk/vendor/composer/installed.php

    r3392568 r3402920  
    22    'root' => array(
    33        'name' => 'codekraft/contactform7-antispam',
    4         'pretty_version' => 'dev-main',
    5         'version' => 'dev-main',
    6         'reference' => 'b64f90abe05a7345358c22c91e8c3f2fb5e90656',
     4        'pretty_version' => '0.7.2',
     5        'version' => '0.7.2.0',
     6        'reference' => null,
    77        'type' => 'wordpress-plugin',
    88        'install_path' => __DIR__ . '/../../',
     
    1212    'versions' => array(
    1313        'codekraft/contactform7-antispam' => array(
    14             'pretty_version' => 'dev-main',
    15             'version' => 'dev-main',
    16             'reference' => 'b64f90abe05a7345358c22c91e8c3f2fb5e90656',
     14            'pretty_version' => '0.7.2',
     15            'version' => '0.7.2.0',
     16            'reference' => null,
    1717            'type' => 'wordpress-plugin',
    1818            'install_path' => __DIR__ . '/../../',
     
    3939        ),
    4040        'maxmind-db/reader' => array(
    41             'pretty_version' => 'v1.12.1',
    42             'version' => '1.12.1.0',
    43             'reference' => '815939e006b7e68062b540ec9e86aaa8be2b6ce4',
     41            'pretty_version' => 'v1.13.1',
     42            'version' => '1.13.1.0',
     43            'reference' => '2194f58d0f024ce923e685cdf92af3daf9951908',
    4444            'type' => 'library',
    4545            'install_path' => __DIR__ . '/../maxmind-db/reader',
     
    4848        ),
    4949        'maxmind/web-service-common' => array(
    50             'pretty_version' => 'v0.10.0',
    51             'version' => '0.10.0.0',
    52             'reference' => 'd7c7c42fc31bff26e0ded73a6e187bcfb193f9c4',
     50            'pretty_version' => 'v0.11.0',
     51            'version' => '0.11.0.0',
     52            'reference' => '5b9e3d3472213361eebdb3ab8879e91b8952091b',
    5353            'type' => 'library',
    5454            'install_path' => __DIR__ . '/../maxmind/web-service-common',
  • cf7-antispam/trunk/vendor/maxmind-db/reader/CHANGELOG.md

    r3325969 r3402920  
    11CHANGELOG
    22=========
     3
     41.13.1 (2025-11-21)
     5-------------------
     6
     7* First PIE release. No other changes.
     8
     91.13.0 (2025-11-20)
     10-------------------
     11
     12* A redundant `filesize()` call in the reader's constructor was removed.
     13  Pull request by Pavel Djundik. GitHub #189.
    314
    4151.12.1 (2025-05-05)
  • cf7-antispam/trunk/vendor/maxmind-db/reader/README.md

    r3325969 r3402920  
    66format that stores data indexed by IP address subnets (IPv4 or IPv6).
    77
    8 ## Installation (Composer) ##
    9 
    10 We recommend installing this package with [Composer](https://getcomposer.org/).
     8## Installation ##
     9
     10### C Extension (Recommended for Performance) ###
     11
     12For significantly faster IP lookups, we recommend installing the C extension via
     13[PIE](https://github.com/php/pie):
     14
     15```bash
     16pie install maxmind-db/reader-ext
     17```
     18
     19The C extension requires the [libmaxminddb](https://github.com/maxmind/libmaxminddb)
     20C library. See the [installation instructions](https://github.com/maxmind/MaxMind-DB-Reader-php-ext#prerequisites)
     21for your platform.
     22
     23### Pure PHP (No Compilation Required) ###
     24
     25If you prefer not to compile a C extension or need maximum portability, you can
     26install the pure PHP implementation with [Composer](https://getcomposer.org/).
    1127
    1228### Download Composer ###
     
    2541
    2642```
    27 php composer.phar require maxmind-db/reader:~1.0
     43php composer.phar require maxmind-db/reader:^1.13.1
    2844```
    2945
     
    109125you are using an autoloader, no changes to your code should be necessary.
    110126
    111 ### Installing Extension ###
     127### Installing Extension via PIE (Recommended) ###
     128
     129We recommend installing the extension via [PIE](https://github.com/php/pie):
     130
     131```bash
     132pie install maxmind-db/reader-ext
     133```
     134
     135See the [extension repository](https://github.com/maxmind/MaxMind-DB-Reader-php-ext#prerequisites)
     136for prerequisites including libmaxminddb installation instructions.
     137
     138### Installing Extension via PECL (Legacy) ###
    112139
    113140First install [libmaxminddb](https://github.com/maxmind/libmaxminddb) as
     
    115142file](https://github.com/maxmind/libmaxminddb/blob/main/README.md#installing-from-a-tarball).
    116143After successfully installing libmaxmindb, you may install the extension
    117 from [pecl](https://pecl.php.net/package/maxminddb):
     144from [PECL](https://pecl.php.net/package/maxminddb):
    118145
    119146```
    120147pecl install maxminddb
    121148```
     149
     150### Installing Extension from Source ###
    122151
    123152Alternatively, you may install it from the source. To do so, run the following
  • cf7-antispam/trunk/vendor/maxmind-db/reader/composer.json

    r3325969 r3402920  
    1919        "ext-bcmath": "bcmath or gmp is required for decoding larger integers with the pure PHP decoder",
    2020        "ext-gmp": "bcmath or gmp is required for decoding larger integers with the pure PHP decoder",
    21         "ext-maxminddb": "A C-based database decoder that provides significantly faster lookups"
     21        "ext-maxminddb": "A C-based database decoder that provides significantly faster lookups",
     22        "maxmind-db/reader-ext": "C extension for significantly faster IP lookups (install via PIE: pie install maxmind-db/reader-ext)"
    2223    },
    2324    "conflict": {
     
    2728        "friendsofphp/php-cs-fixer": "3.*",
    2829        "phpunit/phpunit": ">=8.0.0,<10.0.0",
    29         "squizlabs/php_codesniffer": "3.*",
     30        "squizlabs/php_codesniffer": "4.*",
    3031        "phpstan/phpstan": "*"
    3132    },
  • cf7-antispam/trunk/vendor/maxmind-db/reader/ext/php_maxminddb.h

    r3325969 r3402920  
    1616#ifndef PHP_MAXMINDDB_H
    1717#define PHP_MAXMINDDB_H 1
    18 #define PHP_MAXMINDDB_VERSION "1.12.1"
     18#define PHP_MAXMINDDB_VERSION "1.13.1"
    1919#define PHP_MAXMINDDB_EXTNAME "maxminddb"
    2020
  • cf7-antispam/trunk/vendor/maxmind-db/reader/package.xml

    r3325969 r3402920  
    1515        <active>yes</active>
    1616    </lead>
    17     <date>2025-05-05</date>
     17    <date>2025-11-21</date>
    1818    <version>
    19         <release>1.12.1</release>
    20         <api>1.12.1</api>
     19        <release>1.13.1</release>
     20        <api>1.13.1</api>
    2121    </version>
    2222    <stability>
     
    2525    </stability>
    2626    <license uri="https://github.com/maxmind/MaxMind-DB-Reader-php/blob/main/LICENSE">Apache License 2.0</license>
    27     <notes>* The C extension now checks that the database metadata lookup was
    28   successful.</notes>
     27    <notes>* First PIE release. No other changes.</notes>
    2928    <contents>
    3029        <dir name="/">
  • cf7-antispam/trunk/vendor/maxmind-db/reader/src/MaxMind/Db/Reader.php

    r3325969 r3402920  
    9595        $this->fileHandle = $fileHandle;
    9696
    97         $fileSize = @filesize($database);
    98         if ($fileSize === false) {
     97        $fstat = fstat($fileHandle);
     98        if ($fstat === false) {
    9999            throw new \UnexpectedValueException(
    100100                "Error determining the size of \"$database\"."
    101101            );
    102102        }
    103         $this->fileSize = $fileSize;
     103        $this->fileSize = $fstat['size'];
    104104
    105105        $start = $this->findMetadataStart($database);
     
    333333    {
    334334        $handle = $this->fileHandle;
    335         $fstat = fstat($handle);
    336         if ($fstat === false) {
    337             throw new InvalidDatabaseException(
    338                 "Error getting file information ($filename)."
    339             );
    340         }
    341         $fileSize = $fstat['size'];
     335        $fileSize = $this->fileSize;
    342336        $marker = self::$METADATA_START_MARKER;
    343337        $markerLength = self::$METADATA_START_MARKER_LENGTH;
  • cf7-antispam/trunk/vendor/maxmind/web-service-common/CHANGELOG.md

    r3325969 r3402920  
    11CHANGELOG
    22=========
     3
     40.11.0 (2025-11-20)
     5-------------------
     6
     7* Type hints have been improved.
    38
    490.10.0 (2024-11-14)
  • cf7-antispam/trunk/vendor/maxmind/web-service-common/README.md

    r3325969 r3402920  
    2121## Copyright and License ##
    2222
    23 This software is Copyright (c) 2015-2024 by MaxMind, Inc.
     23This software is Copyright (c) 2015-2025 by MaxMind, Inc.
    2424
    2525This is free software, licensed under the Apache License, Version 2.0.
  • cf7-antispam/trunk/vendor/maxmind/web-service-common/composer.json

    r3325969 r3402920  
    2121    "friendsofphp/php-cs-fixer": "3.*",
    2222    "phpunit/phpunit": "^8.0 || ^9.0",
    23     "squizlabs/php_codesniffer": "3.*",
     23    "squizlabs/php_codesniffer": "4.*",
    2424    "phpstan/phpstan": "*"
    2525  },
  • cf7-antispam/trunk/vendor/maxmind/web-service-common/src/WebService/Client.php

    r3325969 r3402920  
    112112        }
    113113
    114         $this->caBundle = isset($options['caBundle']) ?
    115             $this->caBundle = $options['caBundle'] : $this->getCaBundle();
     114        $this->caBundle = isset($options['caBundle'])
     115            ? $this->caBundle = $options['caBundle'] : $this->getCaBundle();
    116116
    117117        if (isset($options['connectTimeout'])) {
     
    195195        $curlVersion = curl_version();
    196196
    197         return $this->userAgentPrefix . 'MaxMind-WS-API/' . self::VERSION . ' PHP/' . \PHP_VERSION .
    198            ' curl/' . $curlVersion['version'];
     197        return $this->userAgentPrefix . 'MaxMind-WS-API/' . self::VERSION . ' PHP/' . \PHP_VERSION
     198           . ' curl/' . $curlVersion['version'];
    199199    }
    200200
     
    326326        if ($contentType === null || !strstr($contentType, 'json')) {
    327327            throw new HttpException(
    328                 "Received a $statusCode error for $service with " .
    329                 'the following body: ' . $body,
     328                "Received a $statusCode error for $service with "
     329                . 'the following body: ' . $body,
    330330                $statusCode,
    331331                $this->urlFor($path)
     
    336336        if ($message === null) {
    337337            throw new HttpException(
    338                 "Received a $statusCode error for $service but could " .
    339                 'not decode the response as JSON: '
     338                "Received a $statusCode error for $service but could "
     339                . 'not decode the response as JSON: '
    340340                . $this->jsonErrorDescription() . ' Body: ' . $body,
    341341                $statusCode,
     
    346346        if (!isset($message['code']) || !isset($message['error'])) {
    347347            throw new HttpException(
    348                 'Error response contains JSON but it does not ' .
    349                 'specify code or error keys: ' . $body,
     348                'Error response contains JSON but it does not '
     349                . 'specify code or error keys: ' . $body,
    350350                $statusCode,
    351351                $this->urlFor($path)
     
    453453    {
    454454        throw new HttpException(
    455             'Received an unexpected HTTP status ' .
    456             "($statusCode) for $service",
     455            'Received an unexpected HTTP status '
     456            . "($statusCode) for $service",
    457457            $statusCode,
    458458            $this->urlFor($path)
     
    478478            if ($body !== null && $body !== '') {
    479479                throw new WebServiceException(
    480                     "Received a 204 response for $service along with an " .
    481                     "unexpected HTTP body: $body"
     480                    "Received a 204 response for $service along with an "
     481                    . "unexpected HTTP body: $body"
    482482                );
    483483            }
     
    489489        if ($body === null || $body === '') {
    490490            throw new WebServiceException(
    491                 "Received a 200 response for $service but did not " .
    492                 'receive a HTTP body.'
     491                "Received a 200 response for $service but did not "
     492                . 'receive a HTTP body.'
    493493            );
    494494        }
     
    497497        if ($decodedContent === null) {
    498498            throw new WebServiceException(
    499                 "Received a 200 response for $service but could " .
    500                 'not decode the response as JSON: '
     499                "Received a 200 response for $service but could "
     500                . 'not decode the response as JSON: '
    501501                . $this->jsonErrorDescription() . ' Body: ' . $body
    502502            );
  • cf7-antispam/trunk/vendor/maxmind/web-service-common/src/WebService/Http/CurlRequest.php

    r3325969 r3402920  
    2525
    2626    /**
    27      * @var array<string, mixed>
     27     * @var array{
     28     *     caBundle?: string,
     29     *     connectTimeout: float|int,
     30     *     curlHandle: \CurlHandle,
     31     *     headers: array<int, string>,
     32     *     proxy: string|null,
     33     *     timeout: float|int,
     34     *     userAgent: string
     35     * }
    2836     */
    2937    private $options;
    3038
    3139    /**
    32      * @param array<string, mixed> $options
     40     * @param array{
     41     *     caBundle?: string,
     42     *     connectTimeout: float|int,
     43     *     curlHandle: \CurlHandle,
     44     *     headers: array<int, string>,
     45     *     proxy: string|null,
     46     *     timeout: float|int,
     47     *     userAgent: string
     48     * } $options
    3349     */
    3450    public function __construct(string $url, array $options)
     
    90106        $opts[\CURLOPT_PROXY] = $this->options['proxy'];
    91107
    92         // The defined()s are here as the *_MS opts are not available on older
    93         // cURL versions
    94108        $connectTimeout = $this->options['connectTimeout'];
    95         if (\defined('CURLOPT_CONNECTTIMEOUT_MS')) {
    96             $opts[\CURLOPT_CONNECTTIMEOUT_MS] = ceil($connectTimeout * 1000);
    97         } else {
    98             $opts[\CURLOPT_CONNECTTIMEOUT] = ceil($connectTimeout);
    99         }
     109        $opts[\CURLOPT_CONNECTTIMEOUT_MS] = (int) ceil($connectTimeout * 1000);
    100110
    101111        $timeout = $this->options['timeout'];
    102         if (\defined('CURLOPT_TIMEOUT_MS')) {
    103             $opts[\CURLOPT_TIMEOUT_MS] = ceil($timeout * 1000);
    104         } else {
    105             $opts[\CURLOPT_TIMEOUT] = ceil($timeout);
    106         }
     112        $opts[\CURLOPT_TIMEOUT_MS] = (int) ceil($timeout * 1000);
    107113
    108114        curl_setopt_array($this->ch, $opts);
Note: See TracChangeset for help on using the changeset viewer.