cache = new DbStatementCache($dbConn); } public function countLogs( UserInfo|string|null $userInfo = null, IPAddress|string|null $remoteAddr = null ): int { if($userInfo instanceof UserInfo) $userInfo = $userInfo->getId(); if($remoteAddr instanceof IPAddress) $remoteAddr = (string)$remoteAddr; $hasUserInfo = $userInfo !== null; $hasRemoteAddr = $remoteAddr !== null; $args = 0; $query = 'SELECT COUNT(*) FROM msz_audit_log'; if($hasUserInfo) { ++$args; $query .= ' WHERE user_id = ?'; } if($hasRemoteAddr) { $query .= (++$args > 1 ? ' AND' : ' WHERE'); $query .= ' log_ip = INET6_ATON(?)'; } $stmt = $this->cache->get($query); $args = 0; if($hasUserInfo) $stmt->addParameter(++$args, $userInfo); if($hasRemoteAddr) $stmt->addParameter(++$args, $remoteAddr); $stmt->execute(); $result = $stmt->getResult(); $count = 0; if($result->next()) $count = $result->getInteger(0); return $count; } public function getLogs( UserInfo|string|null $userInfo = null, IPAddress|string|null $remoteAddr = null, ?Pagination $pagination = null ): array { if($userInfo instanceof UserInfo) $userInfo = $userInfo->getId(); if($remoteAddr instanceof IPAddress) $remoteAddr = (string)$remoteAddr; $hasUserInfo = $userInfo !== null; $hasRemoteAddr = $remoteAddr !== null; $hasPagination = $pagination !== null; $args = 0; $query = 'SELECT user_id, log_action, log_params, UNIX_TIMESTAMP(log_created), INET6_NTOA(log_ip), log_country FROM msz_audit_log'; if($hasUserInfo) { ++$args; $query .= ' WHERE user_id = ?'; } if($hasRemoteAddr) { $query .= (++$args > 1 ? ' AND' : ' WHERE'); $query .= ' log_ip = INET6_ATON(?)'; } $query .= ' ORDER BY log_created DESC'; if($hasPagination) $query .= ' LIMIT ? OFFSET ?'; $stmt = $this->cache->get($query); $args = 0; if($hasUserInfo) $stmt->addParameter(++$args, $userInfo); if($hasRemoteAddr) $stmt->addParameter(++$args, $remoteAddr); if($hasPagination) { $stmt->addParameter(++$args, $pagination->getRange()); $stmt->addParameter(++$args, $pagination->getOffset()); } $stmt->execute(); $result = $stmt->getResult(); $logs = []; while($result->next()) $logs[] = new AuditLogInfo($result); return $logs; } public function createLog( UserInfo|string|null $userInfo, string $action, array $params = [], IPAddress|string $remoteAddr = '::1', string $countryCode = 'XX' ): void { if($userInfo instanceof UserInfo) $userInfo = $userInfo->getId(); if($remoteAddr instanceof IPAddress) $remoteAddr = (string)$remoteAddr; // action names should have stricter validation, // i do want to switch to a lowercase colon separated format later but i'll save that for the unified log in Hanyuu $actionTrim = trim($action); if($actionTrim !== $action || empty($actionTrim)) throw new InvalidArgumentException('$action may not be empty.'); if(strlen($countryCode) !== 2 || !ctype_alpha($countryCode)) throw new InvalidArgumentException('$countryCode must be two alpha characters.'); foreach($params as &$param) { if(is_array($param)) $param = implode(', ', $param); elseif(is_object($param)) $param = (string)$param; } $params = json_encode($params); $stmt = $this->cache->get('INSERT INTO msz_audit_log (user_id, log_action, log_params, log_ip, log_country) VALUES (?, ?, ?, INET6_ATON(?), UPPER(?))'); $stmt->addParameter(1, $userInfo); $stmt->addParameter(2, $action); $stmt->addParameter(3, $params); $stmt->addParameter(4, $remoteAddr); $stmt->addParameter(5, $countryCode); $stmt->execute(); } }