%PDF- %PDF-
Direktori : /www/varak.net/dmarc.varak.net/classes/Database/Common/ |
Current File : //www/varak.net/dmarc.varak.net/classes/Database/Common/CommonReportLogMapper.php |
<?php /** * dmarc-srg - A php parser, viewer and summary report generator for incoming DMARC reports. * Copyright (C) 2022-2025 Aleksey Andreev (liuch) * * Available at: * https://github.com/liuch/dmarc-srg * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation, either version 3 of the License. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along with * this program. If not, see <http://www.gnu.org/licenses/>. * * ========================= * * This file contains the CommonReportLogMapper class * * @category API * @package DmarcSrg * @author Aleksey Andreev (liuch) * @license https://www.gnu.org/licenses/gpl-3.0.html GNU/GPLv3 */ namespace Liuch\DmarcSrg\Database\Common; use Liuch\DmarcSrg\DateTime; use Liuch\DmarcSrg\Database\ReportLogMapperInterface; use Liuch\DmarcSrg\Exception\DatabaseFatalException; use Liuch\DmarcSrg\Exception\DatabaseNotFoundException; /** * Universal implementation of ReportLogMapper class */ class CommonReportLogMapper implements ReportLogMapperInterface { /** @var \Liuch\DmarcSrg\Database\DatabaseConnector */ private $connector = null; /** * The constructor * * @param \Liuch\DmarcSrg\Database\DatabaseConnector $connector DatabaseConnector instance of the current database */ public function __construct(object $connector) { $this->connector = $connector; } /** * Fetches data of report log item from the database by id * * @param array $data Log data * * @return void */ public function fetch(array &$data): void { try { $st = $this->connector->dbh()->prepare( 'SELECT domain, external_id, event_time, filename, source, success, message FROM ' . $this->connector->tablePrefix('reportlog') . ' WHERE id = ?' ); $st->bindValue(1, $data['id'], \PDO::PARAM_INT); $st->execute(); if (!($row = $st->fetch(\PDO::FETCH_NUM))) { throw new DatabaseNotFoundException(); } $data['domain'] = $row[0]; $data['report_id'] = $row[1]; $data['event_time'] = new DateTime($row[2]); $data['filename'] = $row[3]; $data['source'] = intval($row[4]); $data['success'] = boolval($row[5]); $data['message'] = $row[6]; $st->closeCursor(); } catch (\PDOException $e) { throw new DatabaseFatalException('Failed to get the log item', -1, $e); } } /** * Saves data of report log item to the database * * @return void */ public function save(array &$data): void { $db = $this->connector->dbh(); try { $id = $data['id']; if (is_null($id)) { $st = $db->prepare( 'INSERT INTO ' . $this->connector->tablePrefix('reportlog') . ' (domain, external_id, event_time, filename, source, success, message)' . ' VALUES (?, ?, ?, ?, ?, ?, ?)' ); } else { $st = $db->prepare( 'UPDATE ' . $this->connector->tablePrefix('reportlog') . ' SET domain = ?, external_id = ?, event_time = ?, filename = ?,' . ' source = ?, success = ?, message = ? WHERE id = ?' ); $st->bindValue(8, $id, \PDO::PARAM_INT); } $ts = $data['event_time'] ?? (new DateTime()); $st->bindValue(1, $data['domain'], \PDO::PARAM_STR); $st->bindValue(2, $data['report_id'], \PDO::PARAM_STR); $st->bindValue(3, $ts->format('Y-m-d H:i:s'), \PDO::PARAM_STR); $st->bindValue(4, $data['filename'], \PDO::PARAM_STR); $st->bindValue(5, $data['source'], \PDO::PARAM_INT); $st->bindValue(6, $data['success'], \PDO::PARAM_BOOL); $st->bindValue(7, $data['message'], \PDO::PARAM_STR); $st->execute(); if (is_null($id)) { $data['id'] = intval($db->lastInsertId()); } $st->closeCursor(); $data['event_time'] = $ts; } catch (\PDOException $e) { throw new DatabaseFatalException('Failed to save a report log item'); } } /** * Returns a list of report log items with given criteria * * @param array $filter Key-value array: * 'from_time' => DateTime * 'till_time' => DateTime * @param array $order Key-value array with order options: * 'direction' => string, 'ascent' or 'descent' * @param array $limit Key-value array: * 'offset' => int * 'count' => int * * @return array */ public function list(array &$filter, array &$order, array &$limit): array { $list = []; try { $st = $this->connector->dbh()->prepare( 'SELECT id, domain, event_time, source, success, message FROM ' . $this->connector->tablePrefix('reportlog') . $this->sqlCondition($filter) . $this->sqlOrder($order) . $this->sqlLimit($limit) ); $this->sqlBindValues($st, $filter, $limit); $st->execute(); while ($row = $st->fetch(\PDO::FETCH_NUM)) { $list[] = [ 'id' => intval($row[0]), 'domain' => $row[1], 'event_time' => new DateTime($row[2]), 'source' => intval($row[3]), 'success' => boolval($row[4]), 'message' => $row[5] ]; } $st->closeCursor(); } catch (\PDOException $e) { throw new DatabaseFatalException('Failed to get the logs', -1, $e); } return $list; } /** * Returns the number of report log items matching the specified filter and limits * * @param array $filter Key-value array with filtering parameters * @param array $limit Key-value array with limits * * @return int */ public function count(array &$filter, array &$limit): int { $cnt = 0; try { $st = $this->connector->dbh()->prepare( 'SELECT COUNT(*) FROM ' . $this->connector->tablePrefix('reportlog') . $this->sqlCondition($filter) . $this->sqlLimit($limit) ); $this->sqlBindValues($st, $filter, $limit); $st->execute(); $cnt = intval($st->fetch(\PDO::FETCH_NUM)[0]); $st->closeCursor(); } catch (\PDOException $e) { throw new DatabaseFatalException('Failed to get the log data', -1, $e); } return $cnt; } /** * Deletes report log items from the database * * @param array $filter Key-value array with filtering parameters * @param array $order Key-value array with order options: * 'direction' => string, 'ascent' or 'descent' * @param array $limit Key-value array with limits * * @return void */ public function delete(array &$filter, array &$order, array &$limit): void { try { $st = $this->connector->dbh()->prepare( 'DELETE FROM ' . $this->connector->tablePrefix('reportlog') . $this->sqlCondition($filter) . $this->sqlOrder($order) . $this->sqlLimit($limit) ); $this->sqlBindValues($st, $filter, $limit); $st->execute(); $st->closeCursor(); } catch (\PDOException $e) { throw new DatabaseFatalException('Failed to remove the log data', -1, $e); } } /** * Returns a string with an SQL condition 'WHERE ...' * * @param array $filter Key-value with filtering paremeters * * @return string */ private function sqlCondition(array &$filter): string { $res = []; if (isset($filter['from_time'])) { $res[] = 'event_time >= ?'; } if (isset($filter['till_time'])) { $res[] = 'event_time < ?'; } if (isset($filter['success'])) { $res[] = 'success = ?'; } if (isset($filter['source'])) { $res[] = 'source = ?'; } return count($res) > 0 ? (' WHERE ' . implode(' AND ', $res)) : ''; } /** * Returns 'ORDER BY ...' part of the SQL query * * @param array $order Key-value array with ordering options * * @return string */ private function sqlOrder(array &$order): string { return ' ORDER BY event_time ' . ($order['direction'] === 'descent' ? 'DESC' : 'ASC'); } /** * Returns 'LIMIT ...' part of the SQL string * * @param array $limit Key-value array with keys 'offset' and 'count' * * @return string */ private function sqlLimit(array &$limit): string { $res = ''; if ($limit['count'] > 0) { $res = ' LIMIT ?'; if ($limit['offset'] > 0) { $res .= ', ?'; } } return $res; } /** * Binds the values of the filter and the limit to SQL query * * @param \PDOStatement $st Prepared SOL statement to bind to * @param array $filter Key-value array with filter data * @param array $limit Key-value array with limit data * * @return void */ private function sqlBindValues($st, array &$filter, array &$limit): void { $pos = 0; if (isset($filter['from_time'])) { $st->bindValue(++$pos, $filter['from_time']->format('Y-m-d H:i:s'), \PDO::PARAM_STR); } if (isset($filter['till_time'])) { $st->bindValue(++$pos, $filter['till_time']->format('Y-m-d H:i:s'), \PDO::PARAM_STR); } if (isset($filter['success'])) { $st->bindValue(++$pos, $filter['success'], \PDO::PARAM_BOOL); } if (isset($filter['source'])) { $st->bindValue(++$pos, $filter['source'], \PDO::PARAM_INT); } if ($limit['count'] > 0) { if ($limit['offset'] > 0) { $st->bindValue(++$pos, $limit['offset'], \PDO::PARAM_INT); } $st->bindValue(++$pos, $limit['count'], \PDO::PARAM_INT); } } }