assertUserLoggedIn(); $this->assertPermission('openvk\Web\Models\Entities\TicketReply', 'write', 0); $targetDir = __DIR__ . '/../Models/Entities/'; $mode = in_array($this->queryParam("act"), ["form", "templates", "rollback", "reports"]) ? $this->queryParam("act") : "form"; if ($mode === "form") { $this->template->_template = "NoSpam/Index"; $this->template->disable_ajax = 1; $foundClasses = []; foreach (Finder::findFiles('*.php')->from($targetDir) as $file) { $content = file_get_contents($file->getPathname()); $namespacePattern = '/namespace\s+([^\s;]+)/'; $classPattern = '/class\s+([^\s{]+)/'; preg_match($namespacePattern, $content, $namespaceMatches); preg_match($classPattern, $content, $classMatches); if (isset($namespaceMatches[1]) && isset($classMatches[1])) { $classNamespace = trim($namespaceMatches[1]); $className = trim($classMatches[1]); $fullClassName = $classNamespace . '\\' . $className; if ($classNamespace === NoSpamPresenter::ENTITIES_NAMESPACE && class_exists($fullClassName)) { $foundClasses[] = $className; } } } $models = []; foreach ($foundClasses as $class) { $r = new \ReflectionClass(NoSpamPresenter::ENTITIES_NAMESPACE . "\\$class"); if (!$r->isAbstract() && $r->getName() !== NoSpamPresenter::ENTITIES_NAMESPACE . "\\Correspondence") $models[] = $class; } $this->template->models = $models; } else if ($mode === "templates") { $this->template->_template = "NoSpam/Templates.xml"; $this->template->disable_ajax = 1; $filter = []; if ($this->queryParam("id")) { $filter["id"] = (int)$this->queryParam("id"); } $this->template->templates = iterator_to_array((new NoSpamLogs)->getList($filter)); } else if ($mode === "reports") { $this->redirect("/scumfeed"); } else { $template = (new NoSpamLogs)->get((int)$this->postParam("id")); if (!$template || $template->isRollbacked()) $this->returnJson(["success" => false, "error" => "Шаблон не найден"]); $model = NoSpamPresenter::ENTITIES_NAMESPACE . "\\" . $template->getModel(); $items = $template->getItems(); if (count($items) > 0) { $db = DatabaseConnection::i()->getContext(); $unbanned_ids = []; foreach ($items as $_item) { try { $item = new $model; $table_name = $item->getTableName(); $item = $db->table($table_name)->get((int)$_item); if (!$item) continue; $item = new $model($item); if (key_exists("deleted", $item->unwrap()) && $item->isDeleted()) { $item->setDeleted(0); $item->save(); } if (in_array($template->getTypeRaw(), [2, 3])) { $owner = NULL; $methods = ["getOwner", "getUser", "getRecipient", "getInitiator"]; if (method_exists($item, "ban")) { $owner = $item; } else { foreach ($methods as $method) { if (method_exists($item, $method)) { $owner = $item->$method(); break; } } } $_id = ($owner instanceof Club ? $owner->getId() * -1 : $owner->getId()); if (!in_array($_id, $unbanned_ids)) { $owner->unban($this->user->id); $unbanned_ids[] = $_id; } } } catch (\Throwable $e) { $this->returnJson(["success" => false, "error" => $e->getMessage()]); } } } else { $this->returnJson(["success" => false, "error" => "Объекты не найдены"]); } $template->setRollback(true); $template->save(); $this->returnJson(["success" => true]); } } function renderSearch(): void { $this->assertUserLoggedIn(); $this->assertPermission('openvk\Web\Models\Entities\TicketReply', 'write', 0); $this->assertNoCSRF(); $this->willExecuteWriteAction(); function searchByAdditionalParams(?string $table = NULL, ?string $where = NULL, ?string $ip = NULL, ?string $useragent = NULL, ?int $ts = NULL, ?int $te = NULL, $user = NULL) { $db = DatabaseConnection::i()->getContext(); if ($table && ($ip || $useragent || $ts || $te || $user)) { $conditions = []; if ($ip) $conditions[] = "`ip` REGEXP '$ip'"; if ($useragent) $conditions[] = "`useragent` REGEXP '$useragent'"; if ($ts) $conditions[] = "`ts` < $ts"; if ($te) $conditions[] = "`ts` > $te"; if ($user) { $users = new Users; $_user = $users->getByChandlerUser((new ChandlerUsers)->getById($user)) ?? $users->get((int)$user) ?? $users->getByAddress($user) ?? NULL; if ($_user) { $conditions[] = "`user` = '" . $_user->getChandlerGUID() . "'"; } } $whereStart = "WHERE `object_table` = '$table'"; if ($table === "profiles") { $whereStart .= "AND `type` = 0"; } $conditions = count($conditions) > 0 ? "AND (" . implode(" AND ", $conditions) . ")" : ""; $response = []; if ($conditions) { $logs = $db->query("SELECT * FROM `ChandlerLogs` $whereStart $conditions GROUP BY `object_id`, `object_model`"); foreach ($logs as $log) { $log = (new Logs)->get($log->id); $object = $log->getObject()->unwrap(); if (!$object) continue; if ($where) { if (str_starts_with($where, " AND")) { $where = substr_replace($where, "", 0, strlen(" AND")); } $a = $db->query("SELECT * FROM `$table` WHERE $where")->fetchAll(); foreach ($a as $o) { if ($object->id == $o["id"]) { $response[] = $object; } } } else { $response[] = $object; } } } return $response; } } try { $response = []; $processed = 0; $where = $this->postParam("where"); $ip = addslashes($this->postParam("ip")); $useragent = addslashes($this->postParam("useragent")); $searchTerm = addslashes($this->postParam("q")); $ts = (int)$this->postParam("ts"); $te = (int)$this->postParam("te"); $user = addslashes($this->postParam("user")); if ($where) { $where = explode(";", $where)[0]; } if (!$ip && !$useragent && !$searchTerm && !$ts && !$te && !$where && !$searchTerm && !$user) $this->returnJson(["success" => false, "error" => "Нет запроса. Заполните поле \"подстрока\" или введите запрос \"WHERE\" в поле под ним."]); $models = explode(",", $this->postParam("models")); foreach ($models as $_model) { $model_name = NoSpamPresenter::ENTITIES_NAMESPACE . "\\" . $_model; if (!class_exists($model_name)) { continue; } $model = new $model_name; $c = new \ReflectionClass($model_name); if ($c->isAbstract() || $c->getName() == NoSpamPresenter::ENTITIES_NAMESPACE . "\\Correspondence") { continue; } $db = DatabaseConnection::i()->getContext(); $table = $model->getTableName(); $columns = $db->getStructure()->getColumns($table); if ($searchTerm) { $conditions = []; $need_deleted = false; foreach ($columns as $column) { if ($column["name"] == "deleted") { $need_deleted = true; } else { $conditions[] = "`$column[name]` REGEXP '$searchTerm'"; } } $conditions = implode(" OR ", $conditions); $where = ($this->postParam("where") ? " AND ($conditions)" : "($conditions)"); if ($need_deleted) $where .= " AND (`deleted` = 0)"; } $rows = []; if (str_starts_with($where, " AND")) { if ($searchTerm && !$this->postParam("where")) { $where = substr_replace($where, "", 0, strlen(" AND")); } else { $where = "(" . $this->postParam("where") . ")" . $where; } } if ($ip || $useragent || $ts || $te || $user) { $rows = searchByAdditionalParams($table, $where, $ip, $useragent, $ts, $te, $user); } else { if (!$where) { $rows = []; } else { $result = $db->query("SELECT * FROM `$table` WHERE $where"); $rows = $result->fetchAll(); } } if (!in_array((int)$this->postParam("ban"), [1, 2, 3])) { foreach ($rows as $key => $object) { $object = (array)$object; $_obj = []; foreach ($object as $key => $value) { foreach ($columns as $column) { if ($column["name"] === $key && in_array(strtoupper($column["nativetype"]), ["BLOB", "BINARY", "VARBINARY", "TINYBLOB", "MEDIUMBLOB", "LONGBLOB"])) { $value = "[BINARY]"; break; } } $_obj[$key] = $value; $_obj["__model_name"] = $_model; } $response[] = $_obj; } } else { $ids = []; foreach ($rows as $object) { $object = new $model_name($db->table($table)->get($object->id)); if (!$object) continue; $ids[] = $object->getId(); } $log = new NoSpamLog; $log->setUser($this->user->id); $log->setModel($_model); if ($searchTerm) { $log->setRegex($searchTerm); } else { $log->setRequest($where); } $log->setBan_Type((int)$this->postParam("ban")); $log->setCount(count($rows)); $log->setTime(time()); $log->setItems(implode(",", $ids)); $log->save(); $banned_ids = []; foreach ($rows as $object) { $object = new $model_name($db->table($table)->get($object->id)); if (!$object) continue; $owner = NULL; $methods = ["getOwner", "getUser", "getRecipient", "getInitiator"]; if (method_exists($object, "ban")) { $owner = $object; } else { foreach ($methods as $method) { if (method_exists($object, $method)) { $owner = $object->$method(); break; } } } if ($owner instanceof User && $owner->getId() === $this->user->id) { if (count($rows) === 1) { $this->returnJson(["success" => false, "error" => "\"Производственная травма\" — Вы не можете блокировать или удалять свой же контент"]); } else { continue; } } if (in_array((int)$this->postParam("ban"), [2, 3])) { $reason = mb_strlen(trim($this->postParam("ban_reason"))) > 0 ? addslashes($this->postParam("ban_reason")) : ("**content-noSpamTemplate-" . $log->getId() . "**"); $is_forever = (string)$this->postParam("is_forever") === "true"; $unban_time = $is_forever ? 0 : (int)$this->postParam("unban_time") ?? NULL; if ($owner) { $_id = ($owner instanceof Club ? $owner->getId() * -1 : $owner->getId()); if (!in_array($_id, $banned_ids)) { if ($owner instanceof User) { if (!$unban_time && !$is_forever) $unban_time = time() + $owner->getNewBanTime(); $owner->ban($reason, false, $unban_time, $this->user->id); } else { $owner->ban("Подозрительная активность"); } $banned_ids[] = $_id; } } } if (in_array((int)$this->postParam("ban"), [1, 3])) $object->delete(); } $processed++; } } $this->returnJson(["success" => true, "processed" => $processed, "count" => count($response), "list" => $response]); } catch (\Throwable $e) { $this->returnJson(["success" => false, "error" => $e->getMessage()]); } } }