XF 2.2 Борьба со спамом

Версия XenForo
2.2.13

Akvas

Проверенные
Сообщения
79
Реакции
29
Баллы
8,115
Всем привет!
Кто как борется со спамом? Где-то недели полторы-две одолевают спамеры и консервы:
1744647447088.png

Стояли несколько лет вопрос-ответ (периодически менял), но теперь это не работает. Включил гугл-капчу, все равно регаются. Пока включил ручное одобрение + увеличил сроки по хранению ip для сравнения учеток, чтобы проще банить сразу было.
В первую их атаку вовремя зашел на форум, буквально за несколько минут наспамили ссылками на запрещенку около тысячи сообщений, но благо быстро сообразил, что надо лимиты сообщений добавить, чтобы кнопка "спам" снова появилась под сообщениями для быстрой чистки.

п.с. не поленился и зарегался на стопфоруме и добавил api-ключ, чтобы помогать обновлять спам-лист для всех
 
Последнее редактирование:
Связку рамблер-США мой антиспам блокировал активно. И они перепрыгнули на рамблер-Германия
Вчера мой антиспам двоих таки пропустил на регистрации. Хорошо хоть не пропустил их сообщения, потом я уже их забанил руками
Однако, судя по изворотливости это надолго.
 
It Works, а кто-то кидал абузы рамблеру по спаму?
Никто же шевелиться не будет, если ему не указать на проблему.
Два раза писал. Ответили принято и на этом тишина.
Да это проблему и не решит, перепрыгнут на другую почту
 
Последнее редактирование:
Скрипт для поиска и удаления спам-тем, связанных с даркнет-маркетплейсами и кракен
Проверено на версии: 2.3.6


Вдохновился кодом от West14 из данного поста: XF 2.2 - Борьба со спамом и решил переделать и доработать его полностью под свои нужды. Хочу поделиться с сообществом результатом своей работы! Этот скрипт предназначен для поиска и удаления спам-тем, связанных с даркнет-маркетплейсами, таких как «Кракен», на форумах XenForo. Он учитывает ключевые слова и регулярные выражения, позволяет исключать определенные темы и отображает подробную информацию о найденных темах.

Если вы найдете ошибки, баги или недоработки, пожалуйста, пишите в эту тему. Буду поддерживать скрипт новыми обновлениями и доработками. Также приветствуются любые предложения по улучшению функционала!

Ниже приведена подробная инструкция по использованию скрипта, а сам код прикреплен в спойлере. Надеюсь, он будет полезен для вашего форума!

Инструкция по использованию скрипта

1. Размещение скрипта


Создайте PHP-файл с уникальным и непредсказуемым именем (например, spam_cleaner_7x9z3.php), чтобы снизить вероятность его обнаружения посторонними.
Скопируйте код скрипта (приведен в спойлере ниже) в этот файл или скачайте уже готовый файл, но перед этим переименуйте его как указано в пункте "1."
Поместите файл в корневую папку вашего форума XenForo на хостинге (там, где находятся файлы вроде index.php и папка src).

2. Настройка скрипта Перед запуском необходимо настроить несколько параметров в коде скрипта:

Часовой пояс:
  • В коде установлен часовой пояс Asia/Tomsk (+7). Если ваш форум работает в другом часовом поясе, замените его на нужный, например, Europe/Moscow или America/New_York. Список поддерживаемых часовых поясов можно найти в
  • Измените строки:
    PHP:
    date_default_timezone_set('Asia/Tomsk');
    в начале скрипта и внутри блока try.
ID Администратора:
  • Скрипт требует права администратора для удаления тем. Укажите ID администратора вашего форума в строке:
    PHP:
    $adminUser = \XF::finder('XF:User')->where('user_id', 1)->fetchOne();
  • Замените 1 на ID вашего администратора. Найти ID можно в админ-панели XenForo в разделе «Пользователи» или в базе данных в таблице xf_user.
Исключение тем:
  • Чтобы исключить определенные темы из обработки (например, важные темы, которые не должны быть удалены), добавьте их ID в массив $excludeThreadIds:
    PHP:
    $excludeThreadIds = [1, 2, 3, 10, 20];
  • Укажите ID тем через запятую. Например, для исключения тем с ID 250, 1353 и 7777:
    PHP:
    $excludeThreadIds = [250, 1353, 7777];
Ключевые слова и регулярные выражения:
  • Скрипт ищет темы, содержащие определенные ключевые слова или соответствующие регулярным выражениям. Текущий список ключевых слов:
    PHP:
    $spamKeywords = [ 'даркнет', 'darknet', 'kra34.cc', 'kra34.at', 'krn28.click', 'kra27.at', 'kraken', 'darkweb', 'KRaKeN?!' ];
    Вы можете добавить или удалить слова, связанные со спамом на вашем форуме. []Слово kraken обрабатывается особым образом: оно считается спамом только в сочетании с другими ключевыми словами. Список дополнительных слов:
    PHP:
    $secondarySpamKeywords = ['kraken', 'KRAKEN', 'Kraken'];
    Регулярные выражения для поиска спама:
    PHP:
    $spamPatterns = [ '/kra\d{1,2}.(cc|at)/i', // Домены типа kra34.cc, kra27.at '/.onion/i', // Ссылки на даркнет '/[!?@]{2,}/', // Многократные знаки препинания '/[\p{So}]/u' // Нестандартные символы ];
    Вы можете добавить свои регулярные выражения или изменить существующие для более точной фильтрации.

3. Запуск скрипта
  1. Перейдите в браузере по адресу вашего скрипта, например:
    Код:
    https://yourdomain.com/spam_cleaner_7x9z3.php
    Замените yourdomain.com на домен вашего форума и spam_cleaner_7x9z3.php на имя вашего файла.
  2. Скрипт выведет таблицу с найденными темами, которые соответствуют заданным критериям. В таблице отображаются:
    • ID темы
    • Название темы
    • ID пользователя
    • Имя пользователя
    • Статус темы (активна, на модерации, удалена)
    • Первые 50 символов первого сообщения
  3. Проверьте список тем, чтобы убедиться, что в нем нет важных тем. Если такие темы есть, добавьте их ID в $excludeThreadIds и обновите страницу.
4. Удаление тем ВНИМАНИЕ: Темы удаляются физически из базы данных без возможности восстановления и без записи в журналы XenForo. Будьте осторожны!
  1. В таблице отметьте галочками темы, которые хотите удалить, или выберите «Выбрать все» для удаления всех найденных тем.
  2. Нажмите кнопку «Удалить выбранные темы».
  3. После удаления страница обновится, и удаленные темы исчезнут из списка.
  4. Если возникнут ошибки при удалении (например, недостаток прав), они будут отображены на странице.

5. Дополнительная информация
Статистика
:
  • Скрипт показывает общее количество тем и сообщений в базе, а также количество найденных спам-тем.
  • Также отображается текущий часовой пояс и время запуска скрипта.
Пользователи:
  • Внизу страницы выводится список ID пользователей, создавших спам-темы. Это может быть полезно для дальнейшего анализа или блокировки ботов.
Безопасность:
  • Не разглашайте имя файла скрипта и не делитесь ссылкой на него с посторонними.
  • После использования рекомендуется удалить файл с сервера или переместить его в защищенное место.
6. Возможные улучшения
  • Если вы хотите добавить возможность поиска по другим критериям (например, по датам создания тем или по конкретным форумам), напишите в этой теме, и я постараюсь доработать скрипт.
  • Если у вас есть идеи по улучшению интерфейса или функционала, делитесь предложениями!
7. Благодарности

PHP:
<?php

// Устанавливаем часовой пояс Томск (+7) (Вы можете выбрать свой, если нужно)
date_default_timezone_set('Asia/Tomsk');


$dir = __DIR__;
require($dir . '/src/XF.php');

try {
    XF::start($dir);

    // Повторно устанавливаем часовой пояс (Здесь необходимо повторно установить ваш часовой пояс)
    date_default_timezone_set('Asia/Tomsk');

    // Установите права администратора (Укажите Ваш ID администратора на форуме где user_id', 1)
    $adminUser = \XF::finder('XF:User')->where('user_id', 1)->fetchOne();
    if ($adminUser) {
        \XF::setVisitor($adminUser);
    } else {
        throw new \Exception("Не удалось установить пользователя ID=1");
    }

    $excludeThreadIds = [1, 2, 3, 10, 20]; // Исключайте темы здесь по ID через запятую.

    // Ключевые слова для спама (Рекламные маркеры)
    $spamKeywords = [
        'даркнет', 'darknet', 'kra34.cc', 'kra34.at', 'krn28.click', 'kra27.at', 'kraken', 'darkweb', 'KRaKeN?!'
    ];

    $spamPatterns = [
        '/kra\d{1,2}\.(cc|at)/i',
        '/\.onion/i',
        '/[!?\@]{2,}/',
        '/[\p{So}]/u'
    ];
    // Ключевое слово "kraken" проверяем только с другими маркерами
    $secondarySpamKeywords = ['kraken', 'KRAKEN', 'Kraken'];

    $threadsFinder = \XF::finder('XF:Thread')
        ->with(['User', 'FirstPost'])
        ->where('discussion_state', ['visible', 'moderated'])
        ->where('thread_id', '!=', $excludeThreadIds[0])
        ->order('thread_id', 'DESC');

    $keywordConditions = [];
    foreach ($spamKeywords as $keyword) {
        $keywordConditions[] = ['FirstPost.message', 'LIKE', "%$keyword%"];
        $keywordConditions[] = ['title', 'LIKE', "%$keyword%"];
    }

    foreach ($secondarySpamKeywords as $keyword) {
        foreach ($spamKeywords as $additionalKeyword) {
            $keywordConditions[] = [
                ['FirstPost.message', 'LIKE', "%$keyword%"],
                ['FirstPost.message', 'LIKE', "%$additionalKeyword%"]
            ];
            $keywordConditions[] = [
                ['title', 'LIKE', "%$keyword%"],
                ['title', 'LIKE', "%$additionalKeyword%"]
            ];
        }
    }
    if (!empty($keywordConditions)) {
        $threadsFinder = $threadsFinder->whereOr($keywordConditions);
    }

    $sqlQuery = $threadsFinder->getQuery();

    $threads = $threadsFinder->fetch();

    $filteredThreads = [];
    foreach ($threads as $thread) {
        $textToCheck = ($thread->title ?? '') . ' ' . ($thread->FirstPost->message ?? '');
        $isSpam = false;
        foreach ($spamPatterns as $pattern) {
            if (preg_match($pattern, $textToCheck)) {
                $isSpam = true;
                break;
            }
        }
        if ($isSpam) {
            $filteredThreads[$thread->thread_id] = $thread;
        }
    }

    // Подсчёт тем
    $threadCount = count($filteredThreads);

    // Общее количество тем и сообщений
    $totalThreads = \XF::finder('XF:Thread')->total();
    $totalPosts = \XF::finder('XF:Post')->total();

    // Обработка удаления
    $confirmDeletion = \XF::app()->request()->filter('delete_confirm', 'bool');
    $deleteThreadIds = \XF::app()->request()->filter('delete_threads', 'array-uint');
    $errorMessages = [];

    if ($confirmDeletion && !empty($deleteThreadIds)) {
        foreach ($filteredThreads as $thread) {
            if (in_array($thread->thread_id, $deleteThreadIds)) {
                try {
                    $error = '';
                    if ($thread->canDelete($error)) {
                        $thread->delete();
                    } else {
                        $errorMessages[] = "Невозможно удалить тему #{$thread->thread_id}: " . ($error ?: 'Отсутствуют права на удаление');
                    }
                } catch (\Exception $e) {
                    $errorMessages[] = "Ошибка при удалении темы #{$thread->thread_id}: " . $e->getMessage();
                }
            }
        }
        if (empty($errorMessages)) {
            header('Location: ' . $_SERVER['PHP_SELF']);
            exit;
        }
    }

} catch (\Exception $e) {
    $errorMessage = "Критическая ошибка: " . $e->getMessage() . "\nStack trace: " . $e->getTraceAsString();
    $errorMessages[] = $errorMessage;
    http_response_code(500);
}

?>

<!DOCTYPE html>
<html>
<head>
    <title>Управление спам-темами</title>
    <meta charset="UTF-8">
<style>
    body { font-family: Georgia, serif; }
    table { border-collapse: collapse; width: 100%; margin-bottom: 20px; }
    th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
    th { background-color: #f2f2f2; }
    th:nth-child(1), th:nth-child(2), th:nth-child(4), th:nth-child(5) {
        white-space: nowrap;
        width: 100px;
    }
    th:nth-child(3) {
        width: 800px;
        white-space: nowrap;
    }
    .delete-btn { background-color: #ff4444; color: white; padding: 5px 10px; border: none; cursor: pointer; }
    .delete-btn:hover { background-color: #cc0000; }
    .error { color: red; margin-top: 10px; margin-bottom: 10px; }
    .info {
        color: #FF0000;
        margin-top: 10px;
        margin-bottom: 10px;
        border: 2px solid #8B0000;
        border-radius: 5px;
        padding: 10px;
        background-color: #FFF3F3;
        text-align: center;
        font-weight: bold;
    }
    .debug { margin-top: 10px; margin-bottom: 10px; }
    .debug p { margin: 0; }
    .label { color: #FF4500; }
    .value { color: #008000; }
    .warning {
        border: 2px solid #FF0000;
        background-color: #FFF3F3;
        padding: 15px;
        margin-bottom: 20px;
        border-radius: 5px;
    }
    .warning h3 {
        color: #FF0000;
        margin-top: 0;
        font-size: 1.2em;
    }
    .warning p {
        margin: 5px 0;
    }
    .warning ul {
        margin-left: 20px;
        list-style-type: disc;
    }
    .description { margin-bottom: 15px; }
    .description .label { font-weight: bold; }
    h2 {
        text-align: center;
        color: #333333;
    }
    hr {
        border: 0;
        border-top: 1px solid #333333;
        margin: 10px 0;
    }
</style>
</head>
<body>
    <h2>Управление спам-темами форума</h2>
    <hr>
    <div class="description">
        <p><span class="label">Описание:</span><br>Этот инструмент позволяет находить и удалять спам-темы, связанные с даркнет-маркетплейсом «Кракен», содержащие ключевые слова (Например: «даркнет», «darknet», «kra34.cc», «kra34.at», «krn28.click», «kra27.at», «kraken», «darkweb», «KRaKeN?!») в заголовке или первом сообщении. Используйте с осторожностью и не разглашайте доступ к скрипту.</p><hr>
        <p><span class="label">Дополнительная информация:</span><br><b>За идею благодарю:</b> <a href="https://xenforo.info/members/west14.22547/" style="color: #008000;">West14</a>.<br><b>Реализовал:</b> <a href="https://xenforo.info/members/shumasick.64948/" style="color: #8B0000;">Shumasick</a></p>
    </div>
    <hr>

    <?php if (!empty($errorMessages)): ?>
        <div class="error">
            <?php foreach ($errorMessages as $error): ?>
                <p><?= htmlspecialchars($error) ?></p>
            <?php endforeach; ?>
        </div>
    <?php endif; ?>

    <div class="warning">
        <h3>ВНИМАНИЕ</h3>
        <ul>
            <li>Не разглашайте имя или существование этого файла. Доступ к нему должен быть строго ограничен, чтобы предотвратить несанкционированное использование и потенциальные проблемы с безопасностью форума.</li>
        </ul>
    </div>

    <div class="debug">
        <p><b><span class="label">Скрипт запущен: </span><span class="value"><?php
            $date = new DateTime();
            echo $date->format('d.m.Y H:i:s');
        ?></span></b></p>
        <p><b><span class="label">Текущий часовой пояс: </span><span class="value"><?= date_default_timezone_get() ?></span></b></p>
        <p><b><span class="label">Общее количество тем в базе: </span><span class="value"><?= isset($totalThreads) ? $totalThreads : 'Н/Д' ?></span></b></p>
        <p><b><span class="label">Общее количество сообщений в базе: </span><span class="value"><?= isset($totalPosts) ? $totalPosts : 'Н/Д' ?></span></b></p>
        <p><b><span class="label">Найдено тем по критериям: </span><span class="value"><?= $threadCount ?? 'Н/Д' ?></span></b></p>
    </div>

    <?php if (empty($filteredThreads)): ?>
        <div class="info">
            <p>Подходящие темы не найдены.</p>
        </div>
    <?php else: ?>
        <form method="post">
            <table>
                <tr>
                    <th><input type="checkbox" id="selectAll"> Выбрать все</th>
                    <th>ID Темы:</th>
                    <th>Название Темы:</th>
                    <th>ID Пользователя:</th>
                    <th>Пользователь:</th>
                    <th>Статус Темы:</th>
                    <th>Первые 50 символов сообщения</th>
                </tr>
                <?php foreach ($filteredThreads as $thread): ?>
                    <tr>
                        <td><input type="checkbox" name="delete_threads[]" value="<?= $thread->thread_id ?>"></td>
                        <td><?= $thread->thread_id ?></td>
                        <td><?= htmlspecialchars($thread->title) ?></td>
                        <td><?= $thread->user_id ?? 'N/A' ?></td>
                        <td><?= htmlspecialchars($thread->User->username ?? 'Неизвестный пользователь') ?></td>
                        <td><?= $thread->discussion_state === 'moderated' ? 'На модерации' : ($thread->isDeleted() ? 'Удалена' : 'Активна') ?></td>
                        <td><?= htmlspecialchars(substr($thread->FirstPost->message ?? 'Нет сообщения', 0, 50)) . (strlen($thread->FirstPost->message ?? '') > 50 ? '...' : '') ?></td>
                    </tr>
                <?php endforeach; ?>
            </table>

            <input type="hidden" name="delete_confirm" value="1">
            <button type="submit" class="delete-btn">Удалить выбранные темы</button>
        </form>

        <p>Задействованные ID пользователей: <?= implode(', ', array_unique(array_filter(array_column($filteredThreads, 'user_id')))) ?></p>
    <?php endif; ?>

    <script>
        document.getElementById('selectAll')?.addEventListener('change', function(e) {
            document.querySelectorAll('input[name="delete_threads[]"]').forEach(checkbox => {
                checkbox.checked = e.target.checked;
            });
        });
    </script>
</body>
</html>
1752736280252.png
1752736304222.png

1752736086742.png

1752736119091.png

1752736210864.png
 

Вложения

  • DeleteSPAM.rar
    3.9 KB · Просмотры: 2
Последнее редактирование модератором:
Скрипт для поиска и удаления спам-тем, связанных с даркнет-маркетплейсами и кракен
Проверено на версии: 2.3.6


Вдохновился кодом от West14 из данного поста: XF 2.2 - Борьба со спамом и решил переделать и доработать его полностью под свои нужды. Хочу поделиться с сообществом результатом своей работы! Этот скрипт предназначен для поиска и удаления спам-тем, связанных с даркнет-маркетплейсами, таких как «Кракен», на форумах XenForo. Он учитывает ключевые слова и регулярные выражения, позволяет исключать определенные темы и отображает подробную информацию о найденных темах.

Если вы найдете ошибки, баги или недоработки, пожалуйста, пишите в эту тему. Буду поддерживать скрипт новыми обновлениями и доработками. Также приветствуются любые предложения по улучшению функционала!

Ниже приведена подробная инструкция по использованию скрипта, а сам код прикреплен в спойлере. Надеюсь, он будет полезен для вашего форума!

Инструкция по использованию скрипта

1. Размещение скрипта


Создайте PHP-файл с уникальным и непредсказуемым именем (например, spam_cleaner_7x9z3.php), чтобы снизить вероятность его обнаружения посторонними.
Скопируйте код скрипта (приведен в спойлере ниже) в этот файл или скачайте уже готовый файл, но перед этим переименуйте его как указано в пункте "1."
Поместите файл в корневую папку вашего форума XenForo на хостинге (там, где находятся файлы вроде index.php и папка src).

2. Настройка скрипта Перед запуском необходимо настроить несколько параметров в коде скрипта:

Часовой пояс:
  • В коде установлен часовой пояс Asia/Tomsk (+7). Если ваш форум работает в другом часовом поясе, замените его на нужный, например, Europe/Moscow или America/New_York. Список поддерживаемых часовых поясов можно найти в
  • Измените строки:
    PHP:
    date_default_timezone_set('Asia/Tomsk');
    в начале скрипта и внутри блока try.
ID Администратора:
  • Скрипт требует права администратора для удаления тем. Укажите ID администратора вашего форума в строке:
    PHP:
    $adminUser = \XF::finder('XF:User')->where('user_id', 1)->fetchOne();
  • Замените 1 на ID вашего администратора. Найти ID можно в админ-панели XenForo в разделе «Пользователи» или в базе данных в таблице xf_user.
Исключение тем:
  • Чтобы исключить определенные темы из обработки (например, важные темы, которые не должны быть удалены), добавьте их ID в массив $excludeThreadIds:
    PHP:
    $excludeThreadIds = [1, 2, 3, 10, 20];
  • Укажите ID тем через запятую. Например, для исключения тем с ID 250, 1353 и 7777:
    PHP:
    $excludeThreadIds = [250, 1353, 7777];
Ключевые слова и регулярные выражения:
  • Скрипт ищет темы, содержащие определенные ключевые слова или соответствующие регулярным выражениям. Текущий список ключевых слов:
    PHP:
    $spamKeywords = [ 'даркнет', 'darknet', 'kra34.cc', 'kra34.at', 'krn28.click', 'kra27.at', 'kraken', 'darkweb', 'KRaKeN?!' ];
    Вы можете добавить или удалить слова, связанные со спамом на вашем форуме. []Слово kraken обрабатывается особым образом: оно считается спамом только в сочетании с другими ключевыми словами. Список дополнительных слов:
    PHP:
    $secondarySpamKeywords = ['kraken', 'KRAKEN', 'Kraken'];
    Регулярные выражения для поиска спама:
    PHP:
    $spamPatterns = [ '/kra\d{1,2}.(cc|at)/i', // Домены типа kra34.cc, kra27.at '/.onion/i', // Ссылки на даркнет '/[!?@]{2,}/', // Многократные знаки препинания '/[\p{So}]/u' // Нестандартные символы ];
    Вы можете добавить свои регулярные выражения или изменить существующие для более точной фильтрации.

3. Запуск скрипта
  1. Перейдите в браузере по адресу вашего скрипта, например:
    Код:
    https://yourdomain.com/spam_cleaner_7x9z3.php
    Замените yourdomain.com на домен вашего форума и spam_cleaner_7x9z3.php на имя вашего файла.
  2. Скрипт выведет таблицу с найденными темами, которые соответствуют заданным критериям. В таблице отображаются:
    • ID темы
    • Название темы
    • ID пользователя
    • Имя пользователя
    • Статус темы (активна, на модерации, удалена)
    • Первые 50 символов первого сообщения
  3. Проверьте список тем, чтобы убедиться, что в нем нет важных тем. Если такие темы есть, добавьте их ID в $excludeThreadIds и обновите страницу.
4. Удаление тем ВНИМАНИЕ: Темы удаляются физически из базы данных без возможности восстановления и без записи в журналы XenForo. Будьте осторожны!
  1. В таблице отметьте галочками темы, которые хотите удалить, или выберите «Выбрать все» для удаления всех найденных тем.
  2. Нажмите кнопку «Удалить выбранные темы».
  3. После удаления страница обновится, и удаленные темы исчезнут из списка.
  4. Если возникнут ошибки при удалении (например, недостаток прав), они будут отображены на странице.

5. Дополнительная информация
Статистика
:
  • Скрипт показывает общее количество тем и сообщений в базе, а также количество найденных спам-тем.
  • Также отображается текущий часовой пояс и время запуска скрипта.
Пользователи:
  • Внизу страницы выводится список ID пользователей, создавших спам-темы. Это может быть полезно для дальнейшего анализа или блокировки ботов.
Безопасность:
  • Не разглашайте имя файла скрипта и не делитесь ссылкой на него с посторонними.
  • После использования рекомендуется удалить файл с сервера или переместить его в защищенное место.
6. Возможные улучшения
  • Если вы хотите добавить возможность поиска по другим критериям (например, по датам создания тем или по конкретным форумам), напишите в этой теме, и я постараюсь доработать скрипт.
  • Если у вас есть идеи по улучшению интерфейса или функционала, делитесь предложениями!
7. Благодарности

PHP:
<?php

// Устанавливаем часовой пояс Томск (+7) (Вы можете выбрать свой, если нужно)
date_default_timezone_set('Asia/Tomsk');


$dir = __DIR__;
require($dir . '/src/XF.php');

try {
    XF::start($dir);

    // Повторно устанавливаем часовой пояс (Здесь необходимо повторно установить ваш часовой пояс)
    date_default_timezone_set('Asia/Tomsk');

    // Установите права администратора (Укажите Ваш ID администратора на форуме где user_id', 1)
    $adminUser = \XF::finder('XF:User')->where('user_id', 1)->fetchOne();
    if ($adminUser) {
        \XF::setVisitor($adminUser);
    } else {
        throw new \Exception("Не удалось установить пользователя ID=1");
    }

    $excludeThreadIds = [1, 2, 3, 10, 20]; // Исключайте темы здесь по ID через запятую.

    // Ключевые слова для спама (Рекламные маркеры)
    $spamKeywords = [
        'даркнет', 'darknet', 'kra34.cc', 'kra34.at', 'krn28.click', 'kra27.at', 'kraken', 'darkweb', 'KRaKeN?!'
    ];

    $spamPatterns = [
        '/kra\d{1,2}\.(cc|at)/i',
        '/\.onion/i',
        '/[!?\@]{2,}/',
        '/[\p{So}]/u'
    ];
    // Ключевое слово "kraken" проверяем только с другими маркерами
    $secondarySpamKeywords = ['kraken', 'KRAKEN', 'Kraken'];

    $threadsFinder = \XF::finder('XF:Thread')
        ->with(['User', 'FirstPost'])
        ->where('discussion_state', ['visible', 'moderated'])
        ->where('thread_id', '!=', $excludeThreadIds[0])
        ->order('thread_id', 'DESC');

    $keywordConditions = [];
    foreach ($spamKeywords as $keyword) {
        $keywordConditions[] = ['FirstPost.message', 'LIKE', "%$keyword%"];
        $keywordConditions[] = ['title', 'LIKE', "%$keyword%"];
    }

    foreach ($secondarySpamKeywords as $keyword) {
        foreach ($spamKeywords as $additionalKeyword) {
            $keywordConditions[] = [
                ['FirstPost.message', 'LIKE', "%$keyword%"],
                ['FirstPost.message', 'LIKE', "%$additionalKeyword%"]
            ];
            $keywordConditions[] = [
                ['title', 'LIKE', "%$keyword%"],
                ['title', 'LIKE', "%$additionalKeyword%"]
            ];
        }
    }
    if (!empty($keywordConditions)) {
        $threadsFinder = $threadsFinder->whereOr($keywordConditions);
    }

    $sqlQuery = $threadsFinder->getQuery();

    $threads = $threadsFinder->fetch();

    $filteredThreads = [];
    foreach ($threads as $thread) {
        $textToCheck = ($thread->title ?? '') . ' ' . ($thread->FirstPost->message ?? '');
        $isSpam = false;
        foreach ($spamPatterns as $pattern) {
            if (preg_match($pattern, $textToCheck)) {
                $isSpam = true;
                break;
            }
        }
        if ($isSpam) {
            $filteredThreads[$thread->thread_id] = $thread;
        }
    }

    // Подсчёт тем
    $threadCount = count($filteredThreads);

    // Общее количество тем и сообщений
    $totalThreads = \XF::finder('XF:Thread')->total();
    $totalPosts = \XF::finder('XF:Post')->total();

    // Обработка удаления
    $confirmDeletion = \XF::app()->request()->filter('delete_confirm', 'bool');
    $deleteThreadIds = \XF::app()->request()->filter('delete_threads', 'array-uint');
    $errorMessages = [];

    if ($confirmDeletion && !empty($deleteThreadIds)) {
        foreach ($filteredThreads as $thread) {
            if (in_array($thread->thread_id, $deleteThreadIds)) {
                try {
                    $error = '';
                    if ($thread->canDelete($error)) {
                        $thread->delete();
                    } else {
                        $errorMessages[] = "Невозможно удалить тему #{$thread->thread_id}: " . ($error ?: 'Отсутствуют права на удаление');
                    }
                } catch (\Exception $e) {
                    $errorMessages[] = "Ошибка при удалении темы #{$thread->thread_id}: " . $e->getMessage();
                }
            }
        }
        if (empty($errorMessages)) {
            header('Location: ' . $_SERVER['PHP_SELF']);
            exit;
        }
    }

} catch (\Exception $e) {
    $errorMessage = "Критическая ошибка: " . $e->getMessage() . "\nStack trace: " . $e->getTraceAsString();
    $errorMessages[] = $errorMessage;
    http_response_code(500);
}

?>

<!DOCTYPE html>
<html>
<head>
    <title>Управление спам-темами</title>
    <meta charset="UTF-8">
<style>
    body { font-family: Georgia, serif; }
    table { border-collapse: collapse; width: 100%; margin-bottom: 20px; }
    th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
    th { background-color: #f2f2f2; }
    th:nth-child(1), th:nth-child(2), th:nth-child(4), th:nth-child(5) {
        white-space: nowrap;
        width: 100px;
    }
    th:nth-child(3) {
        width: 800px;
        white-space: nowrap;
    }
    .delete-btn { background-color: #ff4444; color: white; padding: 5px 10px; border: none; cursor: pointer; }
    .delete-btn:hover { background-color: #cc0000; }
    .error { color: red; margin-top: 10px; margin-bottom: 10px; }
    .info {
        color: #FF0000;
        margin-top: 10px;
        margin-bottom: 10px;
        border: 2px solid #8B0000;
        border-radius: 5px;
        padding: 10px;
        background-color: #FFF3F3;
        text-align: center;
        font-weight: bold;
    }
    .debug { margin-top: 10px; margin-bottom: 10px; }
    .debug p { margin: 0; }
    .label { color: #FF4500; }
    .value { color: #008000; }
    .warning {
        border: 2px solid #FF0000;
        background-color: #FFF3F3;
        padding: 15px;
        margin-bottom: 20px;
        border-radius: 5px;
    }
    .warning h3 {
        color: #FF0000;
        margin-top: 0;
        font-size: 1.2em;
    }
    .warning p {
        margin: 5px 0;
    }
    .warning ul {
        margin-left: 20px;
        list-style-type: disc;
    }
    .description { margin-bottom: 15px; }
    .description .label { font-weight: bold; }
    h2 {
        text-align: center;
        color: #333333;
    }
    hr {
        border: 0;
        border-top: 1px solid #333333;
        margin: 10px 0;
    }
</style>
</head>
<body>
    <h2>Управление спам-темами форума</h2>
    <hr>
    <div class="description">
        <p><span class="label">Описание:</span><br>Этот инструмент позволяет находить и удалять спам-темы, связанные с даркнет-маркетплейсом «Кракен», содержащие ключевые слова (Например: «даркнет», «darknet», «kra34.cc», «kra34.at», «krn28.click», «kra27.at», «kraken», «darkweb», «KRaKeN?!») в заголовке или первом сообщении. Используйте с осторожностью и не разглашайте доступ к скрипту.</p><hr>
        <p><span class="label">Дополнительная информация:</span><br><b>За идею благодарю:</b> <a href="https://xenforo.info/members/west14.22547/" style="color: #008000;">West14</a>.<br><b>Реализовал:</b> <a href="https://xenforo.info/members/shumasick.64948/" style="color: #8B0000;">Shumasick</a></p>
    </div>
    <hr>

    <?php if (!empty($errorMessages)): ?>
        <div class="error">
            <?php foreach ($errorMessages as $error): ?>
                <p><?= htmlspecialchars($error) ?></p>
            <?php endforeach; ?>
        </div>
    <?php endif; ?>

    <div class="warning">
        <h3>ВНИМАНИЕ</h3>
        <ul>
            <li>Не разглашайте имя или существование этого файла. Доступ к нему должен быть строго ограничен, чтобы предотвратить несанкционированное использование и потенциальные проблемы с безопасностью форума.</li>
        </ul>
    </div>

    <div class="debug">
        <p><b><span class="label">Скрипт запущен: </span><span class="value"><?php
            $date = new DateTime();
            echo $date->format('d.m.Y H:i:s');
        ?></span></b></p>
        <p><b><span class="label">Текущий часовой пояс: </span><span class="value"><?= date_default_timezone_get() ?></span></b></p>
        <p><b><span class="label">Общее количество тем в базе: </span><span class="value"><?= isset($totalThreads) ? $totalThreads : 'Н/Д' ?></span></b></p>
        <p><b><span class="label">Общее количество сообщений в базе: </span><span class="value"><?= isset($totalPosts) ? $totalPosts : 'Н/Д' ?></span></b></p>
        <p><b><span class="label">Найдено тем по критериям: </span><span class="value"><?= $threadCount ?? 'Н/Д' ?></span></b></p>
    </div>

    <?php if (empty($filteredThreads)): ?>
        <div class="info">
            <p>Подходящие темы не найдены.</p>
        </div>
    <?php else: ?>
        <form method="post">
            <table>
                <tr>
                    <th><input type="checkbox" id="selectAll"> Выбрать все</th>
                    <th>ID Темы:</th>
                    <th>Название Темы:</th>
                    <th>ID Пользователя:</th>
                    <th>Пользователь:</th>
                    <th>Статус Темы:</th>
                    <th>Первые 50 символов сообщения</th>
                </tr>
                <?php foreach ($filteredThreads as $thread): ?>
                    <tr>
                        <td><input type="checkbox" name="delete_threads[]" value="<?= $thread->thread_id ?>"></td>
                        <td><?= $thread->thread_id ?></td>
                        <td><?= htmlspecialchars($thread->title) ?></td>
                        <td><?= $thread->user_id ?? 'N/A' ?></td>
                        <td><?= htmlspecialchars($thread->User->username ?? 'Неизвестный пользователь') ?></td>
                        <td><?= $thread->discussion_state === 'moderated' ? 'На модерации' : ($thread->isDeleted() ? 'Удалена' : 'Активна') ?></td>
                        <td><?= htmlspecialchars(substr($thread->FirstPost->message ?? 'Нет сообщения', 0, 50)) . (strlen($thread->FirstPost->message ?? '') > 50 ? '...' : '') ?></td>
                    </tr>
                <?php endforeach; ?>
            </table>

            <input type="hidden" name="delete_confirm" value="1">
            <button type="submit" class="delete-btn">Удалить выбранные темы</button>
        </form>

        <p>Задействованные ID пользователей: <?= implode(', ', array_unique(array_filter(array_column($filteredThreads, 'user_id')))) ?></p>
    <?php endif; ?>

    <script>
        document.getElementById('selectAll')?.addEventListener('change', function(e) {
            document.querySelectorAll('input[name="delete_threads[]"]').forEach(checkbox => {
                checkbox.checked = e.target.checked;
            });
        });
    </script>
</body>
</html>
А зачем так заморачиваться? Я вписываю через настройки спам фразы "Кракен" и подобные. Все посты автоматом уходят на ручную проверку. Затем достаточно 1 сообщение выделить в проверке спама, и нажать очистка спама. Все посты удаляются от чела, а не один. К примеру бот оставил 20 тем на модерации. Ставлю галку на одной теме "Очистка спама" и удаляются все темы этого бота и он в бан улетает. Плюс в настройках установил, чтобы темы удалялись физически сразу после очистки спама.


Но если честно, щас просто Рамблер заблокировал на регистрацию. Тишина пока что уже неделю.
 
Последнее редактирование:
А зачем так заморачиваться? Я вписываю через настройки спам фразы "Кракен" и подобные.
Ну это наверно когда бот пролез и уже требуется срочно чистить форум
А не отлавливать все его темы и сообщения вручную
Я на одном форуме наблюдал, бот очень плодовитый. За час 360 тем наклепал. Я так понял там в настройках перерыв между сообщениями 10сек. Он по полной это и использовал. По разным разделам форума. Представь потом это все чистить
 
А зачем так заморачиваться?
Я сделал это чисто для себя, но решил поделиться со всеми, вдруг кому-то поможет. Я недавно только начал изучать XF и, например, до сих пор не знаю как ограничить почту rambler из регистрации.
 
Только что, зарегился чел как всегда с рамблера, и несмотря на включенный Антиспам, накидал за 10 минут, 70 сообщений с видоизмененным словом Кракен, конечно что-то антиспам запретил, а потом каким-то образом его сообщения попали на форум. Заблокировал рамблер, посмотрим что дальше будет.

На другой мой форум три месяца назад была атака Кракена, после чего кто-то из доброжелатей тут же отправил письма регистратору домена и хостеру. Те заблокировали сразу и домен и хостинг. Написал регистратору, разблокировали, написал на хостинг, аналогично, на форуме временно отменил вообще регистрацию, только ручной вариант. Захожу на следующий день, снова все в Кракене, они короче оказывается отложили личинки заблаговременно, что бы если их заблочат, с них спамить.
Так что аккуратней, проблема конечно массовая, интересно что на офф. форуме ксенфоро, прилетает им такое? Плохо, что механизмы очень примитивные.
 
Последнее редактирование:
Заблокировал рамблер, посмотрим что дальше будет.
Я тоже сдалась... отключила нафиг регистрацию всех с Рамблера. Регистрация у меня без одобрения, т.к. не так часто захожу... но поставила проверку самого первого сообщения всем. Никто не пройдёт теперь 🤣 даже консервы. Была одна попытка озабоченного Кракеном... не смог зарегистрироваться, вот попробовал как гость оставить коммент... но потерпел неудачу... больше не беспокоят мой форум.
 
Вот не зря чищу учетные записи без постов и не входившие больше чем 6 месяцев. Пока только один раз прорвались с level-app.cc. А так пытаются по три учетки зарегистрировать в день.
 
Последнее редактирование:
Может кто подскажет, где-то у нас есть журнал, попыток зарегится с неудачным финалом, хочется посмотреть, что дает моя блокировка рамблера.
И мне интересно, почему сообщения от спамера все же проскочили на форум? Может доработать? Может они название пишут то кириллицей, то латинскими? Или прописывать еще и название сайта который они лепят повсюду? kra34.cc и kra34.at? С другой стороны они завтра еще зеркал наоткрывают.

*Kraken *kraken Kraken kraken *КРАКЕН *Кракен *кракен КРАКЕН Кракен кракен
 
Последнее редактирование:
Может кто подскажет, где-то у нас есть журнал, попыток зарегится с неудачным финалом, хочется посмотреть, что дает моя блокировка рамблера.
Журналы
Журнал срабатываний антиспама
 
Современный облачный хостинг провайдер | Aéza
Назад
Сверху Снизу