$max_length) { return mb_substr($text, 0, $max_length) . '...'; } else { return $text; } } /** * filter_value - a quick way to highlight text in a table from general filtering * * @param $text - the string to filter * @param $filter - the search term to filter for * @param $href - the href if you wish to have an anchor returned * * @return - the filtered string */ function filter_value($value, $filter, $href = '') { static $charset; if ($charset == '') { $charset = ini_get('default_charset'); } if ($charset == '') { $charset = 'UTF-8'; } if (empty($value)) { return $value; } $value = htmlspecialchars($value, ENT_QUOTES, $charset, false); // Grave Accent character can lead to xss $value = str_replace('`', '`', $value); if ($filter != '') { $value = preg_replace('#(' . preg_quote($filter) . ')#i', "\\1", $value); } if ($href != '') { $value = '' . $value . ''; } return $value; } /** * set_graph_config_option - deprecated - wrapper to set_user_setting(). * * @param $config_name - the name of the configuration setting as specified $settings array * @param $value - the values to be saved * @param $user - the user id, otherwise the session user * * @return - void */ function set_graph_config_option($config_name, $value, $user = -1) { set_user_setting($config_name, $value, $user); } /** * graph_config_value_exists - deprecated - wrapper to user_setting_exists * * @param $config_name - the name of the configuration setting as specified $settings_user array * in 'include/global_settings.php' * @param $user_id - the id of the user to check the configuration value for * * @return (bool) - true if a value exists, false if a value does not exist */ function graph_config_value_exists($config_name, $user_id) { return user_setting_exists($config_name, $user_id); } /** * read_default_graph_config_option - deprecated - wrapper to read_default_user_setting * * @param $config_name - the name of the configuration setting as specified $settings array * in 'include/global_settings.php' * * @return - the default value of the configuration option */ function read_default_graph_config_option($config_name) { return read_default_user_setting($config_name); } /** * read_graph_config_option - deprecated - finds the current value of a graph configuration setting * * @param $config_name - the name of the configuration setting as specified $settings_user array * in 'include/global_settings.php' * * @return - the current value of the graph configuration option */ function read_graph_config_option($config_name, $force = false) { return read_user_setting($config_name, false, $force); } /** * save_user_setting - sets/updates aLL user settings * * @param $config_name - the name of the configuration setting as specified $settings array * @param $value - the values to be saved * @param $user - the user id, otherwise the session user * * @return - void */ function save_user_settings($user = -1) { global $settings_user; if ($user == -1 || empty($user)) { $user = $_SESSION['sess_user_id']; } foreach ($settings_user as $tab_short_name => $tab_fields) { foreach ($tab_fields as $field_name => $field_array) { /* Check every field with a numeric default value and reset it to default if the inputted value is not numeric */ if (isset($field_array['default']) && is_numeric($field_array['default']) && !is_numeric(get_nfilter_request_var($field_name))) { set_request_var($field_name, $field_array['default']); } if (isset($field_array['method'])) { if ($field_array['method'] == 'checkbox') { set_user_setting($field_name, (isset_request_var($field_name) ? 'on' : ''), $user); } elseif ($field_array['method'] == 'checkbox_group') { foreach ($field_array['items'] as $sub_field_name => $sub_field_array) { set_user_setting($sub_field_name, (isset_request_var($sub_field_name) ? 'on' : ''), $user); } } elseif ($field_array['method'] == 'textbox_password') { if (get_nfilter_request_var($field_name) != get_nfilter_request_var($field_name.'_confirm')) { $_SESSION['sess_error_fields'][$field_name] = $field_name; $_SESSION['sess_field_values'][$field_name] = get_nfilter_request_var($field_name); $errors[4] = 4; } elseif (isset_request_var($field_name)) { set_user_setting($field_name, get_nfilter_request_var($field_name), $user); } } elseif ((isset($field_array['items'])) && (is_array($field_array['items']))) { foreach ($field_array['items'] as $sub_field_name => $sub_field_array) { if (isset_request_var($sub_field_name)) { set_user_setting($sub_field_name, get_nfilter_request_var($sub_field_name), $user); } } } elseif (isset_request_var($field_name)) { set_user_setting($field_name, get_nfilter_request_var($field_name), $user); } } } } } /** * set_user_setting - sets/updates a user setting with the given value. * * @param $config_name - the name of the configuration setting as specified $settings array * @param $value - the values to be saved * @param $user - the user id, otherwise the session user * * @return - void */ function set_user_setting($config_name, $value, $user = -1) { global $settings_user; if ($user == -1 && isset($_SESSION['sess_user_id'])) { $user = $_SESSION['sess_user_id']; } if ($user == -1) { if (isset($_SESSION['sess_user_id'])) { $mode = 'WEBUI'; } else { $mode = 'POLLER'; } cacti_log('NOTE: Attempt to set user setting \'' . $config_name . '\', with no user id: ' . cacti_debug_backtrace('', false, false, 0, 1), false, $mode, POLLER_VERBOSITY_MEDIUM); } elseif (db_table_exists('settings_user')) { if (strlen($config_name) > 75) { cacti_log("ERROR: User setting name '$config_name' is too long, will be truncated", false, 'SYSTEM'); } db_execute_prepared('REPLACE INTO settings_user SET user_id = ?, name = ?, value = ?', array($user, $config_name, $value)); unset($_SESSION['sess_user_config_array']); $settings_user[$config_name]['value'] = $value; } } /** * user_setting_exists - determines if a value exists for the current user/setting specified * * @param $config_name - the name of the configuration setting as specified $settings_user array * in 'include/global_settings.php' * @param $user_id - the id of the user to check the configuration value for * * @return (bool) - true if a value exists, false if a value does not exist */ function user_setting_exists($config_name, $user_id) { static $user_setting_values = array(); if (!isset($user_setting_values[$config_name])) { $value = 0; if (db_table_exists('settings_user')) { $value = db_fetch_cell_prepared('SELECT COUNT(*) FROM settings_user WHERE name = ? AND user_id = ?', array($config_name, $user_id)); } if ($value !== false && $value > 0) { $user_setting_values[$config_name] = true; } else { $user_setting_values[$config_name] = false; } } return $user_setting_values[$config_name]; } /** * clear_user_setting - if a value exists for the current user/setting specified, removes it * * @param $config_name - the name of the configuration setting as specified $settings_user array * in 'include/global_settings.php' * @param $user_id - the id of the user to remove the configuration value for */ function clear_user_setting($config_name, $user = -1) { global $settings_user; if ($user == -1) { $user = $_SESSION['sess_user_id']; } if (db_table_exists('settings_user')) { db_execute_prepared('DELETE FROM settings_user WHERE name = ? AND user_id = ?', array($config_name, $user)); } unset($_SESSION['sess_user_config_array']); } /** * read_default_user_setting - finds the default value of a user configuration setting * * @param $config_name - the name of the configuration setting as specified $settings array * in 'include/global_settings.php' * * @return - the default value of the configuration option */ function read_default_user_setting($config_name) { global $config, $settings_user; foreach ($settings_user as $tab_array) { if (isset($tab_array[$config_name]) && isset($tab_array[$config_name]['default'])) { return $tab_array[$config_name]['default']; } else { foreach ($tab_array as $field_array) { if (isset($field_array['items']) && isset($field_array['items'][$config_name]) && isset($field_array['items'][$config_name]['default'])) { return $field_array['items'][$config_name]['default']; } } } } } /** * read_user_setting - finds the current value of a graph configuration setting * * @param $config_name - the name of the configuration setting as specified $settings_user array * in 'include/global_settings.php' * @param $default - the default value is none is set * @param $force - pull the data from the database if true ignoring session * @param $user - assume this user's identity * * @return - the current value of the user setting */ function read_user_setting($config_name, $default = false, $force = false, $user = 0) { global $config; /* users must have cacti user auth turned on to use this, or the guest account must be active */ if ($user == 0 && isset($_SESSION['sess_user_id'])) { $effective_uid = $_SESSION['sess_user_id']; } elseif (read_config_option('auth_method') == 0 || $user > 0) { /* first attempt to get the db setting for guest */ if ($user == 0) { $effective_uid = db_fetch_cell("SELECT user_auth.id FROM settings INNER JOIN user_auth ON user_auth.username = settings.value WHERE settings.name = 'guest_user'"); if ($effective_uid == '') { $effective_uid = 0; } } else { $effective_uid = $user; } $db_setting = false; if (db_table_exists('settings_user')) { $db_setting = db_fetch_row_prepared('SELECT value FROM settings_user WHERE name = ? AND user_id = ?', array($config_name, $effective_uid)); } if (cacti_sizeof($db_setting)) { return $db_setting['value']; } elseif ($default !== false) { return $default; } else { return read_default_user_setting($config_name); } } else { $effective_uid = 0; } if (!$force) { if (isset($_SESSION['sess_user_config_array'])) { $user_config_array = $_SESSION['sess_user_config_array']; } } if (!isset($user_config_array[$config_name])) { $db_setting = false; if (db_table_exists('settings_user')) { $db_setting = db_fetch_row_prepared('SELECT value FROM settings_user WHERE name = ? AND user_id = ?', array($config_name, $effective_uid)); } if (cacti_sizeof($db_setting)) { $user_config_array[$config_name] = $db_setting['value']; } elseif ($default !== false) { $user_config_array[$config_name] = $default; } else { $user_config_array[$config_name] = read_default_user_setting($config_name); } if (isset($_SESSION)) { $_SESSION['sess_user_config_array'] = $user_config_array; } else { $config['config_user_settings_array'] = $user_config_array; } } return $user_config_array[$config_name]; } /** * is_remote_path_setting - determines of a Cacti setting should be maintained * on the Remote Data Collector separate from the Main cacti server * * @param $config_name - the name of the configuration setting as specified $settings array * * @return (bool) - true if the setting should be saved locally */ function is_remote_path_setting($config_name) { global $config; if ($config['poller_id'] > 1 && (strpos($config_name, 'path_') !== false || strpos($config_name, '_path') !== false)) { return true; } else { return false; } } /** * set_config_option - sets/updates a cacti config option with the given value. * * @param $config_name - the name of the configuration setting as specified $settings array * @param $value - the values to be saved * @param $remote - push the setting to the remote with the exception of path variables * * @return (void) */ function set_config_option($config_name, $value, $remote = false) { global $config; include_once($config['base_path'] . '/lib/poller.php'); if (strlen($config_name) > 75) { cacti_log("ERROR: Config option name '$config_name' is too long, will be truncated", false, 'SYSTEM'); } db_execute_prepared('REPLACE INTO settings SET name = ?, value = ?', array($config_name, $value)); if ($remote && !is_remote_path_setting($config_name)) { $gone_time = read_config_option('poller_interval') * 2; $pollers = array_rekey( db_fetch_assoc('SELECT id, UNIX_TIMESTAMP() - UNIX_TIMESTAMP(last_status) AS last_polled FROM poller WHERE id > 1 AND disabled=""'), 'id', 'last_polled' ); $sql = 'INSERT INTO settings (name, value) VALUES (?, ?) ON DUPLICATE KEY UPDATE value=VALUES(value)'; foreach($pollers as $p => $t) { if ($t > $gone_time) { raise_message('poller_' . $p, __('Settings save to Data Collector %d skipped due to heartbeat.', $p), MESSAGE_LEVEL_WARN); } else { $rcnn_id = poller_connect_to_remote($p); if ($rcnn_id) { if (db_execute_prepared($sql, array($config_name, $value), false, $rcnn_id) === false) { $rcnn_id = false; } } // check if we still have rcnn_id, if it's now become false, we had a problem if (!$rcnn_id) { raise_message('poller_' . $p, __('Settings save to Data Collector %d Failed.', $p), MESSAGE_LEVEL_ERROR); } } } } $config_array = array(); if ($config['is_web']) { $sess = true; } else { $sess = false; } // Store the array back for later retrieval if ($sess) { $_SESSION['sess_config_array'] = $value; } else { $config['config_options_array'] = $value; } if (!empty($config['DEBUG_SET_CONFIG_OPTION'])) { file_put_contents(sys_get_temp_dir() . '/cacti-option.log', get_debug_prefix() . cacti_debug_backtrace($config_name, false, false, 0, 1) . "\n", FILE_APPEND); } } /** * config_value_exists - determines if a value exists for the current user/setting specified * * @param $config_name - the name of the configuration setting as specified $settings array * in 'include/global_settings.php' * * @return - true if a value exists, false if a value does not exist */ function config_value_exists($config_name) { static $config_values = array(); if (!isset($config_values[$config_name])) { $value = db_fetch_cell_prepared('SELECT COUNT(*) FROM settings WHERE name = ?', array($config_name)); if ($value > 0) { $config_values[$config_name] = true; } else { $config_values[$config_name] = false; } } return $config_values[$config_name]; } /** * read_default_config_option - finds the default value of a Cacti configuration setting * * @param $config_name - the name of the configuration setting as specified $settings array * in 'include/global_settings.php' * * @return - the default value of the configuration option */ function read_default_config_option($config_name) { global $config, $settings; if (isset($settings) && is_array($settings)) { foreach ($settings as $tab_array) { if (isset($tab_array[$config_name]) && isset($tab_array[$config_name]['default'])) { return $tab_array[$config_name]['default']; } else { foreach ($tab_array as $field_array) { if (isset($field_array['items']) && isset($field_array['items'][$config_name]) && isset($field_array['items'][$config_name]['default'])) { return $field_array['items'][$config_name]['default']; } } } } } } function prime_common_config_settings() { global $config; //$start = microtime(true); $common_settings = array( 'auth_method', 'auth_cache_enabled', 'path_cactilog', 'rrdtool_version', 'log_verbosity', 'log_destination', 'default_image_format', 'default_graph_width', 'default_graph_height', 'default_datechar', 'default_date_format', 'default_poller', 'default_site', 'i18n_language_support', 'i18n_default_language', 'reports_allow_ln', // Common page rendering 'selective_debug', 'selected_theme', 'min_tree_width', 'max_tree_width', ); if ($config['is_web']) { $extra_settings = array( // Common all pages 'force_https', 'content_security_policy_script', 'content_security_alternate_sources', 'deletion_verification', // Common graphing 'rrdtool_watermark', 'realtime_cache_path', 'path_rrdtool', 'hide_disabled', 'graph_watermark', 'graph_dateformat', 'font_method', 'date', 'boost_rrd_update_system_enable', 'boost_rrd_update_max_records_per_select', 'boost_rrd_update_enable', 'boost_png_cache_enable', 'remote_storage_method', ); } else { $extra_settings = array( // Common polling 'poller_interval', 'snmp_version', 'snmp_username', 'snmp_timeout', 'snmp_community', 'snmp_auth_protocol', 'snmp_security_level', 'snmp_priv_protocol', 'snmp_priv_passphrase', 'snmp_port', 'snmp_password', 'snmp_retries', 'device_threads', 'max_get_size', 'availability_method', 'ping_method', 'ping_port', 'ping_retries', 'ping_timeout', 'path_snmpbulkwalk', 'path_snmpwalk', 'path_snmpget', 'path_spine', // Common API 'default_template', 'delete_verification', // Thold 'alert_bl_trigger', 'alert_deadnotify', 'alert_email', 'alert_exempt', 'alert_repeat', 'alert_trigger', 'base_url', 'thold_alert_snmp_warning', 'thold_alert_snmp_normal', 'thold_alert_snmp', 'thold_daemon_debug', 'thold_disable_all', 'thold_log_debug', 'thold_send_text_only', 'thold_show_datasource', ); } $common_settings = array_merge($common_settings, $extra_settings); $settings = array_rekey( db_fetch_assoc_prepared('SELECT name, value FROM settings WHERE name IN (' . trim(str_repeat('?, ', cacti_sizeof($common_settings)),', ') . ')', $common_settings), 'name', 'value' ); if (isset($_SESSION['sess_config_array'])) { $sess = true; } else { $sess = false; } if (cacti_sizeof($settings)) { foreach($settings as $name => $value) { if ($sess) { $_SESSION['sess_config_array'][$name] = $value; } else { $config['config_options_array'][$name] = $value; } } } //$end = microtime(true); //cacti_log('The Total common load time:' . round($end - $start, 4)); } /** * Finds the current value of a Cacti configuration setting * * @param $config_name The name of the configuration setting as specified * as a key in $settings array in * 'include/global_settings.php' * * @return string|false The current value of the configuration option */ function read_config_option($config_name, $force = false) { global $config, $database_hostname, $database_default, $database_port, $database_sessions; $loaded = false; if ($config['is_web']) { $sess = true; if (isset($_SESSION['sess_config_array'][$config_name])) { $loaded = true; } } else { $sess = false; if (isset($config['config_options_array'][$config_name])) { $loaded = true; } } if (!empty($config['DEBUG_READ_CONFIG_OPTION'])) { file_put_contents(sys_get_temp_dir() . '/cacti-option.log', get_debug_prefix() . cacti_debug_backtrace($config_name, false, false, 0, 1) . "\n", FILE_APPEND); } // Do we have a value already stored in the array, or // do we want to make sure we have the latest value // from the database? if (!$loaded || $force) { // We need to check against the DB, but lets assume default value // unless we can actually read the DB $value = read_default_config_option($config_name); if (!empty($config['DEBUG_READ_CONFIG_OPTION'])) { file_put_contents(sys_get_temp_dir() . '/cacti-option.log', get_debug_prefix() . " $config_name: " . ' dh: ' . isset($database_hostname) . ' dp: ' . isset($database_port) . ' dd: ' . isset($database_default) . ' ds: ' . isset($database_sessions["$database_hostname:$database_port:$database_default"]) . "\n", FILE_APPEND); if (isset($database_hostname) && isset($database_port) && isset($database_default)) { file_put_contents(sys_get_temp_dir() . '/cacti-option.log', get_debug_prefix() . " $config_name: [$database_hostname:$database_port:$database_default]\n", FILE_APPEND); } } // Are the database variables set, and do we have a connection?? // If we don't, we'll only use the default value without storing // so that we can read the database version later. if (isset($database_hostname) && isset($database_port) && isset($database_default) && isset($database_sessions["$database_hostname:$database_port:$database_default"])) { // Get the database setting $db_result = db_fetch_row_prepared('SELECT value FROM settings WHERE name = ?', array($config_name)); if (cacti_sizeof($db_result)) { $value = $db_result['value']; } // Store whatever value we have in the array if ($sess) { if (!isset($_SESSION['sess_config_array']) || !is_array($_SESSION['sess_config_array'])) { $_SESSION['sess_config_array'] = array(); } $_SESSION['sess_config_array'][$config_name] = $value; } else { if (!isset($config['config_options_array']) || !is_array($config['config_options_array'])) { $config['config_options_array'] = array(); } $config['config_options_array'][$config_name] = $value; } } } else { // We already have the value stored in the array and // we don't want to force a db read, so use the cached // version if ($sess) { $value = $_SESSION['sess_config_array'][$config_name]; } else { $value = $config['config_options_array'][$config_name]; } } return $value; } /** * get_selected_theme - checks the user settings and if the user selected * theme is set, returns it otherwise returns the system default. * * @return - the theme name */ function get_selected_theme() { global $config, $themes; // shortcut if theme is set in session if (isset($_SESSION['selected_theme'])) { if (file_exists($config['base_path'] . '/include/themes/' . $_SESSION['selected_theme'] . '/main.css')) { return $_SESSION['selected_theme']; } } // default to system selected theme $theme = read_config_option('selected_theme'); // check for a pre-1.x cacti being upgraded if ($theme == '' && !db_table_exists('settings_user')) { return 'modern'; } // figure out user defined theme if (isset($_SESSION['sess_user_id'])) { // fetch user defined theme $user_theme = db_fetch_cell_prepared("SELECT value FROM settings_user WHERE name='selected_theme' AND user_id = ?", array($_SESSION['sess_user_id']), '', false); // user has a theme if (! empty($user_theme)) { $theme = $user_theme;; } } if (!file_exists($config['base_path'] . '/include/themes/' . $theme . '/main.css')) { foreach($themes as $t => $name) { if (file_exists($config['base_path'] . '/include/themes/' . $t . '/main.css')) { $theme = $t; db_execute_prepared('UPDATE settings_user SET value = ? WHERE user_id = ? AND name="selected_theme"', array($theme, $_SESSION['sess_user_id'])); break; } } } // update session $_SESSION['selected_theme'] = $theme; return $theme; } /** * form_input_validate - validates the value of a form field and Takes the appropriate action if the input * is not valid * * @param $field_value - the value of the form field * @param $field_name - the name of the $_POST field as specified in the HTML * @param $regexp_match - (optionally) enter a regular expression to match the value against * @param $allow_nulls - (bool) whether to allow an empty string as a value or not * @param $custom_message - (int) the ID of the message to raise upon an error which is defined in the * $messages array in 'include/global_arrays.php' * * @return - the original $field_value */ function form_input_validate($field_value, $field_name, $regexp_match, $allow_nulls, $custom_message = 3) { global $messages; /* write current values to the "field_values" array so we can retain them */ $_SESSION['sess_field_values'][$field_name] = $field_value; if (($allow_nulls == true) && ($field_value == '')) { return $field_value; } if ($allow_nulls == false && $field_value == '') { if (read_config_option('log_validation') == 'on') { cacti_log("Form Validation Failed: Variable '$field_name' does not allow nulls and variable is null", false); } raise_message($custom_message); $_SESSION['sess_error_fields'][$field_name] = $field_name; } elseif ($regexp_match != '' && !preg_match('/' . $regexp_match . '/', $field_value)) { if (read_config_option('log_validation') == 'on') { cacti_log("Form Validation Failed: Variable '$field_name' with Value '$field_value' Failed REGEX '$regexp_match'", false); cacti_debug_backtrace('REGEX FAILURE'); } raise_message($custom_message); $_SESSION['sess_error_fields'][$field_name] = $field_name; } return $field_value; } /** * check_changed - determines if a request variable has changed between page loads * * @return - true if the value changed between loads */ function check_changed($request, $session) { if ((isset_request_var($request)) && (isset($_SESSION[$session]))) { if (get_nfilter_request_var($request) != $_SESSION[$session]) { return 1; } } } /** * is_error_message - finds whether an error message has been raised and has not been outputted to the * user * * @return - whether the messages array contains an error or not */ function is_error_message() { global $config, $messages; if (isset($_SESSION['sess_error_fields']) && cacti_sizeof($_SESSION['sess_error_fields'])) { return true; } else { return false; } } function get_message_level($current_message) { $current_level = MESSAGE_LEVEL_NONE; if (isset($current_message['level'])) { $current_level = $current_message['level']; } elseif (isset($current_message['type'])) { switch ($current_message['type']) { case 'error': $current_level = MESSAGE_LEVEL_ERROR; break; case 'info': $current_level = MESSAGE_LEVEL_INFO; break; } } return $current_level; } /** * get_format_message_instance - finds the level of the current message instance * * @param message array the message instance * * @return - a formatted message */ function get_format_message_instance($current_message) { if (is_array($current_message)) { $fmessage = isset($current_message['message']) ? $current_message['message'] : __esc('Message Not Found.'); } else { $fmessage = $current_message; } $level = get_message_level($current_message); switch ($level) { case MESSAGE_LEVEL_NONE: $message = '' . $fmessage . ''; break; case MESSAGE_LEVEL_INFO: $message = '' . $fmessage . ''; break; case MESSAGE_LEVEL_WARN: $message = '' . $fmessage . ''; break; case MESSAGE_LEVEL_ERROR: $message = '' . $fmessage . ''; break; case MESSAGE_LEVEL_CSRF: $message = '' . $fmessage . ''; break; default; $message = '' . $fmessage . ''; break; } return $message; } /** * get_message_max_type - finds the message and returns its type * * @return - the message type 'info', 'warn', 'error' or 'csrf' */ function get_message_max_type() { global $messages; $level = MESSAGE_LEVEL_NONE; if (isset($_SESSION['sess_messages'])) { if (is_array($_SESSION['sess_messages'])) { foreach ($_SESSION['sess_messages'] as $current_message_id => $current_message) { $current_level = get_message_level($current_message); if ($current_level == MESSAGE_LEVEL_NONE && isset($messages[$current_message_id])) { $current_level = get_message_level($messages[$current_message_id]); } if ($current_level != $level && $level != MESSAGE_LEVEL_NONE) { $level = MESSAGE_LEVEL_MIXED; } else { $level = $current_level; } } } } return $level; } /** * raise_message - mark a message to be displayed to the user once display_output_messages() is called * * @param $message_id - the ID of the message to raise as defined in $messages in 'include/global_arrays.php' */ function raise_message($message_id, $message = '', $message_level = MESSAGE_LEVEL_NONE) { global $config, $messages, $no_http_headers; // This function should always exist, if not its an invalid install if (function_exists('session_status')) { $need_session = (session_status() == PHP_SESSION_NONE) && (!isset($no_http_headers)); } else { return false; } if (empty($message)) { if (array_key_exists($message_id, $messages)) { $predefined = $messages[$message_id]; if (isset($predefined['message'])) { $message = $predefined['message']; } else { $message = $predefined; } if ($message_level == MESSAGE_LEVEL_NONE) { $message_level = get_message_level($predefined); } } elseif (isset($_SESSION[$message_id])) { $message = $_SESSION[$message_id]; $message_level = MESSAGE_LEVEL_ERROR; } else { $message = __('Message Not Found.'); $message_level = MESSAGE_LEVEL_ERROR; } } if ($need_session) { cacti_session_start(); } if (!isset($_SESSION['sess_messages'])) { $_SESSION['sess_messages'] = array(); } $_SESSION['sess_messages'][$message_id] = array('message' => $message, 'level' => $message_level); if ($need_session) { cacti_session_close(); } } /** * raise_message_javascript - raises a message that will appear in the UI * as the result of an server side error that can not be captured * normally. * * @param (string) The title for the dialog title bar * @param (string) Header section for the message * @param (string) The actual error message to display * * @return (void) */ function raise_message_javascript($title, $header, $message) { ?> array('level' => 3, 'message' => $_SESSION['sess_messages'])); } $omessage['level'] = get_message_max_type(); foreach ($_SESSION['sess_messages'] as $current_message_id => $current_message) { $message = get_format_message_instance($current_message); if (!empty($message)) { $omessage['message'] = (isset($omessage['message']) && $omessage['message'] != '' ? $omessage['message'] . '
':'') . $message; } else { cacti_log("ERROR: Cacti Error Message Id '$current_message_id' Not Defined", false, 'WEBUI'); } } } clear_messages(); return json_encode($omessage); } function display_custom_error_message($message) { raise_message('custom_error', $message); } /** * clear_messages - clears the message cache */ function clear_messages() { // This function should always exist, if not its an invalid install if (function_exists('session_status')) { $need_session = (session_status() == PHP_SESSION_NONE) && (!isset($no_http_headers)); } else { return false; } if ($need_session) { cacti_session_start(); } kill_session_var('sess_error_fields'); kill_session_var('sess_messages'); if ($need_session) { cacti_session_close(); } } /** * kill_session_var - kills a session variable using unset() */ function kill_session_var($var_name) { /* register_global = on: reset local settings cache so the user sees the new settings */ unset($_SESSION[$var_name]); /* register_global = off: reset local settings cache so the user sees the new settings */ /* session_unregister is deprecated in PHP 5.3.0, unset is sufficient */ if (version_compare(PHP_VERSION, '5.3.0', '<')) { session_unregister($var_name); } else { unset($var_name); } } /** * force_session_data - forces session data into the session if the session was closed for some reason */ function force_session_data() { // This function should always exist, if not its an invalid install if (!function_exists('session_status')) { return false; } elseif (session_status() == PHP_SESSION_NONE) { $data = $_SESSION; cacti_session_start(); $_SESSION = $data; cacti_session_close(); } } /** * array_rekey - changes an array in the form: * * '$arr[0] = array('id' => 23, 'name' => 'blah')' to the form * '$arr = array(23 => 'blah')' * * @param array $array The original array to manipulate * @param string $key The name of the key * @param string $key_value The name of the key value * * @return array the modified array */ function array_rekey($array, $key, $key_value) { $ret_array = array(); if (is_array($array)) { foreach ($array as $item) { $item_key = $item[$key]; if (is_array($key_value)) { foreach ($key_value as $value) { $ret_array[$item_key][$value] = $item[$value]; } } else { $ret_array[$item_key] = $item[$key_value]; } } } return $ret_array; } /** * cacti_log_file - returns the log filename */ function cacti_log_file() { global $config; $logfile = read_config_option('path_cactilog'); if ($logfile == '') { $logfile = $config['base_path'] . '/log/cacti.log'; } $config['log_path'] = $logfile; return $logfile; } function get_selective_log_level() { static $force_level = null; if ($force_level !== null) { return $force_level; } if (isset($_SERVER['PHP_SELF'])) { $current_file = basename($_SERVER['PHP_SELF']); $dir_name = dirname($_SERVER['PHP_SELF']); } elseif (isset($_SERVER['SCRIPT_NAME'])) { $current_file = basename($_SERVER['SCRIPT_NAME']); $dir_name = dirname($_SERVER['SCRIPT_NAME']); } elseif (isset($_SERVER['SCRIPT_FILENAME'])) { $current_file = basename($_SERVER['SCRIPT_FILENAME']); $dir_name = dirname($_SERVER['SCRIPT_FILENAME']); } else { $current_file = basename(__FILE__); $dir_name = dirname(__FILE__); } $force_level = ''; $debug_files = read_config_option('selective_debug'); if ($debug_files != '') { $files = explode(',', $debug_files); if (array_search($current_file, $files) !== false) { $force_level = POLLER_VERBOSITY_DEBUG; } } if (strpos($dir_name, 'plugins') !== false) { $debug_plugins = read_config_option('selective_plugin_debug'); if ($debug_plugins != '') { $debug_plugins = explode(',', $debug_plugins); foreach($debug_plugins as $myplugin) { if (strpos($dir_name, DIRECTORY_SEPARATOR . $myplugin) !== false) { $force_level = POLLER_VERBOSITY_DEBUG; break; } } } } return $force_level; } /** * cacti_log - logs a string to Cacti's log file or optionally to the browser * * @param $string - the string to append to the log file * @param $output - (bool) whether to output the log line to the browser using print() or not * @param $environ - (string) tells from where the script was called from * @param $level - (int) only log if above the specified log level */ function cacti_log($string, $output = false, $environ = 'CMDPHP', $level = '') { global $config, $database_log; static $start = null; if ($start == null) { $start = microtime(true); } if (!isset($database_log)) { $database_log = false; } if (trim($string) == '') { return false; } $last_log = $database_log; $database_log = false; $force_level = get_selective_log_level(); $oprefix = ''; $omessage = ''; /* only log if the specific level is reached, developer debug is special low + specific devdbg calls */ if ($force_level == '') { if ($level != '') { $logVerbosity = read_config_option('log_verbosity'); if ($logVerbosity == POLLER_VERBOSITY_DEVDBG) { if ($level != POLLER_VERBOSITY_DEVDBG) { if ($level > POLLER_VERBOSITY_LOW) { $database_log = $last_log; return; } } } elseif ($level > $logVerbosity) { $database_log = $last_log; return; } } } cacti_system_zone_set(); /* fill in the current date for printing in the log */ if (defined('CACTI_DATE_TIME_FORMAT')) { $date = date(CACTI_DATE_TIME_FORMAT); } else { $date = date('Y-m-d H:i:s'); } cacti_browser_zone_set(); /* determine how to log data */ $logdestination = read_config_option('log_destination'); $logfile = cacti_log_file(); /* format the message */ if ($environ == 'POLLER') { $prefix = "$date - " . $environ . ': Poller[' . $config['poller_id'] . '] PID[' . getmypid() . '] '; if ($output) { $oprefix = sprintf('Total[%3.4f] ', microtime(true) - $start); } } else { $prefix = "$date - " . $environ . ' '; if ($output) { $oprefix = $prefix; } } /* Log to Logfile */ $message = clean_up_lines($string) . PHP_EOL; if ($output) { $omessage = $oprefix . $message; } if (($logdestination == 1 || $logdestination == 2) && read_config_option('log_verbosity') != POLLER_VERBOSITY_NONE) { /* print the data to the log (append) */ $fp = @fopen($logfile, 'a'); if ($fp) { $message = $prefix . $message; @fwrite($fp, $message); fclose($fp); } } /* Log to Syslog/Eventlog */ /* Syslog is currently Unstable in Win32 */ if ($logdestination == 2 || $logdestination == 3) { $log_type = ''; if (strpos($string, 'ERROR:') !== false) { $log_type = 'err'; } elseif (strpos($string, 'WARNING:') !== false) { $log_type = 'warn'; } elseif (strpos($string, 'STATS:') !== false) { $log_type = 'stat'; } elseif (strpos($string, 'NOTICE:') !== false) { $log_type = 'note'; } if ($log_type != '') { if ($config['cacti_server_os'] == 'win32') { openlog('Cacti', LOG_NDELAY | LOG_PID, LOG_USER); } else { openlog('Cacti', LOG_NDELAY | LOG_PID, LOG_SYSLOG); } if ($log_type == 'err' && read_config_option('log_perror')) { syslog(LOG_CRIT, $environ . ': ' . $string); } elseif ($log_type == 'warn' && read_config_option('log_pwarn')) { syslog(LOG_WARNING, $environ . ': ' . $string); } elseif (($log_type == 'stat' || $log_type == 'note') && read_config_option('log_pstats')) { syslog(LOG_INFO, $environ . ': ' . $string); } closelog(); } } /* print output to standard out if required */ if ($output == true && isset($_SERVER['argv'][0])) { print $omessage; } $database_log = $last_log; } /** * tail_file - Emulates the tail function with PHP native functions. * It is used in 0.8.6 to speed the viewing of the Cacti log file, which * can be problematic in the 0.8.6 branch. * * @param $file_name - (char constant) the name of the file to tail * @param $line_cnt - (int constant) the number of lines to count * @param $message_type - (int constant) the type of message to return * @param $filter - (char) the filtering expression to search for * @param $page_nr - (int) the page we want to show rows for * @param $total_rows - (int) the total number of rows in the logfile * @param $matches - (bool) match or does not match the filter */ function tail_file($file_name, $number_of_lines, $message_type = -1, $filter = '', &$page_nr = 1, &$total_rows = 0, $matches = true) { if (!file_exists($file_name)) { touch($file_name); return array(); } if (!is_readable($file_name)) { return array(__('Error %s is not readable', $file_name)); } $filter = strtolower($filter); $fp = fopen($file_name, 'r'); /* Count all lines in the logfile */ $total_rows = 0; while (($line = fgets($fp)) !== false) { if (determine_display_log_entry($message_type, $line, $filter, $matches)) { ++$total_rows; } } // Reset the page count to 1 if the number of lines is exceeded if (($page_nr - 1) * $number_of_lines > $total_rows) { set_request_var('page', 1); $page_nr = 1; } /* rewind file pointer, to start all over */ rewind($fp); $start = $total_rows - ($page_nr * $number_of_lines); $end = $start + $number_of_lines; if ($start < 0) { $start = 0; } force_session_data(); /* load up the lines into an array */ $file_array = array(); $i = 0; while (($line = fgets($fp)) !== false) { $display = determine_display_log_entry($message_type, $line, $filter, $matches); if ($display === false) { continue; } if ($i < $start) { ++$i; continue; } if ($i >= $end) { break; } ++$i; $file_array[$i] = $line; } fclose($fp); return $file_array; } /** * determine_display_log_entry - function to determine if we display the line * * @param $message_type * @param $line * @param $filter * @param $matches * * @return - should the entry be displayed */ function determine_display_log_entry($message_type, $line, $filter, $matches = true) { static $thold_enabled = null; if ($thold_enabled == null) { $thold_enabled = api_plugin_is_enabled('thold'); } /* determine if we are to display the line */ switch ($message_type) { case 1: /* stats only */ $display = (strpos($line, 'STATS') !== false); break; case 2: /* warnings only */ $display = (strpos($line, 'WARN') !== false); break; case 3: /* warnings + */ $display = (strpos($line, 'WARN') !== false); if (!$display) { $display = (strpos($line, 'ERROR') !== false); } if (!$display) { $display = (strpos($line, 'DEBUG') !== false); } if (!$display) { $display = (strpos($line, ' SQL') !== false); } break; case 4: /* errors only */ $display = (strpos($line, 'ERROR') !== false); break; case 5: /* errors + */ $display = (strpos($line, 'ERROR') !== false); if (!$display) { $display = (strpos($line, 'DEBUG') !== false); } if (!$display) { $display = (strpos($line, ' SQL') !== false); } break; case 6: /* debug only */ $display = (strpos($line, 'DEBUG') !== false && strpos($line, ' SQL ') === false); break; case 7: /* sql calls only */ $display = (strpos($line, ' SQL ') !== false); break; case 8: /* AutoM8 Only */ $display = (strpos($line, 'AUTOM8') !== false); break; case 9: /* Non Stats */ $display = (strpos($line, 'STATS') === false); break; case 10: /* Boost Only*/ $display = (strpos($line, 'BOOST') !== false); break; case 11: /* device events + */ $display = (strpos($line, 'HOST EVENT') !== false); if (!$display) { $display = (strpos($line, '] is recovering!') !== false); } if (!$display) { $display = (strpos($line, '] is down!') !== false); } break; case 12: /* Assertions */ $display = (strpos($line, 'ASSERT FAILED') !== false); if (!$display) { $display = (strpos($line, 'Recache Event') !== false); } break; case -1: /* all */ $display = true; break; default: /* all other lines */ if ($thold_enabled) { if ($message_type == 99) { $display = (strpos($line, 'THOLD: Threshold') !== false); } } else { $display = true; } } /* match any lines that match the search string */ if ($display === true && $filter != '') { if ($matches) { if (validate_is_regex($filter) && preg_match('/' . $filter . '/i', $line)) { return $line; } elseif (stripos($line, $filter) !== false) { return $line; } } else { if (validate_is_regex($filter)) { if (!preg_match('/' . $filter . '/i', $line)) { return $line; } } elseif (!stripos($line, $filter) !== false) { return $line; } } return false; } return $display; } /** * update_host_status - updates the host table with information about its status. * It will also output to the appropriate log file when an event occurs. * * @param $status - (int constant) the status of the host (Up/Down) * @param $host_id - (int) the host ID for the results * @param $ping - (class array) results of the ping command. */ function update_host_status($status, $host_id, &$ping, $ping_availability, $print_data_to_stdout) { $issue_log_message = false; $ping_failure_count = read_config_option('ping_failure_count'); $ping_recovery_count = read_config_option('ping_recovery_count'); $host = db_fetch_row_prepared('SELECT * FROM host WHERE id = ?', array($host_id)); /* initialize fail and recovery dates correctly */ if ($host['status_fail_date'] == '') { $host['status_fail_date'] = strtotime('0000-00-00 00:00:00'); } if ($host['status_rec_date'] == '') { $host['status_rec_date'] = strtotime('0000-00-00 00:00:00'); } if ($status == HOST_DOWN) { /* Set initial date down. BUGFIX */ if (empty($host['status_fail_date'])) { $host['status_fail_date'] = time(); } /* update total polls, failed polls and availability */ $host['failed_polls']++; $host['total_polls']++; $host['availability'] = 100 * ($host['total_polls'] - $host['failed_polls']) / $host['total_polls']; /* determine the error message to display */ if (($ping_availability == AVAIL_SNMP_AND_PING) || ($ping_availability == AVAIL_SNMP_OR_PING)) { if (($host['snmp_community'] == '') && ($host['snmp_version'] != 3)) { /* snmp version 1/2 without community string assume SNMP test to be successful due to backward compatibility issues */ $host['status_last_error'] = $ping->ping_response; } else { $host['status_last_error'] = $ping->snmp_response . ', ' . $ping->ping_response; } } elseif ($ping_availability == AVAIL_SNMP) { if (($host['snmp_community'] == '') && ($host['snmp_version'] != 3)) { $host['status_last_error'] = 'Device does not require SNMP'; } else { $host['status_last_error'] = $ping->snmp_response; } } else { $host['status_last_error'] = $ping->ping_response; } /* determine if to send an alert and update remainder of statistics */ if ($host['status'] == HOST_UP) { /* increment the event failure count */ $host['status_event_count']++; /* if it's time to issue an error message, indicate so */ if ($host['status_event_count'] >= $ping_failure_count) { /* host is now down, flag it that way */ $host['status'] = HOST_DOWN; $issue_log_message = true; $host['status_fail_date'] = time(); $host['status_event_count'] = 0; } } elseif ($host['status'] == HOST_RECOVERING) { /* host is recovering, put back in failed state */ $host['status_event_count'] = 1; $host['status'] = HOST_DOWN; } elseif ($host['status'] == HOST_UNKNOWN) { /* host was unknown and now is down */ $host['status'] = HOST_DOWN; $host['status_event_count'] = 0; } else { $host['status_event_count']++; } } else { /* host is up. Update total polls and availability */ $host['total_polls']++; $host['availability'] = 100 * ($host['total_polls'] - $host['failed_polls']) / $host['total_polls']; if ((($ping_availability == AVAIL_SNMP_AND_PING) || ($ping_availability == AVAIL_SNMP_OR_PING) || ($ping_availability == AVAIL_SNMP)) && (!is_numeric($ping->snmp_status))) { $ping->snmp_status = 0.000; } if ((($ping_availability == AVAIL_SNMP_AND_PING) || ($ping_availability == AVAIL_SNMP_OR_PING) || ($ping_availability == AVAIL_PING)) && (!is_numeric($ping->ping_status))) { $ping->ping_status = 0.000; } /* determine the ping statistic to set and do so */ if (($ping_availability == AVAIL_SNMP_AND_PING) || ($ping_availability == AVAIL_SNMP_OR_PING)) { if (($host['snmp_community'] == '') && ($host['snmp_version'] != 3)) { $ping_time = 0.000; } else { /* calculate the average of the two times */ $ping_time = ($ping->snmp_status + $ping->ping_status) / 2; } } elseif ($ping_availability == AVAIL_SNMP) { if (($host['snmp_community'] == '') && ($host['snmp_version'] != 3)) { $ping_time = 0.000; } else { $ping_time = $ping->snmp_status; } } elseif ($ping_availability == AVAIL_NONE) { $ping_time = 0.000; } else { $ping_time = $ping->ping_status; } /* update times as required */ if (is_numeric($ping_time)) { $host['cur_time'] = $ping_time; /* maximum time */ if ($ping_time > $host['max_time']) { $host['max_time'] = $ping_time; } /* minimum time */ if ($ping_time < $host['min_time']) { $host['min_time'] = $ping_time; } /* average time */ $host['avg_time'] = (($host['total_polls'] - 1 - $host['failed_polls']) * $host['avg_time'] + $ping_time) / ($host['total_polls'] - $host['failed_polls']); } /* the host was down, now it's recovering */ if ($host['status'] == HOST_DOWN || $host['status'] == HOST_RECOVERING) { /* just up, change to recovering */ if ($host['status'] == HOST_DOWN) { $host['status'] = HOST_RECOVERING; $host['status_event_count'] = 1; } else { $host['status_event_count']++; } /* if it's time to issue a recovery message, indicate so */ if ($host['status_event_count'] >= $ping_recovery_count) { /* host is up, flag it that way */ $host['status'] = HOST_UP; $issue_log_message = true; $host['status_rec_date'] = time(); $host['status_event_count'] = 0; } } else { /* host was unknown and now is up */ $host['status'] = HOST_UP; $host['status_event_count'] = 0; } } /* if the user wants a flood of information then flood them */ if ($host['status'] == HOST_UP || $host['status'] == HOST_RECOVERING) { /* log ping result if we are to use a ping for reachability testing */ if ($ping_availability == AVAIL_SNMP_AND_PING) { cacti_log("Device[$host_id] PING: " . $ping->ping_response, $print_data_to_stdout, 'PING', POLLER_VERBOSITY_HIGH); cacti_log("Device[$host_id] SNMP: " . $ping->snmp_response, $print_data_to_stdout, 'PING', POLLER_VERBOSITY_HIGH); } elseif ($ping_availability == AVAIL_SNMP) { if (($host['snmp_community'] == '') && ($host['snmp_version'] != 3)) { cacti_log("Device[$host_id] SNMP: Device does not require SNMP", $print_data_to_stdout, 'PING', POLLER_VERBOSITY_HIGH); } else { cacti_log("Device[$host_id] SNMP: " . $ping->snmp_response, $print_data_to_stdout, 'PING', POLLER_VERBOSITY_HIGH); } } else { cacti_log("Device[$host_id] PING: " . $ping->ping_response, $print_data_to_stdout, 'PING', POLLER_VERBOSITY_HIGH); } } else { if ($ping_availability == AVAIL_SNMP_AND_PING) { cacti_log("Device[$host_id] PING: " . $ping->ping_response, $print_data_to_stdout, 'PING', POLLER_VERBOSITY_HIGH); cacti_log("Device[$host_id] SNMP: " . $ping->snmp_response, $print_data_to_stdout, 'PING', POLLER_VERBOSITY_HIGH); } elseif ($ping_availability == AVAIL_SNMP) { cacti_log("Device[$host_id] SNMP: " . $ping->snmp_response, $print_data_to_stdout, 'PING', POLLER_VERBOSITY_HIGH); } else { cacti_log("Device[$host_id] PING: " . $ping->ping_response, $print_data_to_stdout, 'PING', POLLER_VERBOSITY_HIGH); } } /* if there is supposed to be an event generated, do it */ if ($issue_log_message) { if ($host['status'] == HOST_DOWN) { cacti_log("Device[$host_id] ERROR: HOST EVENT: Device is DOWN Message: " . $host['status_last_error'], $print_data_to_stdout); } else { cacti_log("Device[$host_id] NOTICE: HOST EVENT: Device Returned FROM DOWN State: ", $print_data_to_stdout); } } db_execute_prepared('UPDATE host SET status = ?, status_event_count = ?, status_fail_date = FROM_UNIXTIME(?), status_rec_date = FROM_UNIXTIME(?), status_last_error = ?, min_time = ?, max_time = ?, cur_time = ?, avg_time = ?, total_polls = ?, failed_polls = ?, availability = ? WHERE hostname = ? AND deleted = ""', array( $host['status'], $host['status_event_count'], $host['status_fail_date'], $host['status_rec_date'], $host['status_last_error'], $host['min_time'], $host['max_time'], $host['cur_time'], $host['avg_time'], $host['total_polls'], $host['failed_polls'], $host['availability'], $host['hostname'] ) ); } /** * is_hexadecimal - test whether a string represents a hexadecimal number, * ignoring space and tab, and case insensitive. * * @param $result - the string to test * @param 1 if the argument is hex, 0 otherwise, and false on error */ function is_hexadecimal($result) { $hexstr = str_replace(array(' ', '-'), ':', trim($result)); $parts = explode(':', $hexstr); foreach($parts as $part) { if (strlen($part) != 2) { return false; } if (ctype_xdigit($part) == false) { return false; } } return true; } /** * strip_domain - removes the domain from a hostname * * @param $hostname - the hostname for a device * * @return - the stripped hostname */ function strip_domain($hostname) { if (is_ipaddress($hostname)) { return $hostname; } elseif (read_config_option('strip_domain') == 'on') { $parts = explode('.', $hostname); return $parts[0]; } else { return $hostname; } } /** * is_mac_address - determines if the result value is a mac address * * @param $result - some string to be evaluated * * @return - either to result is a mac address of not */ function is_mac_address($result) { if (!defined('FILTER_VALIDATE_MAC')) { if (preg_match('/^([0-9a-f]{1,2}[\.:-]) {5}([0-9a-f]{1,2})$/i', $result)) { return true; } else { return false; } } else { return filter_var($result, FILTER_VALIDATE_MAC); } } function is_hex_string(&$result) { if ($result == '') { return false; } $compare = strtolower($result); /* strip off the 'Hex:, Hex-, and Hex-STRING:' * Hex- is considered due to the stripping of 'String:' in * lib/snmp.php */ if (substr($compare, 0, 4) == 'hex-') { $check = trim(str_ireplace('hex-', '', $result)); } elseif (substr($compare, 0, 11) == 'hex-string:') { $check = trim(str_ireplace('hex-string:', '', $result)); } else { return false; } $parts = explode(' ', $check); /* assume if something is a hex string it will have a length > 1 */ if (cacti_sizeof($parts) == 1) { return false; } foreach($parts as $part) { if (strlen($part) != 2) { return false; } if (ctype_xdigit($part) == false) { return false; } } $result = $check; return true; } /** * prepare_validate_result - determines if the result value is valid or not. If not valid returns a "U" * * @param $result - the result from the poll, the result can be modified in the call * * @return - either to result is valid or not */ function prepare_validate_result(&$result) { /* first trim the string */ $result = trim($result, "'\"\n\r"); /* clean off ugly non-numeric data */ if (is_numeric($result)) { dsv_log('prepare_validate_result','data is numeric', POLLER_VERBOSITY_MEDIUM); return true; } elseif ($result == 'U') { dsv_log('prepare_validate_result', 'data is U', POLLER_VERBOSITY_MEDIUM); return true; } elseif (is_hexadecimal($result)) { dsv_log('prepare_validate_result', 'data is hex', POLLER_VERBOSITY_MEDIUM); return hexdec($result); } elseif (substr_count($result, ':') || substr_count($result, '!')) { /* looking for name value pairs */ if (substr_count($result, ' ') == 0) { dsv_log('prepare_validate_result', 'data has no spaces', POLLER_VERBOSITY_MEDIUM); return true; } else { $delim_cnt = 0; if (substr_count($result, ':')) { $delim_cnt = substr_count($result, ':'); } elseif (strstr($result, '!')) { $delim_cnt = substr_count($result, '!'); } $space_cnt = substr_count(trim($result), ' '); dsv_log('prepare_validate_result', "data has $space_cnt spaces and $delim_cnt fields which is " . (($space_cnt + 1 == $delim_cnt) ? '' : 'NOT') . ' okay', POLLER_VERBOSITY_MEDIUM); return ($space_cnt+1 == $delim_cnt); } } else { $result = strip_alpha($result); if ($result === false) { $result = 'U'; return false; } else { return true; } } } /** * strip_alpha - remove non-numeric data from a string and return the numeric part * * @param $string - the string to be evaluated * * @return - either the numeric value or false if not numeric */ function strip_alpha($string) { /* strip all non numeric data */ $string = trim(preg_replace('/[^0-9,.+-]/', '', $string)); /* check the easy cases first */ /* it has no delimiters, and no space, therefore, must be numeric */ if (is_numeric($string) || is_float($string)) { return $string; } else { return false; } } /** * is_valid_pathname - takes a pathname are verifies it matches file name rules * * @param $path - the pathname to be tested * * @return - either true or false */ function is_valid_pathname($path) { if (preg_match('/^([a-zA-Z0-9\_\.\-\\\:\/]+)$/', trim($path))) { return true; } else { return false; } } /** * dsv_log - provides debug logging when tracing Graph/Data Source creation * * @param $message - the message to output to the log * @param $data - the data to be carried with the message * @param $level - the level to log the dsv_log at or above */ function dsv_log($message, $data = null, $level = POLLER_VERBOSITY_LOW) { if (read_config_option('data_source_trace') == 'on') { cacti_log(($message . ' = ') . (is_array($data) ? json_encode($data) : ($data === null ? 'NULL' : $data)), false, 'DSTRACE', $level); } } /** * test_data_sources * * Tests all data sources to confirm that it returns valid data. This * function is used by automation to prevent the creation of graphs * that will never generate data. * * @param $graph_template_id - The Graph Template to test * @param $host_id - The Host to test * * @return boolean true or false */ function test_data_sources($graph_template_id, $host_id, $snmp_query_id = 0, $snmp_index = '', $values = array()) { $data_template_ids = array_rekey( db_fetch_assoc_prepared('SELECT DISTINCT data_template_id FROM graph_templates_item AS gti INNER JOIN data_template_rrd AS dtr ON gti.task_item_id = dtr.id WHERE gti.hash != "" AND gti.local_graph_id = 0 AND dtr.local_data_id = 0 AND gti.graph_template_id = ?', array($graph_template_id)), 'data_template_id', 'data_template_id' ); $test_source = db_fetch_cell_prepared('SELECT test_source FROM graph_templates WHERE id = ?', array($graph_template_id)); if (cacti_sizeof($data_template_ids) && $test_source == 'on') { foreach($data_template_ids as $dt) { dsv_log("test_data_source", [ 'dt' => $dt, 'host_id' => $host_id, 'snmp_query_id' => $snmp_query_id, 'snmp_index' => $snmp_index, 'values' => $values]); if (!test_data_source($dt, $host_id, $snmp_query_id, $snmp_index, $values)) { return false; } } } return true; } /** * test_data_source * * Tests a single data source to confirm that it returns valid data. This * function is used by automation to prevent the creation of graphs * that will never generate data. * * @param $graph_template_id - The Graph Template to test * @param $host_id - The Host to test * * @return boolean true or false */ function test_data_source($data_template_id, $host_id, $snmp_query_id = 0, $snmp_index = '', $suggested_vals = array()) { global $called_by_script_server; $called_by_script_server = true; dsv_log('test_data_source', [ 'data_template_id' => $data_template_id, 'host_id' => $host_id, 'snmp_query_id' => $snmp_query_id, 'snmp_index' => $snmp_index, 'suggested_vals' => $suggested_vals]); $data_input = db_fetch_row_prepared('SELECT ' . SQL_NO_CACHE . ' di.id, di.type_id, dtd.id AS data_template_data_id, dtd.data_template_id, dtd.active, dtd.rrd_step, di.name FROM data_template_data AS dtd INNER JOIN data_input AS di ON dtd.data_input_id=di.id WHERE dtd.local_data_id = 0 AND dtd.data_template_id = ?', array($data_template_id)); dsv_log('data_input', $data_input); $host = db_fetch_row_prepared('SELECT ' . SQL_NO_CACHE . ' * FROM host WHERE id = ?', array($host_id)); dsv_log('host', $host); $data_template_data_id = 0; if (cacti_sizeof($data_input) && $data_input['active'] == 'on') { $data_template_data_id = $data_input['data_template_data_id']; /* we have to perform some additional sql queries if this is a 'query' */ if (($data_input['type_id'] == DATA_INPUT_TYPE_SNMP_QUERY) || ($data_input['type_id'] == DATA_INPUT_TYPE_SCRIPT_QUERY) || ($data_input['type_id'] == DATA_INPUT_TYPE_QUERY_SCRIPT_SERVER)) { $field = data_query_field_list($data_template_data_id); dsv_log('query field', $field); $params = array(); $params[] = $data_input['data_template_id']; if ($field['output_type'] != '') { $output_type_sql = ' AND sqgr.snmp_query_graph_id = ?'; $params[] = $field['output_type']; } else { $output_type_sql = ''; } $outputs_sql = 'SELECT DISTINCT ' . SQL_NO_CACHE . " sqgr.snmp_field_name, dtr.id as data_template_rrd_id FROM snmp_query_graph_rrd AS sqgr INNER JOIN data_template_rrd AS dtr ON sqgr.data_template_rrd_id = dtr.id WHERE sqgr.data_template_id = ? AND dtr.local_data_id = 0 $output_type_sql ORDER BY dtr.id"; dsv_log('outputs_sql', $outputs_sql); dsv_log('outputs_params', $params); $outputs = db_fetch_assoc_prepared($outputs_sql, $params); dsv_log('outputs', $outputs); } if (($data_input['type_id'] == DATA_INPUT_TYPE_SCRIPT) || ($data_input['type_id'] == DATA_INPUT_TYPE_PHP_SCRIPT_SERVER)) { if ($data_input['type_id'] == DATA_INPUT_TYPE_PHP_SCRIPT_SERVER) { $action = POLLER_ACTION_SCRIPT_PHP; } else { $action = POLLER_ACTION_SCRIPT; } $script_path = get_full_test_script_path($data_template_id, $host_id); dsv_log('script_path', $script_path); $num_output_fields_sql = 'SELECT ' . SQL_NO_CACHE . ' id FROM data_input_fields WHERE data_input_id = ? AND input_output = "out" AND update_rra="on"'; dsv_log('num_output_fields_sql',$num_output_fields_sql); $num_output_fields = cacti_sizeof(db_fetch_assoc_prepared($num_output_fields_sql, array($data_input['id']))); dsv_log('num_output_fields', $num_output_fields); if ($num_output_fields == 1) { $data_template_rrd_id = db_fetch_cell_prepared('SELECT ' . SQL_NO_CACHE . ' id FROM data_template_rrd WHERE local_data_id = 0 AND hash != "" AND data_template_id = ?', array($data_template_id)); $data_source_item_name = get_data_source_item_name($data_template_rrd_id); } else { $data_source_item_name = ''; } dsv_log('data_source_item_name', $data_source_item_name); if ($action == POLLER_ACTION_SCRIPT) { dsv_log('script_path', $script_path); $output = shell_exec($script_path); } else { // Script server is a bit more complicated $php = read_config_option('path_php_binary'); $parts = explode(' ', $script_path); dsv_log('parts', $parts); if (file_exists($parts[0])) { unset($parts[1]); $script = implode(' ', $parts); dsv_log('script', $script); $output = shell_exec("$php -q $script"); if ($output == '' || $output == false) { $output = 'U'; } } else { $output = 'U'; } } dsv_log('output', $output); if (!is_numeric($output)) { if ($output == 'U') { return false; } elseif (strpos($output, ':U') !== false) { return false; } elseif (prepare_validate_result($output) === false) { return false; } } return true; } elseif ($data_input['type_id'] == DATA_INPUT_TYPE_SNMP) { /* get host fields first */ $host_fields_sql = 'SELECT ' . SQL_NO_CACHE . ' dif.id, dif.type_code, did.value FROM data_input_fields AS dif LEFT JOIN data_input_data AS did ON dif.id=did.data_input_field_id WHERE (type_code LIKE "snmp_%" OR type_code IN("hostname","host_id")) AND did.data_template_data_id = ? AND did.value != ""'; dsv_log('host_fields_sql', $host_fields_sql); dsv_log('host_fields_sql_params', ['data_template_data_id' => $data_template_data_id]); $host_fields = array_rekey( db_fetch_assoc_prepared($host_fields_sql, array($data_template_data_id)), 'type_code', 'value' ); dsv_log('SNMP host_fields', $host_fields); $data_template_data = db_fetch_assoc_prepared('SELECT ' . SQL_NO_CACHE . ' dif.id, dif.type_code, did.value FROM data_input_fields AS dif LEFT JOIN data_input_data AS did ON dif.id = did.data_input_field_id WHERE (type_code LIKE "snmp_%" OR type_code="hostname") AND did.data_template_data_id = ?', array($data_template_data_id)); dsv_log('SNMP data_template_data', $data_template_data); if (cacti_sizeof($data_template_data)) { foreach ($data_template_data as $field) { $key = $field['type_code']; $value = $field['value']; dsv_log('SNMP field', $field); dsv_log('SNMP value', $value); if (!empty($suggested_vals['custom_data'][$data_template_id][$field['id']])) { $value = $suggested_vals['custom_data'][$data_template_id][$field['id']]; dsv_log("SNMP value replace suggested $key", $value); } if (!empty($value) && !isset($host_fields[$key])) { $host_fields[$key] = $value; dsv_log("SNMP value replace template $key", $value); } } } dsv_log('SNMP [updated] host_fields', $host_fields); $host = array_merge($host, $host_fields); dsv_log('SNMP [updated] host', $host); $session = cacti_snmp_session($host['hostname'], $host['snmp_community'], $host['snmp_version'], $host['snmp_username'], $host['snmp_password'], $host['snmp_auth_protocol'], $host['snmp_priv_passphrase'], $host['snmp_priv_protocol'], $host['snmp_context'], $host['snmp_engine_id'], $host['snmp_port'], $host['snmp_timeout'], $host['ping_retries'], $host['max_oids']); $output = cacti_snmp_session_get($session, $host['snmp_oid']); dsv_log('SNMP output', $output); if (!is_numeric($output)) { if (prepare_validate_result($output) === false) { return false; } } return true; } elseif ($data_input['type_id'] == DATA_INPUT_TYPE_SNMP_QUERY) { $snmp_queries = get_data_query_array($snmp_query_id); /* get host fields first */ $host_fields = array_rekey( db_fetch_assoc_prepared('SELECT ' . SQL_NO_CACHE . ' dif.id, dif.type_code, did.value FROM data_input_fields AS dif LEFT JOIN data_input_data AS did ON dif.id=did.data_input_field_id WHERE (type_code LIKE "snmp_%" OR type_code="hostname") AND did.data_template_data_id = ? AND did.value != ""', array($data_template_data_id)), 'type_code', 'value' ); dsv_log('SNMP_QUERY host_fields', $host_fields); $data_template_data = db_fetch_assoc_prepared('SELECT ' . SQL_NO_CACHE . ' dif.id, dif.type_code, did.value FROM data_input_fields AS dif LEFT JOIN data_input_data AS did ON dif.id=did.data_input_field_id WHERE (type_code LIKE "snmp_%" OR type_code="hostname") AND did.data_template_data_id = ?', array($data_template_data_id)); dsv_log('SNMP_QUERY data_template_data', $data_template_data); if (cacti_sizeof($data_template_data)) { foreach ($data_template_data as $field) { $key = $field['type_code']; $value = $field['value']; dsv_log('SNMP_QUERY field', $field); if (!empty($suggested_vals['custom_data'][$data_template_id][$field['id']])) { $value = $suggested_vals['custom_data'][$data_template_id][$field['id']]; dsv_log("SNMP_QUERY value replace suggested $key", $value); } if (!empty($value) && !isset($host_fields[$key])) { $host_fields[$key] = $value; dsv_log("SNMP_QUERY value replace template $key", $value); } } } dsv_log('SNMP_QUERY [updated] host_fields', $host_fields); $host = array_merge($host, $host_fields); dsv_log('SNMP_QUERY [updated] host', $host); if (cacti_sizeof($outputs) && cacti_sizeof($snmp_queries)) { foreach ($outputs as $output) { if (isset($snmp_queries['fields'][$output['snmp_field_name']]['oid'])) { $oid = $snmp_queries['fields'][$output['snmp_field_name']]['oid'] . '.' . $snmp_index; if (isset($snmp_queries['fields'][$output['snmp_field_name']]['oid_suffix'])) { $oid .= '.' . $snmp_queries['fields'][$output['snmp_field_name']]['oid_suffix']; } } if (!empty($oid)) { $session = cacti_snmp_session($host['hostname'], $host['snmp_community'], $host['snmp_version'], $host['snmp_username'], $host['snmp_password'], $host['snmp_auth_protocol'], $host['snmp_priv_passphrase'], $host['snmp_priv_protocol'], $host['snmp_context'], $host['snmp_engine_id'], $host['snmp_port'], $host['snmp_timeout'], $host['ping_retries'], $host['max_oids']); $output = cacti_snmp_session_get($session, $oid); if (!is_numeric($output)) { if (prepare_validate_result($output) === false) { return false; } } return true; } } } } elseif (($data_input['type_id'] == DATA_INPUT_TYPE_SCRIPT_QUERY) || ($data_input['type_id'] == DATA_INPUT_TYPE_QUERY_SCRIPT_SERVER)) { $script_queries = get_data_query_array($snmp_query_id); /* get host fields first */ $host_fields = array_rekey( db_fetch_assoc_prepared('SELECT ' . SQL_NO_CACHE . ' dif.id, dif.type_code, did.value FROM data_input_fields AS dif LEFT JOIN data_input_data AS did ON dif.id=did.data_input_field_id WHERE (type_code LIKE "snmp_%" OR type_code="hostname") AND did.data_template_data_id = ? AND did.value != ""', array($data_template_data_id)), 'type_code', 'value' ); dsv_log('SCRIPT host_fields', $host_fields); $data_template_fields = array_rekey( db_fetch_assoc_prepared('SELECT ' . SQL_NO_CACHE . ' dif.id, dif.type_code, did.value FROM data_input_fields AS dif LEFT JOIN data_input_data AS did ON dif.id=did.data_input_field_id WHERE (type_code LIKE "snmp_%" OR type_code="hostname") AND did.data_template_data_id = ? AND did.value != ""', array($data_template_data_id)), 'type_code', 'value' ); $data_template_data = db_fetch_assoc_prepared('SELECT ' . SQL_NO_CACHE . ' dif.id, dif.type_code, did.value FROM data_input_fields AS dif LEFT JOIN data_input_data AS did ON dif.id=did.data_input_field_id WHERE (type_code LIKE "snmp_%" OR type_code="hostname") AND did.data_template_data_id = ?', array($data_template_data_id)); dsv_log('SCRIPT data_template_data', $data_template_data); if (cacti_sizeof($data_template_data)) { foreach ($data_template_data as $field) { $key = $field['type_code']; $value = $field['value']; dsv_log('SCRIPT field', $field); if (!empty($suggested_vals['custom_data'][$data_template_id][$field['id']])) { $value = $suggested_vals['custom_data'][$data_template_id][$field['id']]; dsv_log("SCRIPT value replace suggested $key", $value); } if (!empty($value) && !isset($host_fields[$key])) { $host_fields[$key] = $value; dsv_log("SCRIPT value replace template $key", $value); } } } dsv_log('SCRIPT [updated] host_fields', $host_fields); $host = array_merge($host, $host_fields); dsv_log('SCRIPT [updated] host', $host); if (cacti_sizeof($outputs) && cacti_sizeof($script_queries)) { foreach ($outputs as $output) { if (isset($script_queries['fields'][$output['snmp_field_name']]['query_name'])) { $identifier = $script_queries['fields'][$output['snmp_field_name']]['query_name']; if ($data_input['type_id'] == DATA_INPUT_TYPE_QUERY_SCRIPT_SERVER) { $action = POLLER_ACTION_SCRIPT; $prepend = ''; if (isset($script_queries['arg_prepend']) && $script_queries['arg_prepend'] != '') { $prepend = $script_queries['arg_prepend']; } $script_path = read_config_option('path_php_binary') . ' -q ' . get_script_query_path(trim($prepend . ' ' . $script_queries['arg_get'] . ' ' . $identifier . ' ' . $snmp_index), $script_queries['script_path'], $host_id); } else { $action = POLLER_ACTION_SCRIPT; $script_path = get_script_query_path(trim((isset($script_queries['arg_prepend']) ? $script_queries['arg_prepend'] : '') . ' ' . $script_queries['arg_get'] . ' ' . $identifier . ' ' . $snmp_index), $script_queries['script_path'], $host_id); } } if (isset($script_path)) { $output = shell_exec($script_path); if (!is_numeric($output)) { if (prepare_validate_result($output) === false) { return false; } } return true; } } } } } return false; } /** * get_full_test_script_path - gets the full path to the script to execute to obtain data for a * given data template for testing. this function does not work on SNMP actions, only * script-based actions * * @param $data_template_id - (int) the ID of the data template * * @return string - the full script path or (bool) false for an error */ function get_full_test_script_path($data_template_id, $host_id) { global $config; $data_source = db_fetch_row_prepared('SELECT ' . SQL_NO_CACHE . ' dtd.id, dtd.data_input_id, di.type_id, di.input_string FROM data_template_data AS dtd INNER JOIN data_input AS di ON dtd.data_input_id = di.id WHERE dtd.local_data_id = 0 AND dtd.data_template_id = ?', array($data_template_id)); $data = db_fetch_assoc_prepared("SELECT " . SQL_NO_CACHE . " dif.data_name, did.value FROM data_input_fields AS dif LEFT JOIN data_input_data AS did ON dif.id = did.data_input_field_id WHERE dif.data_input_id = ? AND did.data_template_data_id = ? AND dif.input_output = 'in'", array($data_source['data_input_id'], $data_source['id'])); $full_path = $data_source['input_string']; $host = db_fetch_row_prepared('SELECT * FROM host WHERE id = ?', array($host_id)); if (cacti_sizeof($data)) { foreach ($data as $item) { if (isset($host[$item['data_name']])) { $value = cacti_escapeshellarg($host[$item['data_name']]); } elseif ($item['data_name'] == 'host_id' || $item['data_name'] == 'hostid') { $value = cacti_escapeshellarg($host['id']); } else { $value = "'" . $item['value'] . "'"; } $full_path = str_replace('<' . $item['data_name'] . '>', $value, $full_path); } } $search = array('', '', ''); $replace = array($config['base_path'], read_config_option('path_snmpget'), read_config_option('path_php_binary')); $full_path = str_replace($search, $replace, $full_path); /** * sometimes a certain input value will not have anything entered... null out these fields * in the input string so we don't mess up the script */ return preg_replace('/(<[A-Za-z0-9_]+>)+/', '', $full_path); } /** * get_full_script_path - gets the full path to the script to execute to obtain data for a * given data source. this function does not work on SNMP actions, only script-based actions * * @param $local_data_id - (int) the ID of the data source * * @return - the full script path or (bool) false for an error */ function get_full_script_path($local_data_id) { global $config; $data_source = db_fetch_row_prepared('SELECT ' . SQL_NO_CACHE . ' dtd.id, dtd.data_input_id, di.type_id, di.input_string FROM data_template_data AS dtd INNER JOIN data_input AS di ON dtd.data_input_id = di.id WHERE dtd.local_data_id = ?', array($local_data_id)); /* snmp-actions don't have paths */ if (($data_source['type_id'] == DATA_INPUT_TYPE_SNMP) || ($data_source['type_id'] == DATA_INPUT_TYPE_SNMP_QUERY)) { return false; } $data = db_fetch_assoc_prepared("SELECT " . SQL_NO_CACHE . " dif.data_name, did.value FROM data_input_fields AS dif LEFT JOIN data_input_data AS did ON dif.id = did.data_input_field_id WHERE dif.data_input_id = ? AND did.data_template_data_id = ? AND dif.input_output = 'in'", array($data_source['data_input_id'], $data_source['id'])); $full_path = $data_source['input_string']; if (cacti_sizeof($data)) { foreach ($data as $item) { $value = cacti_escapeshellarg($item['value']); if ($value == '') { $value = "''"; } $full_path = str_replace('<' . $item['data_name'] . '>', $value, $full_path); } } $search = array('', '', ''); $replace = array($config['base_path'], read_config_option('path_snmpget'), read_config_option('path_php_binary')); $full_path = str_replace($search, $replace, $full_path); /* sometimes a certain input value will not have anything entered... null out these fields in the input string so we don't mess up the script */ return preg_replace('/(<[A-Za-z0-9_]+>)+/', '', $full_path); } /** * get_data_source_item_name - gets the name of a data source item or generates a new one if one does not * already exist * * @param $data_template_rrd_id - (int) the ID of the data source item * * @return - the name of the data source item or an empty string for an error */ function get_data_source_item_name($data_template_rrd_id) { if (empty($data_template_rrd_id)) { return ''; } $data_source = db_fetch_row_prepared('SELECT ' . SQL_NO_CACHE . ' dtr.data_source_name, dtd.name FROM data_template_rrd AS dtr INNER JOIN data_template_data AS dtd ON dtr.local_data_id = dtd.local_data_id WHERE dtr.id = ?', array($data_template_rrd_id) ); /* use the cacti ds name by default or the user defined one, if entered */ if (empty($data_source['data_source_name'])) { /* limit input to 19 characters */ $data_source_name = clean_up_name($data_source['name']); $data_source_name = substr(strtolower($data_source_name), 0, (19-strlen($data_template_rrd_id))) . $data_template_rrd_id; return $data_source_name; } else { return $data_source['data_source_name']; } } /** * get_data_source_path - gets the full path to the .rrd file associated with a given data source * * @param $local_data_id - (int) the ID of the data source * @param $expand_paths - (bool) whether to expand the variable into its full path or not * * @return - the full path to the data source or an empty string for an error */ function get_data_source_path($local_data_id, $expand_paths) { global $config; static $data_source_path_cache = array(); if (empty($local_data_id)) { return ''; } if (isset($data_source_path_cache[$local_data_id])) { return $data_source_path_cache[$local_data_id]; } $data_source = db_fetch_row_prepared('SELECT name, data_source_path FROM data_template_data AS dtd WHERE local_data_id = ?', array($local_data_id)); if (cacti_sizeof($data_source)) { if (empty($data_source['data_source_path'])) { /* no custom path was specified */ $data_source_path = generate_data_source_path($local_data_id); } elseif (!strstr($data_source['data_source_path'], '/')) { $data_source_path = '/' . $data_source['data_source_path']; } else { $data_source_path = $data_source['data_source_path']; } /* whether to show the "actual" path or the variable name (for edit boxes) */ if ($expand_paths == true) { $data_source_path = str_replace('/', $config['rra_path'] . '/', $data_source_path); } $data_source_path_cache[$local_data_id] = $data_source_path; return $data_source_path; } } /** * stri_replace - a case insensitive string replace * * @param $find - needle * @param $replace - replace needle with this * @param $string - haystack * * @return - the original string with '$find' replaced by '$replace' */ function stri_replace($find, $replace, $string) { $parts = explode(strtolower($find), strtolower($string)); $pos = 0; $findLength = strlen($find); foreach ($parts as $key => $part) { $partLength = strlen($part); $parts[$key] = substr($string, $pos, $partLength); $pos += $partLength + $findLength; } return (join($replace, $parts)); } /** * clean_up_lines - runs a string through a regular expression designed to remove * new lines and the spaces around them * * @param $string - the string to modify/clean * * @return string The modified string */ function clean_up_lines($string) { if ($string != '') { return preg_replace('/\s*[\r\n]+\s*/',' ', $string); } else { return $string; } } /** * clean_up_name - runs a string through a series of regular expressions designed to * eliminate "bad" characters * * @param $string - the string to modify/clean * * @return string The modified string */ function clean_up_name($string) { if ($string != '') { $string = preg_replace('/[\s\.]+/', '_', $string); $string = preg_replace('/[^a-zA-Z0-9_]+/', '', $string); $string = preg_replace('/_{2,}/', '_', $string); } return $string; } /** * clean_up_file name - runs a string through a series of regular expressions designed to * eliminate "bad" characters * * @param $string - the string to modify/clean * * @return string The modified string */ function clean_up_file_name($string) { if ($string != '') { $string = preg_replace('/[\s\.]+/', '_', $string); $string = preg_replace('/[^a-zA-Z0-9_-]+/', '', $string); $string = preg_replace('/_{2,}/', '_', $string); } return $string; } /** * clean_up_path - takes any path and makes sure it contains the correct directory * separators based on the current operating system * * @param $path - the path to modify * * @return - the modified path */ function clean_up_path($path) { global $config; if ($config['cacti_server_os'] == 'win32') { return str_replace('/', "\\", $path); } elseif ($config['cacti_server_os'] == 'unix' || read_config_option('using_cygwin') == 'on' || read_config_option('storage_location')) { return str_replace("\\", '/', $path); } else { return $path; } } /** * get_data_source_title - returns the title of a data source without using the title cache * * @param $local_data_id - (int) the ID of the data source to get a title for * * @return - the data source title */ function get_data_source_title($local_data_id) { $data = db_fetch_row_prepared('SELECT dl.host_id, dl.snmp_query_id, dl.snmp_index, dl.data_template_id, dtd.name, dtd.id as template_id FROM data_local AS dl LEFT JOIN data_template_data AS dtd ON dtd.local_data_id = dl.id WHERE dl.id = ?', array($local_data_id)); $title = 'Missing Datasource ' . $local_data_id; if (cacti_sizeof($data)) { if (strstr($data['name'], '|') !== false && $data['host_id'] > 0) { $data['name'] = substitute_data_input_data($data['name'], '', $local_data_id); $title = expand_title($data['host_id'], $data['snmp_query_id'], $data['snmp_index'], $data['name']); } else { $title = $data['name']; } // Is the data source linked to a template? If so, make sure we have a template on the // LEFT JOIN since it may not find one. Also, we can't check that they are the same ID // ID yet because there are two, one with a 0 local_data_id (base template) and one with // this source's id (instance of template). if ($data['data_template_id'] && !$data['template_id']) { $title .= ' (Bad template "' . $data['data_template_id'] . '")'; } } return $title; } /** * get_device_name - returns the description of the device in cacti host table * * @param $host_id - (int) the ID of the device to get a description for * * @return - the device name */ function get_device_name($host_id) { return db_fetch_cell_prepared('SELECT description FROM host WHERE id = ?', array($host_id)); } /** * get_color - returns the hex color value from the cacti colors table * * @param $color_id - (int) the ID of the cacti color * @return - the hex color value * */ function get_color($color_id) { return db_fetch_cell_prepared('SELECT hex FROM colors WHERE id = ?', array($color_id)); } /** * get_graph_title_cache - returns the title of the graph using the title cache * * @param $local_graph_id - (int) the ID of the graph to get the title for * * @return - the graph title */ function get_graph_title_cache($local_graph_id) { return db_fetch_cell_prepared('SELECT title_cache FROM graph_templates_graph WHERE local_graph_id = ?', array($local_graph_id)); } /** * get_graph_title - returns the title of a graph without using the title cache * * @param $local_graph_id - (int) the ID of the graph to get a title for * * @return string The graph title */ function get_graph_title($local_graph_id) { $graph = db_fetch_row_prepared('SELECT gl.host_id, gl.snmp_query_id, gl.snmp_index, gtg.local_graph_id, gtg.t_title, gtg.title FROM graph_templates_graph AS gtg INNER JOIN graph_local AS gl ON gtg.local_graph_id = gl.id WHERE gl.id = ?', array($local_graph_id)); if (cacti_sizeof($graph)) { if (strstr($graph['title'], '|') !== false && $graph['host_id'] > 0 && empty($graph['t_title'])) { $graph['title'] = substitute_data_input_data($graph['title'], $graph, 0); return expand_title($graph['host_id'], $graph['snmp_query_id'], $graph['snmp_index'], $graph['title']); } else { return $graph['title']; } } else { return ''; } } /** * get_guest_account - return the guest account as defined in the system * if there is one, else return 0. * * @return (int) the guest account if greater than 0 */ function get_guest_account() { $user = db_fetch_cell_prepared('SELECT id FROM user_auth WHERE username = ? OR id = ?', array(read_config_option('guest_user'), read_config_option('guest_user'))); if (empty($user)) { return 0; } else { return $user; } } /** * get_template_account - return the template account given a user. * if a user is not given, provide the 'default' template account. * This function is hookable by third party plugins. * * @param (int|string) either the username or user_id of the user * * @return (int) the template account if one exist for the user */ function get_template_account($user = '') { if ($user == '') { // no username or user_id passed, use default functionality $user = db_fetch_cell_prepared('SELECT id FROM user_auth WHERE username = ? OR id = ?', array(read_config_option('user_template'), read_config_option('user_template'))); if (empty($user)) { return 0; } else { return $user; } } else { $template = api_plugin_hook_function('get_template_account', $user); if ($template == $user) { // no plugin present, use default functionality $user = db_fetch_cell_prepared('SELECT id FROM user_auth WHERE username = ? OR id = ?', array(read_config_option('user_template'), read_config_option('user_template'))); if (empty($user)) { return 0; } else { return $user; } } elseif ($template > 0) { // plugin present and returned account return $template; } else { // plugin present and returned no account return 0; } } } /** * get_username - returns the username for the selected user * * @param $user_id - (int) the ID of the user * * @return - the username */ function get_username($user_id) { return db_fetch_cell_prepared('SELECT username FROM user_auth WHERE id = ?', array($user_id)); } /** * get_execution_user - returns the username of the running process * * @return - the username */ function get_execution_user() { if (function_exists('posix_getpwuid')) { $user_info = posix_getpwuid(posix_geteuid()); return $user_info['name']; } else { return exec('whoami'); } } /** * generate_data_source_path - creates a new data source path from scratch using the first data source * item name and updates the database with the new value * * @param $local_data_id - (int) the ID of the data source to generate a new path for * * @return - the new generated path */ function generate_data_source_path($local_data_id) { global $config; static $extended_paths = false; static $pattern = false; if ($extended_paths === false) { $extended_paths = read_config_option('extended_paths'); } if ($pattern === false) { $pattern = read_config_option('extended_paths_type'); } /* try any prepend the name with the host description */ $data = db_fetch_row_prepared('SELECT dl.host_id, h.description, dl.snmp_query_id FROM host AS h INNER JOIN data_local AS dl ON dl.host_id = h.id AND dl.id = ?', array($local_data_id)); if (cacti_sizeof($data)) { $host_name = $data['description']; $host_id = $data['host_id']; $data_query_id = $data['snmp_query_id']; } else { $host_name = 'undefinedhost'; $host_id = 0; $data_query_id = 0; } /* put it all together using the local_data_id at the end */ if ($extended_paths == 'on') { $maxdirs = read_config_option('extended_paths_hashes'); if (empty($maxdirs) || $maxdirs < 0 || !is_numeric($maxdirs)) { $maxdirs = 100; } $hash_id = $host_id % $maxdirs; if ($pattern == 'device' || $pattern == '') { $new_path = "/$host_id/$local_data_id.rrd"; } elseif ($pattern == 'device_dq') { $new_path = "/$host_id/$data_query_id/$local_data_id.rrd"; } elseif ($pattern == 'hash_device') { $new_path = "/$hash_id/$host_id/$local_data_id.rrd"; } elseif ($pattern == 'hash_device_dq') { $new_path = "/$hash_id/$host_id/$data_query_id/$local_data_id.rrd"; } } else { $host_part = strtolower(clean_up_file_name($host_name)) . '_'; /* then try and use the internal DS name to identify it */ $data_source_rrd_name = db_fetch_cell_prepared('SELECT data_source_name FROM data_template_rrd WHERE local_data_id = ? ORDER BY id LIMIT 1', array($local_data_id) ); if (!empty($data_source_rrd_name)) { $ds_part = strtolower(clean_up_file_name($data_source_rrd_name)); } else { $ds_part = 'ds'; } $new_path = "/$host_part$ds_part" . '_' . "$local_data_id.rrd"; } /* update our changes to the db */ db_execute_prepared('UPDATE data_template_data SET data_source_path = ? WHERE local_data_id = ?', array($new_path, $local_data_id)); return $new_path; } /** * generate graph_best_cf - takes the requested consolidation function and maps against * the list of available consolidation functions for the consolidation functions and returns * the most appropriate. Typically, this will be the requested value * * @param $data_template_id * @param $requested_cf * @param $ds_step * * @return - the best cf to use */ function generate_graph_best_cf($local_data_id, $requested_cf, $ds_step = 60) { static $best_cf; if ($local_data_id > 0) { $avail_cf_functions = get_rrd_cfs($local_data_id); if (cacti_sizeof($avail_cf_functions)) { /* workaround until we have RRA presets in 0.8.8 */ /* check through the cf's and get the best */ /* if none was found, take the first */ $best_cf = reset($avail_cf_functions); foreach($avail_cf_functions as $cf) { if ($cf == $requested_cf) { $best_cf = $requested_cf; } } } else { $best_cf = '1'; } } /* if you can not figure it out return average */ return $best_cf; } /** * get_rrd_cfs - reads the RRDfile and gets the RRAs stored in it. * * @param $local_data_id * * @return - array of the CF functions */ function get_rrd_cfs($local_data_id) { global $consolidation_functions; static $rrd_cfs = array(); if (array_key_exists($local_data_id, $rrd_cfs)) { return $rrd_cfs[$local_data_id]; } $cfs = array(); $rrdfile = get_data_source_path($local_data_id, true); $output = @rrdtool_execute("info $rrdfile", false, RRDTOOL_OUTPUT_STDOUT); /* search for * rra[0].cf = 'LAST' * or similar */ if ($output != '') { $output = explode("\n", $output); if (cacti_sizeof($output)) { foreach($output as $line) { if (substr_count($line, '.cf')) { $values = explode('=',$line); if (!in_array(trim($values[1], '" '), $cfs)) { $cfs[] = trim($values[1], '" '); } } } } } $new_cfs = array(); if (cacti_sizeof($cfs)) { foreach($cfs as $cf) { switch($cf) { case 'AVG': case 'AVERAGE': $new_cfs[1] = array_search('AVERAGE', $consolidation_functions); break; case 'MIN': $new_cfs[2] = array_search('MIN', $consolidation_functions); break; case 'MAX': $new_cfs[3] = array_search('MAX', $consolidation_functions); break; case 'LAST': $new_cfs[4] = array_search('LAST', $consolidation_functions); break; } } } $rrd_cfs[$local_data_id] = $new_cfs; return $new_cfs; } /** * generate_graph_def_name - takes a number and turns each digit into its letter-based * counterpart for RRDtool DEF names (ex 1 -> a, 2 -> b, etc) * * @param $graph_item_id - (int) the ID to generate a letter-based representation of * * @return - a letter-based representation of the input argument */ function generate_graph_def_name($graph_item_id) { $lookup_table = array('a','b','c','d','e','f','g','h','i','j'); $result = ''; $strValGII = strval($graph_item_id); for ($i=0; $i/', $string, $matches)) { $j = 0; for ($i=0; ($i < cacti_count($matches[1])); $i++) { if (in_array($matches[1][$i], $registered_cacti_names) == false) { $j++; db_execute_prepared("UPDATE data_input_fields SET sequence = ? WHERE data_input_id = ? AND input_output IN ('in') AND data_name = ?", array($j, $data_input_id, $matches[1][$i])); } } update_replication_crc(0, 'poller_replicate_data_input_fields_crc'); } } /** * move_graph_group - takes a graph group (parent+children) and swaps it with another graph * group * * @param $graph_template_item_id - (int) the ID of the (parent) graph item that was clicked * @param $graph_group_array - (array) an array containing the graph group to be moved * @param $target_id - (int) the ID of the (parent) graph item of the target group * @param $direction - ('next' or 'previous') whether the graph group is to be swapped with * group above or below the current group */ function move_graph_group($graph_template_item_id, $graph_group_array, $target_id, $direction) { $graph_item = db_fetch_row_prepared('SELECT local_graph_id, graph_template_id FROM graph_templates_item WHERE id = ?', array($graph_template_item_id)); if (empty($graph_item['local_graph_id'])) { $sql_where = 'graph_template_id = ' . $graph_item['graph_template_id'] . ' AND local_graph_id = 0'; } else { $sql_where = 'local_graph_id = ' . $graph_item['local_graph_id']; } /* get a list of parent+children of our target group */ $target_graph_group_array = get_graph_group($target_id); /* if this "parent" item has no children, then treat it like a regular gprint */ if (cacti_sizeof($target_graph_group_array) == 0) { if ($direction == 'next') { move_item_down('graph_templates_item', $graph_template_item_id, $sql_where); } elseif ($direction == 'previous') { move_item_up('graph_templates_item', $graph_template_item_id, $sql_where); } return; } /* start the sequence at '1' */ $sequence_counter = 1; $graph_items = db_fetch_assoc_prepared("SELECT id, sequence FROM graph_templates_item WHERE $sql_where ORDER BY sequence"); if (cacti_sizeof($graph_items)) { foreach ($graph_items as $item) { /* check to see if we are at the "target" spot in the loop; if we are, update the sequences and move on */ if ($target_id == $item['id']) { if ($direction == 'next') { $group_array1 = $target_graph_group_array; $group_array2 = $graph_group_array; } elseif ($direction == 'previous') { $group_array1 = $graph_group_array; $group_array2 = $target_graph_group_array; } foreach ($group_array1 as $graph_template_item_id) { db_execute_prepared('UPDATE graph_templates_item SET sequence = ? WHERE id = ?', array($sequence_counter, $graph_template_item_id)); /* propagate to ALL graphs using this template */ if (empty($graph_item['local_graph_id'])) { db_execute_prepared('UPDATE graph_templates_item SET sequence = ? WHERE local_graph_template_item_id = ?', array($sequence_counter, $graph_template_item_id)); } $sequence_counter++; } foreach ($group_array2 as $graph_template_item_id) { db_execute_prepared('UPDATE graph_templates_item SET sequence = ? WHERE id = ?', array($sequence_counter, $graph_template_item_id)); /* propagate to ALL graphs using this template */ if (empty($graph_item['local_graph_id'])) { db_execute_prepared('UPDATE graph_templates_item SET sequence = ? WHERE local_graph_template_item_id = ?', array($sequence_counter, $graph_template_item_id)); } $sequence_counter++; } } /* make sure to "ignore" the items that we handled above */ if ((!isset($graph_group_array[$item['id']])) && (!isset($target_graph_group_array[$item['id']]))) { db_execute_prepared('UPDATE graph_templates_item SET sequence = ? WHERE id = ?', array($sequence_counter, $item['id'])); $sequence_counter++; } } } } /** * get_graph_group - returns an array containing each item in the graph group given a single * graph item in that group * * @param $graph_template_item_id - (int) the ID of the graph item to return the group of * * @return - (array) an array containing each item in the graph group */ function get_graph_group($graph_template_item_id) { global $graph_item_types; $graph_item = db_fetch_row_prepared('SELECT graph_type_id, sequence, local_graph_id, graph_template_id FROM graph_templates_item WHERE id = ?', array($graph_template_item_id)); $params[] = $graph_item['sequence']; if (empty($graph_item['local_graph_id'])) { $params[] = $graph_item['graph_template_id']; $sql_where = 'graph_template_id = ? AND local_graph_id = 0'; } else { $params[] = $graph_item['sequence']; $sql_where = 'local_graph_id = ?'; } /* parents are LINE%, AREA%, and STACK%. If not return */ if (!preg_match('/(LINE|AREA|STACK)/', $graph_item_types[$graph_item['graph_type_id']])) { return array(); } $graph_item_children_array = array(); /* put the parent item in the array as well */ $graph_item_children_array[$graph_template_item_id] = $graph_template_item_id; $graph_items = db_fetch_assoc_prepared("SELECT id, graph_type_id, text_format, hard_return FROM graph_templates_item WHERE sequence > ? AND $sql_where ORDER BY sequence", $params); $is_hard = false; if (cacti_sizeof($graph_items)) { foreach ($graph_items as $item) { if ($is_hard) { return $graph_item_children_array; } elseif (strstr($graph_item_types[$item['graph_type_id']], 'GPRINT') !== false) { /* a child must be a GPRINT */ $graph_item_children_array[$item['id']] = $item['id']; if ($item['hard_return'] == 'on') { $is_hard = true; } } elseif (strstr($graph_item_types[$item['graph_type_id']], 'COMMENT') !== false) { if (preg_match_all('/\|([0-9]{1,2}):(bits|bytes):(\d):(current|total|max|total_peak|all_max_current|all_max_peak|aggregate_max|aggregate_sum|aggregate_current|aggregate):(\d)?\|/', $item['text_format'], $matches, PREG_SET_ORDER)) { $graph_item_children_array[$item['id']] = $item['id']; } elseif (preg_match_all('/\|sum:(\d|auto):(current|total|atomic):(\d):(\d+|auto)\|/', $item['text_format'], $matches, PREG_SET_ORDER)) { $graph_item_children_array[$item['id']] = $item['id']; } else { /* if not a GPRINT or special COMMENT then get out */ return $graph_item_children_array; } } else { /* if not a GPRINT or special COMMENT then get out */ return $graph_item_children_array; } } } return $graph_item_children_array; } /** * get_graph_parent - returns the ID of the next or previous parent graph item id * * @param $graph_template_item_id - the ID of the current graph item * @param $direction - ('next' or 'previous') whether to find the next or previous parent * * @return - the ID of the next or previous parent graph item id */ function get_graph_parent($graph_template_item_id, $direction) { $graph_item = db_fetch_row_prepared('SELECT sequence, local_graph_id, graph_template_id FROM graph_templates_item WHERE id = ?', array($graph_template_item_id)); if (empty($graph_item['local_graph_id'])) { $sql_where = 'graph_template_id = ' . $graph_item['graph_template_id'] . ' AND local_graph_id = 0'; } else { $sql_where = 'local_graph_id = ' . $graph_item['local_graph_id']; } if ($direction == 'next') { $sql_operator = '>'; $sql_order = 'ASC'; } elseif ($direction == 'previous') { $sql_operator = '<'; $sql_order = 'DESC'; } $next_parent_id = db_fetch_cell("SELECT id FROM graph_templates_item WHERE sequence $sql_operator " . $graph_item['sequence'] . " AND graph_type_id IN (4, 5, 6, 7, 8, 20) AND $sql_where ORDER BY sequence $sql_order LIMIT 1"); if (empty($next_parent_id)) { return 0; } else { return $next_parent_id; } } /** * get_item - returns the ID of the next or previous item id * * @param $tblname - the table name that contains the target id * @param $field - the field name that contains the target id * @param $startid - (int) the current id * @param $lmt_query - an SQL "where" clause to limit the query * @param $direction - ('next' or 'previous') whether to find the next or previous item id * * @return - (int) the ID of the next or previous item id */ function get_item($tblname, $field, $startid, $lmt_query, $direction) { if ($direction == 'next') { $sql_operator = '>'; $sql_order = 'ASC'; } elseif ($direction == 'previous') { $sql_operator = '<'; $sql_order = 'DESC'; } $current_sequence = db_fetch_cell_prepared("SELECT $field FROM $tblname WHERE id = ?", array($startid)); $new_item_id = db_fetch_cell("SELECT id FROM $tblname WHERE $field $sql_operator $current_sequence " . ($lmt_query != '' ? " AND $lmt_query":"") . " ORDER BY $field $sql_order LIMIT 1"); if (empty($new_item_id)) { return $startid; } else { return $new_item_id; } } /** * get_sequence - returns the next available sequence id * * @param $id - (int) the current id * @param $field - the field name that contains the target id * @param $table_name - the table name that contains the target id * @param $group_query - an SQL "where" clause to limit the query * * @return - (int) the next available sequence id */ function get_sequence($id, $field, $table_name, $group_query) { if (empty($id)) { $data = db_fetch_row("SELECT max($field)+1 AS seq FROM $table_name WHERE $group_query"); if ($data['seq'] == '') { return 1; } else { return $data['seq']; } } else { $data = db_fetch_row_prepared("SELECT $field FROM $table_name WHERE id = ?", array($id)); return $data[$field]; } } /** * move_item_down - moves an item down by swapping it with the item below it * * @param $table_name - the table name that contains the target id * @param $current_id - (int) the current id * @param $group_query - an SQL "where" clause to limit the query */ function move_item_down($table_name, $current_id, $group_query = '') { $next_item = get_item($table_name, 'sequence', $current_id, $group_query, 'next'); $sequence = db_fetch_cell_prepared("SELECT sequence FROM $table_name WHERE id = ?", array($current_id)); $sequence_next = db_fetch_cell_prepared("SELECT sequence FROM $table_name WHERE id = ?", array($next_item)); db_execute_prepared("UPDATE $table_name SET sequence = ? WHERE id = ?", array($sequence_next, $current_id)); db_execute_prepared("UPDATE $table_name SET sequence = ? WHERE id = ?", array($sequence, $next_item)); } /** * move_item_up - moves an item down by swapping it with the item above it * * @param $table_name - the table name that contains the target id * @param $current_id - (int) the current id * @param $group_query - an SQL "where" clause to limit the query */ function move_item_up($table_name, $current_id, $group_query = '') { $last_item = get_item($table_name, 'sequence', $current_id, $group_query, 'previous'); $sequence = db_fetch_cell_prepared("SELECT sequence FROM $table_name WHERE id = ?", array($current_id)); $sequence_last = db_fetch_cell_prepared("SELECT sequence FROM $table_name WHERE id = ?", array($last_item)); db_execute_prepared("UPDATE $table_name SET sequence = ? WHERE id = ?", array($sequence_last, $current_id)); db_execute_prepared("UPDATE $table_name SET sequence = ? WHERE id = ?", array($sequence, $last_item)); } /** * exec_into_array - executes a command and puts each line of its output into * an array * * @param $command_line - the command to execute * * @return - (array) an array containing the command output */ function exec_into_array($command_line) { $out = array(); $err = 0; exec($command_line,$out,$err); return array_values($out); } /** * get_web_browser - determines the current web browser in use by the client * * @return - ('ie' or 'moz' or 'other') */ function get_web_browser() { if (!empty($_SERVER['HTTP_USER_AGENT'])) { if (stristr($_SERVER['HTTP_USER_AGENT'], 'Mozilla') && (!(stristr($_SERVER['HTTP_USER_AGENT'], 'compatible')))) { return 'moz'; } elseif (stristr($_SERVER['HTTP_USER_AGENT'], 'MSIE')) { return 'ie'; } else { return 'other'; } } else { return 'other'; } } /** * draw_login_status - provides a consistent login status page for all pages that use it */ function draw_login_status($using_guest_account = false) { global $config; $guest_account = get_guest_account(); $auth_method = read_config_option('auth_method'); if (isset($_SESSION['sess_user_id']) && $_SESSION['sess_user_id'] === $guest_account) { api_plugin_hook('nav_login_before'); print __('Logged in as') . " ". __('guest') . "
"; api_plugin_hook('nav_login_after'); } elseif (isset($_SESSION['sess_user_id']) && $using_guest_account == false) { $user = db_fetch_row_prepared('SELECT username, password_change, realm FROM user_auth WHERE id = ?', array($_SESSION['sess_user_id'])); api_plugin_hook('nav_login_before'); print __('Logged in as') . " " . html_escape($user['username']) . "
'; api_plugin_hook('nav_login_after'); } } /** * draw_navigation_text - determines the top header navigation text for the current page and displays it to * * @param $type - Either 'url' or 'title' * * @return - Either the navigation text or title */ function draw_navigation_text($type = 'url') { global $config, $navigation; $navigation = api_plugin_hook_function('draw_navigation_text', $navigation); $current_page = get_current_page(); if (!isempty_request_var('action')) { get_filter_request_var('action', FILTER_VALIDATE_REGEXP, array('options' => array('regexp' => '/^([-a-zA-Z0-9_\s]+)$/'))); } $current_action = (isset_request_var('action') ? get_request_var('action') : ''); // find the current page in the big array if (isset($navigation[$current_page . ':' . $current_action])) { $current_array = $navigation[$current_page . ':' . $current_action]; } else { // If it's not set in the array, then default to a generic title $current_array = array( 'mapping' => 'index.php:', 'title' => ucwords(str_replace('_', ' ', basename(get_current_page(), '.php'))), 'level' => 0 ); } // Extract the full breadcrumb path from the current_array if (isset($current_array['mapping'])) { $current_mappings = explode(',', $current_array['mapping']); } else { $current_mappings = array(); } $current_nav = "