0
AND dtr.local_data_id = ?',
[$local_data_id]), 'id', 'name');
}
/**
* Validates and processes a given filename, determining its path and base name.
*
* This function checks if the provided filename matches specific log file patterns
* (e.g., standard log, error log, or boost log) and extracts the corresponding
* file path and base name. Optionally, it can verify if the file exists.
*
* @param string $file The input filename to validate. This will be modified
* to contain only the base name of the file.
* @param string $filepath The output variable that will hold the directory path
* of the validated file.
* @param string $filename The output variable that will hold the base name of
* the validated file.
* @param bool $filecheck If true, the function will check if the
* resolved file exists. Defaults to false.
*
* @return bool Returns true if the file is valid (and exists if $filecheck is true),
* or false otherwise.
*/
function clog_validate_filename(string &$file, string &$filepath = '', string &$filename = '', bool $filecheck = false) : bool {
$logfile = read_config_option('path_cactilog');
if ($logfile == '') {
$logfile = CACTI_PATH_LOG . '/cacti.log';
}
$errfile = read_config_option('path_stderrlog');
$errbase = basename($errfile);
$boostfile = read_config_option('path_boost_log');
$boostbase = basename($boostfile);
$file = basename($file);
$logbase = basename($logfile);
$filepath = '';
$filename = '';
$filefull = '';
if (!empty($errfile) && str_starts_with($file, $errbase)) {
$filepath = dirname($errfile);
$filename = $errbase;
$filefull = $filepath . '/' . $file;
} elseif (!empty($logfile) && str_starts_with($file, $logbase)) {
$filepath = dirname($logfile);
$filename = $logbase;
$filefull = $filepath . '/' . $file;
} elseif (!empty($boostfile) && str_starts_with($file, $boostbase)) {
$filepath = dirname($boostfile);
$filename = $boostbase;
$filefull = $filepath . '/' . $file;
}
return ($filecheck ? file_exists($filefull) : !empty($filefull));
}
/**
* Purges or clears a specified log file within the Cacti application.
*
* @param string $action The action to be taken 'purge' or 'rotate'
*
* @return void
*/
function clog_purge_logfile(string $action = 'purge') : void {
$filename = gnrv('filename');
$logpath = '';
$logname = '';
if (!clog_validate_filename($filename, $logpath, $logname)) {
raise_message('clog_invalid');
header('Location: ' . get_current_page());
exit(0);
}
$purgefile = $logpath . '/' . $filename;
$logfile = $logpath . '/' . $logname;
$log_action = read_config_option('log_action');
// get base filenames for rotate assessment
$cactiLog = basename(read_config_option('path_cactilog'));
$errorLog = basename(read_config_option('path_stderrlog'));
// basic checking
if ($action == 'rotate' && $log_action == LOG_ACTION_PURGE) {
raise_message('rotate_failed', __esc('Cacti Log file rotation failed for Log File \'%s\'. User \'%s\' wished to rotate, but rotating is disabled', basename($purgefile), get_username()), MESSAGE_LEVEL_ERROR);
return;
}
if ($action == 'purge' && $log_action == LOG_ACTION_ROTATE) {
raise_message('purge_failed', __esc('Cacti Log file purging failed for Log File \'%s\'. User \'%s\' wished to purge, but purging is disabled', basename($purgefile), get_username()), MESSAGE_LEVEL_ERROR);
return;
}
if ($filename != $cactiLog && $filename != $errorLog && $action == 'rotate') {
raise_message('rotate_failed', __esc('Cacti Log file rotation failed for Log File \'%s\'. User \'%s\' wished to rotate, but rotating is not allowed on already rotated files', basename($purgefile), get_username()), MESSAGE_LEVEL_ERROR);
return;
}
if ($action == 'purge') {
$imessage = __('The Cacti Log File \'%s\' was Removed by user \'%s\'', basename($purgefile), get_username());
$message = sprintf('The Cacti Log File \'%s\', Removed by user \'%s\'', basename($purgefile), get_username());
} else {
$imessage = __('The Cacti Log File \'%s\' was Rotated by user \'%s\'', basename($purgefile), get_username());
$message = sprintf('The Cacti Log File \'%s\', Rotated by user \'%s\'', basename($purgefile), get_username());
}
if (file_exists($purgefile)) {
if (is_writable($purgefile)) {
if ($logfile != $purgefile) {
if ($action == 'purge') {
unlink($purgefile);
raise_message('clog_removed', $imessage, MESSAGE_LEVEL_INFO);
cacti_log($message, false, 'WEBUI');
} else {
raise_message('clog_removed', __esc('Removal Failed due to the Administrator blocking removal of archived files. The file \'%s\' can not be removed.', basename($purgefile)), MESSAGE_LEVEL_WARN);
}
} else {
if ($action == 'rotate') {
$ext = date('Ymd-His');
rename($logfile, $logfile . '-' . $ext);
}
$log_fh = fopen($logfile, 'w');
if (is_resource($log_fh)) {
fclose($log_fh);
raise_message('clog_removed', $imessage, MESSAGE_LEVEL_INFO);
cacti_log($message, false, 'WEBUI');
} else {
raise_message('clog_removed', __esc('Unable to open log file \'%s\' for writing.', basename($logfile)), MESSAGE_LEVEL_ERROR);
}
}
} else {
raise_message('clog_permissions');
}
} else {
raise_message('clog_missing');
}
}
/**
* Displays the log file viewer for Cacti, allowing users to view, filter, and manage log entries.
*
* @return void
*/
function clog_view_logfile() : void {
global $logfile_actions;
$exclude_reported = false;
$clogAdmin = clog_admin();
// enable page refreshes
kill_session_var('custom');
if (isrv('filename')) {
$logfile = basename(gnrv('filename'));
} elseif (isset($_SESSION['sess_clog']['filename'])) {
$logfile = basename($_SESSION['sess_clog']['filename']);
} else {
$logfile = 'cacti.log';
}
$logname = '';
$logpath = '';
if (!clog_validate_filename($logfile, $logpath, $logname, true)) {
$logfile = read_config_option('path_cactilog');
} else {
$logfile = $logpath . '/' . $logfile;
}
if ($clogAdmin) {
$redirect = false;
if (isrv('purge_continue')) {
$redirect = true;
clog_purge_logfile('purge');
} elseif (isrv('rotate_continue')) {
$redirect = true;
clog_purge_logfile('rotate');
}
if ($redirect) {
$logfile = read_config_option('path_cactilog');
header('Location: clog.php?filename=' . basename($logfile));
exit;
}
}
$page_nr = gnrv('page');
if ($page_nr == '') {
$page_nr = 1;
srv('page', 1);
}
if (get_current_page() == 'clog.php' || get_current_page() == 'clog_user.php') {
general_header();
} else {
top_header();
}
if ($clogAdmin) {
if (gnrv('action') == 'purge' || gnrv('action') == 'rotate') {
// Keep phpstan happy
$action = '';
$title = '';
$message = '';
$header = '';
if (gnrv('action') == 'purge') {
$message = __('Click \'Continue\' to Purge the Log File \'' . htmle(basename($logfile)) . '\'.
Note: If logging is set to both Cacti and Syslog, the log information will remain in Syslog.');
$action = 'purge_continue';
$button = __esc('Purge');
$title = __esc('Purge Log');
$header = $logfile_actions[LOG_ACTION_PURGE];
} elseif (gnrv('action') == 'rotate') {
$message = __('Click \'Continue\' to Rotate the existing Log File \'' . htmle(basename($logfile)) . '\'.
Note: If logging is set to both Cacti and Syslog, the log information will remain in Syslog.');
$action = 'rotate_continue';
$button = __esc('Rotate');
$title = __esc('Rotate Log');
$header = $logfile_actions[LOG_ACTION_ROTATE];
}
form_start(get_current_page());
html_start_box($header, '60%', false, 3, 'center', '');
print "