'' . site_url('/?wpcaptcha_unblock=' . $options['global_unblock_key']) . ''));
        } else if ($tool == 'empty_log') {
            self::empty_log(sanitize_text_field($_POST['log']));
            wp_send_json_success();
        } else if ($tool == 'unlock_accesslock') {
            $wpdb->update(
                $wpdb->wpcatcha_accesslocks,
                array(
                    'unlocked' => 1
                ),
                array(
                    'accesslock_ID' => intval($_POST['lock_id'])
                )
            );
            wp_send_json_success(array('id' => $_POST['lock_id']));
        } else if ($tool == 'delete_lock_log') {
            $wpdb->delete(
                $wpdb->wpcatcha_accesslocks,
                array(
                    'accesslock_ID' => intval($_POST['lock_id'])
                )
            );
            wp_send_json_success(array('id' => $_POST['lock_id']));
        } else if ($tool == 'delete_fail_log') {
            $wpdb->delete(
                $wpdb->wpcatcha_login_fails,
                array(
                    'login_attempt_ID' => intval($_POST['fail_id'])
                )
            );
            wp_send_json_success(array('id' => $_POST['fail_id']));
        } else if ($tool == 'wpcaptcha_dismiss_pointer') {
            delete_option(WPCAPTCHA_POINTERS_KEY);
            wp_send_json_success();
        } else if ($tool == 'verify_captcha') {
            $captcha_result = self::verify_captcha($_POST['captcha_type'], $_POST['captcha_site_key'], $_POST['captcha_secret_key'], $_POST['captcha_response']);
            if (is_wp_error($captcha_result)) {
                wp_send_json_error($captcha_result->get_error_message());
            }
            wp_send_json_success();
        } else {
            wp_send_json_error(__('Unknown tool.', 'advanced-google-recaptcha'));
        }
        die();
    } // ajax_run_tool
    /**
     * Get rule row html
     *
     * @return string row HTML
     *
     * @param array $data with rule settings
     */
    static function get_date_time($timestamp)
    {
        $interval = current_time('timestamp') - $timestamp;
        return '' . self::humanTiming($interval, true) . '
' . date('Y/m/d', $timestamp) . ' ' . date('h:i:s A', $timestamp) . '';
    }
    static function verify_captcha($type, $site_key, $secret_key, $response)
    {
        if ($type == 'builtin') {
            if ($response === $_COOKIE['wpcaptcha_captcha']) {
                return true;
            } else {
                return new WP_Error('wpcaptcha_builtin_captcha_failed', __("ERROR: captcha verification failed.
Please try again.", 'advanced-google-recaptcha'));
            }
        } else if ($type == 'recaptchav2') {
            if (!isset($response) || empty($response)) {
                return new WP_Error('wpcaptcha_recaptchav2_not_submitted', __("reCAPTCHA verification failed ", 'advanced-google-recaptcha'));
            } else {
                $response = wp_remote_get('https://www.google.com/recaptcha/api/siteverify?secret=' . $secret_key . '&response=' . $response);
                $response = json_decode($response['body']);
                if ($response->success) {
                    return true;
                } else {
                    return new WP_Error('wpcaptcha_recaptchav2_failed', __("reCAPTCHA verification failed " . (isset($response->{'error-codes'}) ? ': ' . implode(',', $response->{'error-codes'}) : ''), 'advanced-google-recaptcha'));
                }
            }
        } else if ($type == 'recaptchav3') {
            if (!isset($response) || empty($response)) {
                return new WP_Error('wpcaptcha_recaptchav3_not_submitted', __("reCAPTCHA verification failed ", 'advanced-google-recaptcha'));
            } else {
                $response = wp_remote_get('https://www.google.com/recaptcha/api/siteverify?secret=' . $secret_key . '&response=' . $response);
                $response = json_decode($response['body']);
                if ($response->success) {
                    return true;
                } else {
                    return new WP_Error('wpcaptcha_recaptchav2_failed', __("reCAPTCHA verification failed " . (isset($response->{'error-codes'}) ? ': ' . implode(',', $response->{'error-codes'}) : ''), 'advanced-google-recaptcha'));
                }
            }
        } 
    }
    /**
     * Get human readable timestamp like 2 hours ago
     *
     * @return int time
     *
     * @param string timestamp
     */
    static function humanTiming($time)
    {
        $tokens = array(
            31536000 => 'year',
            2592000 => 'month',
            604800 => 'week',
            86400 => 'day',
            3600 => 'hour',
            60 => 'minute',
            1 => 'second'
        );
        if ($time < 1) {
            return 'just now';
        }
        foreach ($tokens as $unit => $text) {
            if ($time < $unit) continue;
            $numberOfUnits = floor($time / $unit);
            return $numberOfUnits . ' ' . $text . (($numberOfUnits > 1) ? 's' : '') . ' ago';
        }
    }
    static function empty_log($log)
    {
        global $wpdb;
        if ($log == 'fails') {
            $wpdb->query('TRUNCATE TABLE ' . $wpdb->wpcatcha_login_fails);
        } else {
            $wpdb->query('TRUNCATE TABLE ' . $wpdb->wpcatcha_accesslocks);
        }
    }
    /**
     * Fetch activity logs and output JSON for datatables
     *
     * @return null
     */
    static function get_locks_logs()
    {
        global $wpdb;
        $aColumns = array('accesslock_ID', 'unlocked', 'accesslock_date', 'release_date', 'reason', 'accesslock_IP');
        $sIndexColumn = "accesslock_ID";
        // paging
        $sLimit = '';
        if (isset($_GET['iDisplayStart']) && $_GET['iDisplayLength'] != '-1') {
            $sLimit = "LIMIT " . intval($_GET['iDisplayStart']) . ", " .
            intval($_GET['iDisplayLength']);
        } // paging
        // ordering
        $sOrder = '';
        if (isset($_GET['iSortCol_0'])) {
            $sOrder = "ORDER BY  ";
            for ($i = 0; $i < intval($_GET['iSortingCols']); $i++) {
                if ($_GET['bSortable_' . intval($_GET['iSortCol_' . $i])] == "true") {
                    $sOrder .= $aColumns[intval($_GET['iSortCol_' . $i])] . " "
                        . ($_GET['sSortDir_' . $i] == 'desc'?'desc':'asc') . ", ";
                }
            }
            $sOrder = substr_replace($sOrder, '', -2);
            if ($sOrder == "ORDER BY") {
                $sOrder = '';
            }
        } // ordering
        // filtering
        $sWhere = '';
        if (isset($_GET['sSearch']) && $_GET['sSearch'] != '') {
            $sWhere = "WHERE (";
            for ($i = 0; $i < count($aColumns); $i++) {
                $sWhere .= $aColumns[$i] . " LIKE '%" . esc_sql($_GET['sSearch']) . "%' OR ";
            }
            $sWhere  = substr_replace($sWhere, '', -3);
            $sWhere .= ')';
        } // filtering
        // individual column filtering
        for ($i = 0; $i < count($aColumns); $i++) {
            if (isset($_GET['bSearchable_' . $i]) && $_GET['bSearchable_' . $i] == "true" && $_GET['sSearch_' . $i] != '') {
                if ($sWhere == '') {
                    $sWhere = "WHERE ";
                } else {
                    $sWhere .= " AND ";
                }
                $sWhere .= $aColumns[$i] . " LIKE '%" . esc_sql($_GET['sSearch_' . $i]) . "%' ";
            }
        } // individual columns
        // build query
        $wpdb->sQuery = "SELECT SQL_CALC_FOUND_ROWS " . str_replace(" , ", " ", implode(", ", $aColumns)) . " FROM " . $wpdb->wpcatcha_accesslocks . " $sWhere $sOrder $sLimit";
        $rResult = $wpdb->get_results($wpdb->sQuery);
        // data set length after filtering
        $wpdb->sQuery = "SELECT FOUND_ROWS()";
        $iFilteredTotal = $wpdb->get_var($wpdb->sQuery);
        // total data set length
        $wpdb->sQuery = "SELECT COUNT(" . $sIndexColumn . ") FROM " . $wpdb->wpcatcha_accesslocks;
        $iTotal = $wpdb->get_var($wpdb->sQuery);
        // construct output
        $output = array(
            "sEcho" => intval(@$_GET['sEcho']),
            "iTotalRecords" => $iTotal,
            "iTotalDisplayRecords" => $iFilteredTotal,
            "aaData" => array()
        );
        foreach ($rResult as $aRow) {
            $row = array();
            $row['DT_RowId'] = $aRow->accesslock_ID;
            if (strtotime($aRow->release_date) < time()) {
                $row['DT_RowClass'] = 'lock_expired';
            }
            for ($i = 0; $i < count($aColumns); $i++) {
                if ($aColumns[$i] == 'unlocked') {
                    $unblocked = $aRow->{$aColumns[$i]};
                    if ($unblocked == 0 && strtotime($aRow->release_date) > time()) {
                        $row[] = '