fuc-new/src/Services/Detect.php
2025-12-30 18:57:14 +08:00

176 lines
6.1 KiB
PHP
Executable File

<?php
declare(strict_types=1);
namespace App\Services;
use App\Models\Config;
use App\Models\DetectBanLog;
use App\Models\DetectLog;
use App\Models\Node;
use App\Models\User;
use App\Services\IM\Telegram;
use App\Utils\Tools;
use GuzzleHttp\Exception\GuzzleException;
use Psr\Http\Client\ClientExceptionInterface;
use Telegram\Bot\Exceptions\TelegramSDKException;
use function file_get_contents;
use function in_array;
use function json_decode;
use function str_replace;
use function strtotime;
use function time;
use const PHP_EOL;
final class Detect
{
/**
* @throws TelegramSDKException
*/
public static function gfw(): void
{
$nodes = (new Node())->where('type', 1)
->where('ipv4', '!=', '127.0.0.1')->where('online', 1)->get();
foreach ($nodes as $node) {
$api_url = str_replace(
['{ip}', '{port}'],
[$node->ipv4, $_ENV['detect_gfw_port']],
$_ENV['detect_gfw_url']
);
$json_tcping = json_decode(file_get_contents($api_url), true);
$result_tcping = $json_tcping['status'] === 'true';
if ($result_tcping && ! $node->gfw_block) {
continue;
}
if (! $result_tcping && ! $node->gfw_block) {
//被墙了
echo '检测到节点 #' . $node->id . ' 被 GFW 封锁' . PHP_EOL;
echo 'Send gfw mail to admin' . PHP_EOL;
// try {
// Notification::notifyAdmin(
// $_ENV['appName'] . '-系统警告',
// '管理员你好,系统发现节点 ' . $node->name . ' 被墙了。'
// );
// } catch (GuzzleException|ClientExceptionInterface|TelegramSDKException $e) {
// echo $e->getMessage() . PHP_EOL;
// }
//
// if (Config::obtain('telegram_node_gfwed')) {
// $notice_text = str_replace(
// '%node_name%',
// $node->name,
// Config::obtain('telegram_node_gfwed_text')
// );
//
// (new Telegram())->send(0, $notice_text);
// }
$node->gfw_block = true;
$node->save();
continue;
}
if ($result_tcping && $node->gfw_block) {
echo '检测到节点 #' . $node->id . ' 被 GFW 解除封锁' . PHP_EOL;
echo 'Send gfw mail to admin' . PHP_EOL;
// try {
// Notification::notifyAdmin(
// $_ENV['appName'] . '-系统提示',
// '管理员你好,系统发现节点 ' . $node->name . ' 溜出墙了。'
// );
// } catch (GuzzleException|ClientExceptionInterface|TelegramSDKException $e) {
// echo $e->getMessage() . PHP_EOL;
// }
//
// if (Config::obtain('telegram_node_ungfwed')) {
// $notice_text = str_replace(
// '%node_name%',
// $node->name,
// Config::obtain('telegram_node_ungfwed_text')
// );
//
// (new Telegram())->send(0, $notice_text);
// }
$node->gfw_block = false;
$node->save();
}
}
}
public static function ban(): void
{
$new_logs = (new DetectLog())->where('status', '=', 0)->orderBy('id')->get();
$user_logs = [];
foreach ($new_logs as $log) {
// 分类各个用户的记录数量
$user_logs[$log->user_id] = 0;
$user_logs[$log->user_id]++;
$log->status = 1;
$log->save();
}
foreach ($user_logs as $userid => $value) {
// 执行封禁
$user = (new User())->find($userid);
if ($user === null) {
continue;
}
if ($user->is_banned === 1 ||
($user->is_admin && $_ENV['auto_detect_ban_allow_admin']) ||
in_array($user->id, $_ENV['auto_detect_ban_allow_users'])) {
continue;
}
$user->all_detect_number += $value;
$user->save();
$last_DetectBanLog = (new DetectBanLog())->where('user_id', $userid)->orderBy('id', 'desc')->first();
$last_all_detect_number = ((int) $last_DetectBanLog?->all_detect_number);
$detect_number = $user->all_detect_number - $last_all_detect_number;
if ($detect_number >= $_ENV['auto_detect_ban_number']) {
$last_detect_ban_time = $user->last_detect_ban_time;
$user->is_banned = 1;
$user->banned_reason = 'DetectBan';
$user->last_detect_ban_time = Tools::toDateTime(time());
$user->save();
$DetectBanLog = new DetectBanLog();
$DetectBanLog->user_id = $user->id;
$DetectBanLog->detect_number = $detect_number;
$DetectBanLog->ban_time = $_ENV['auto_detect_ban_time'];
$DetectBanLog->start_time = strtotime($last_detect_ban_time);
$DetectBanLog->end_time = time();
$DetectBanLog->all_detect_number = $user->all_detect_number;
$DetectBanLog->save();
}
}
echo Tools::toDateTime(time()) . ' 审计封禁检查结束' . PHP_EOL;
// 审计封禁解封
$banned_users = (new User())->where('is_banned', 1)->where('banned_reason', 'DetectBan')->get();
foreach ($banned_users as $user) {
$logs = (new DetectBanLog())->where('user_id', $user->id)->orderBy('id', 'desc')->first();
if ($logs !== null && ($logs->end_time + $logs->ban_time * 60) <= time()) {
$user->is_banned = 0;
$user->banned_reason = '';
$user->save();
}
}
echo Tools::toDateTime(time()) . ' 审计解封检查结束' . PHP_EOL;
}
}