$item) { $path = $config['html_dir'].'/includes/entities/'.$entity_type.'.inc.php'; if (is_file($path)) { include($path); } } /** * Used for replace some strings at end of run all html scripts * * @param string $buffer HTML buffer from ob_start() * @return string Changed buffer */ function html_callback($buffer) { global $config; // Do not disclose version to unauthorized requests $version_param = $_SESSION['authenticated'] ? '?v=' . OBSERVIUM_VERSION : ''; // Install registered CSS/JS links $types = array( 'css' => ' ' . PHP_EOL, 'style' => ' ' . PHP_EOL, 'js' => ' ' . PHP_EOL, 'script' => ' ' . PHP_EOL, 'meta' => ' ' . PHP_EOL, ); foreach ($types as $type => $string) { $uptype = strtoupper($type); if (isset($GLOBALS['cache_html']['resources'][$type])) { $$type = '' . PHP_EOL; foreach (array_unique($GLOBALS['cache_html']['resources'][$type]) as $content) // Do not use global $cache variable, because it is reset before flush ob_cache { if (is_array($content)) { // for meta foreach($content as $param => $value) { $string = str_replace('%%STRING_'.$param.'%%', $value, $string); } $$type .= $string; } else { $$type .= str_replace('%%STRING%%', $content, $string); } } $$type .= ' ' . PHP_EOL; $buffer = str_replace('' . PHP_EOL, $$type, $buffer); } else { // Clean template string $buffer = str_replace('', '', $buffer); } } // Replace page title as specified by the page modules if (!is_array($GLOBALS['cache_html']['title'])) { // Title not set by any page, fall back to nicecase'd page name: if ($GLOBALS['vars']['page'] && $_SESSION['authenticated']) { $GLOBALS['cache_html']['title'] = array(nicecase($GLOBALS['vars']['page'])); } else { // HALP. Likely main page, doesn't need anything else... $GLOBALS['cache_html']['title'] = array(); } } // If suffix is set, put it in the back if ($config['page_title_suffix']) { $GLOBALS['cache_html']['title'][] = $config['page_title_suffix']; } // If prefix is set, put it in front if ($config['page_title_prefix']) { array_unshift($GLOBALS['cache_html']['title'], $config['page_title_prefix']); } // Build title with separators $title = implode($config['page_title_separator'], $GLOBALS['cache_html']['title']); /* // Replace title placeholder by actual title $buffer = str_replace('##TITLE##', escape_html($title), $buffer); // Page panel $buffer = str_replace('##PAGE_PANEL##', $GLOBALS['cache_html']['page_panel'], $buffer); // UI Alerts //$buffer = str_replace('##UI_ALERTS##', $GLOBALS['ui_alerts'], $buffer); $buffer = str_replace('##UI_ALERTS##', implode(PHP_EOL, $GLOBALS['cache_html']['ui_alerts']), $buffer); */ $replace = [ // Replace title placeholder by actual title '##TITLE##' => escape_html($title), // Page panel '##PAGE_PANEL##' => $GLOBALS['cache_html']['page_panel'], // UI Alerts //'##UI_ALERTS##' => $GLOBALS['ui_alerts'], '##UI_ALERTS##' => implode(PHP_EOL, (array)$GLOBALS['cache_html']['ui_alerts']), ]; //$buffer = array_str_replace($replace, $buffer, TRUE); // Return modified HTML page source return array_str_replace($replace, $buffer, TRUE); } /** * Parse $_GET, $_POST and REQUEST_URI into $vars array * * @param array|string $vars_order Request variables order (POST, URI, GET) * @param boolean $auth this var or ($_SESSION['authenticated']) used for allow to use var_decode() * @return array array of vars */ function get_vars($vars_order = [], $auth = FALSE) { if (is_string($vars_order)) { $vars_order = explode(' ', $vars_order); } elseif (empty($vars_order) || !is_array($vars_order)) { $vars_order = [ 'POST', 'URI', 'GET' ]; // Default order } // Content-Type=>application/x-www-form-urlencoded $content_type = isset($_SERVER['HTTP_CONTENT_TYPE']) ? $_SERVER['HTTP_CONTENT_TYPE'] : $_SERVER['CONTENT_TYPE']; // https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/XSS%20Injection // XSS script regex // STATE; return $state; } /** * Generate Percentage Bar * * This function generates an Observium percentage bar from a supplied array of arguments. * It is possible to draw a bar that does not work at all, * So care should be taken to make sure values are valid. * * @param array $args * @return string */ // TESTME needs unit testing function percentage_bar($args) { if (strlen($args['bg'])) { $style .= 'background-color:'.$args['bg'].';'; } if (strlen($args['border'])) { $style .= 'border-color:'.$args['border'].';'; } if (strlen($args['width'])) { $style .= 'width:'.$args['width'].';'; } if (strlen($args['text_c'])) { $style_b .= 'color:'.$args['text_c'].';'; } $total = '0'; $output = '
'; foreach ($args['bars'] as $bar) { $output .= '
'; $total += $bar['percent']; } $left = '100' - $total; if ($left > 0) { $output .= '
'; } if ($left >= 0) { $output .= '
'.$args['text'].'
'; } foreach ($args['bars'] as $bar) { $output .= '
'.$bar['text'].'
'; } # if ($left > '0') { $output .= '
'.$args['text'].'
'; } $output .= '
'; return $output; } // Legacy function // DO NOT USE THIS. Please replace instances of it with percentage_bar from above. // TESTME needs unit testing // DOCME needs phpdoc block function print_percentage_bar($width, $height, $percent, $left_text, $left_colour, $left_background, $right_text, $right_colour, $right_background) { if ($percent > "100") { $size_percent = "100"; } else { $size_percent = $percent; } $percentage_bar['border'] = "#".$left_background; $percentage_bar['bg'] = "#".$right_background; $percentage_bar['width'] = $width; $percentage_bar['text'] = $right_text; $percentage_bar['bars'][0] = array('percent' => $size_percent, 'colour' => '#'.$left_background, 'text' => $left_text); $output = percentage_bar($percentage_bar); return $output; } // TESTME needs unit testing // DOCME needs phpdoc block function device_link_class($device) { if (isset($device['status']) && $device['status'] == '0') { $class = "red"; } else { $class = ""; } if ( (isset($device['ignore']) && $device['ignore'] == '1') || (!is_null($device['ignore_until']) && strtotime($device['ignore_until']) > time()) ) { $class = "grey"; if (isset($device['status']) && $device['status'] == '1') { $class = "green"; } } if (isset($device['disabled']) && $device['disabled'] == '1') { $class = "grey"; } return $class; } /** * Return cached locations list * * If filter used, return locations available only for specified params. * Without filter return all available locations (cached) * * @param array $filter * @return array */ // TESTME needs unit testing function get_locations($filter = array()) { $where_array = []; foreach ($filter as $var => $value) { switch ($var) { case 'location_lat': case 'location_lon': case 'location_country': case 'location_state': case 'location_county': case 'location_city': // Check geo params only when GEO enabled globally if ($GLOBALS['config']['geocoding']['enable']) { $where_array[$var] = generate_query_values_and($value, $var); } break; case 'location': $where_array[$var] = generate_query_values_and($value, $var); break; } } if (count($where_array)) { // Return only founded locations $where = implode('', $where_array) . $GLOBALS['cache']['where']['devices_permitted']; $locations = dbFetchColumn("SELECT DISTINCT `location` FROM `devices_locations` WHERE 1 $where;"); } else { $locations = array(); foreach ($GLOBALS['cache']['device_locations'] as $location => $count) { $locations[] = $location; } } sort($locations); return $locations; } /** * Return the filename of the device RANCID config file * * @param string $hostname * @param false $rdebug * * @return false|string */ function get_rancid_filename($hostname, $rdebug = FALSE) { global $config; $hostnames = generate_device_hostnames($hostname, $config['rancid_suffix'], $rdebug); foreach ($config['rancid_configs'] as $config_path) { if (!str_ends($config_path, '/')) { $config_path .= '/'; } if ($rdebug) { echo("Looking in configured directory: $config_path
"); } foreach ($hostnames as $host) { if (is_file($config_path . $host)) { if ($rdebug) { echo("File " . $config_path . $host . " found.
"); } return $config_path . $host; } if ($rdebug) { echo("File " . $config_path . $host . " not found.
"); } } } return FALSE; } // return the filename of the device NFSEN rrd file // TESTME needs unit testing // DOCME needs phpdoc block function get_nfsen_filename($hostname) { global $config; $nfsen_rrds = (is_array($config['nfsen_rrds']) ? $config['nfsen_rrds'] : array($config['nfsen_rrds'])); foreach ($nfsen_rrds as $nfsen_rrd) { if (!str_ends($nfsen_rrd, '/')) { $nfsen_rrd .= '/'; } $basefilename_underscored = str_replace(".", $config['nfsen_split_char'], $hostname); // Remove suffix and prefix from basename $nfsen_filename = $basefilename_underscored; if (isset($config['nfsen_suffix']) && strlen($config['nfsen_suffix'])) { $nfsen_filename = (strstr($nfsen_filename, $config['nfsen_suffix'], TRUE)); } if (isset($config['nfsen_prefix']) && strlen($config['nfsen_prefix'])) { $nfsen_filename = (strstr($nfsen_filename, $config['nfsen_prefix'])); } $nfsen_rrd_file = $nfsen_rrd . $nfsen_filename . '.rrd'; if (is_file($nfsen_rrd_file)) { return $nfsen_rrd_file; } } return FALSE; } // Note, by default text NOT escaped. // TESTME needs unit testing // DOCME needs phpdoc block function generate_ap_link($args, $text = NULL, $type = NULL, $escape = FALSE) { humanize_port($args); if (!$text) { $text = escape_html($args['port_label']); } if ($type) { $args['graph_type'] = $type; } if (!isset($args['graph_type'])) { $args['graph_type'] = 'port_bits'; } if (!isset($args['hostname']) && $args['device_id']) { $args = array_merge($args, device_by_id_cache($args['device_id'])); } $content = "
". $args['text'] . " - " . escape_html($args['port_label']) . "
"; if ($args['ifAlias']) { $content .= escape_html($args['ifAlias']) . "
"; } $content .= "
"; $graph_array['type'] = $args['graph_type']; $graph_array['legend'] = "yes"; $graph_array['height'] = "100"; $graph_array['width'] = "340"; $graph_array['to'] = get_time(); $graph_array['from'] = get_time('day'); $graph_array['id'] = $args['accesspoint_id']; $content .= generate_graph_tag($graph_array); $graph_array['from'] = get_time('week'); $content .= generate_graph_tag($graph_array); $graph_array['from'] = get_time('month'); $content .= generate_graph_tag($graph_array); $graph_array['from'] = get_time('year'); $content .= generate_graph_tag($graph_array); $content .= "
"; $url = generate_ap_url($args); if (port_permitted($args['interface_id'], $args['device_id'])) { return overlib_link($url, $text, $content, $class, $escape); } return $text; } /** * Returns TRUE if the device is marked as ignored in the cache. * * @param $device_id * * @return bool */ function device_is_ignored($device_id) { return isset($GLOBALS['cache']['devices']['ignored']) && in_array($device_id, $GLOBALS['cache']['devices']['ignored'], TRUE); } // TESTME needs unit testing // DOCME needs phpdoc block function generate_ap_url($ap, $vars=array()) { return generate_url(array('page' => 'device', 'device' => $ap['device_id'], 'tab' => 'accesspoint', 'ap' => $ap['accesspoint_id']), $vars); } /** * Generate SQL WHERE string with check permissions and ignores for device_id, port_id and other * * Note, this function uses comparison operator IN. Max number of values in the IN list * is limited by the 'max_allowed_packet' option (default: 1048576) * * Usage examples: * generate_query_permitted() * ' AND `device_id` IN (1,4,8,33) AND `device_id` NOT IN (66) AND (`device_id` != '' AND `device_id` IS NOT NULL) ' * generate_query_permitted(array('device'), array('device_table' => 'D')) * ' AND `D`.`device_id` IN (1,4,8,33) AND `D`.`device_id` NOT IN (66) AND (`D`.`device_id` != '' AND `D`.`device_id` IS NOT NULL) ' * generate_query_permitted(array('device', 'port'), array('port_table' => 'I')) == * ' AND `device_id` IN (1,4,8,33) AND `device_id` NOT IN (66) AND (`device_id` != '' AND `device_id` IS NOT NULL) * AND `I`.`port_id` IN (1,4,8,33) AND `I`.`port_id` NOT IN (66) AND (`I`.`port_id` != '' AND `I`.`port_id` IS NOT NULL) ' * generate_query_permitted(array('device', 'port'), array('port_table' => 'I', 'hide_ignored' => TRUE)) * This additionaly exclude all ignored devices and ports * * @uses html/includes/cache-data.inc.php * @global integer $_SESSION['userlevel'] * @global boolean $GLOBALS['config']['web_show_disabled'] * @global array $GLOBALS['permissions'] * @global array $GLOBALS['cache']['devices'] * @global array $GLOBALS['cache']['ports'] * @global string $GLOBALS['vars']['page'] * @param array|string $type_array Array with permission types, currently allowed 'devices', 'ports' * @param array $options Options for each permission type: device_table, port_table, hide_ignored, hide_disabled * @return string */ // TESTME needs unit testing function generate_query_permitted($type_array = [ 'device' ], $options = []) { if (!is_array($type_array)) { $type_array = [ $type_array ]; } $user_limited = $_SESSION['userlevel'] < 5; $page = $GLOBALS['vars']['page']; // If device IDs stored in SESSION use it (used in ajax) //if (!isset($GLOBALS['cache']['devices']) && isset($_SESSION['cache']['devices'])) //{ // $GLOBALS['cache']['devices'] = $_SESSION['cache']['devices']; //} if (!isset($GLOBALS['permissions'])) { // Note, this function must used after load permissions list! print_error("Function ".__FUNCTION__."() on page '$page' called before include cache-data.inc.php or something wrong with caching permissions. Please report this to developers!"); } // Use option hide_disabled if passed or use config $options['hide_disabled'] = (isset($options['hide_disabled']) ? (bool)$options['hide_disabled'] : !$GLOBALS['config']['web_show_disabled']); //$query_permitted = ''; $query_part = []; foreach ($type_array as $type) { switch ($type) { // Devices permission query case 'device': case 'devices': $column = '`device_id`'; $query_permitted = []; if (isset($options['device_table'])) { $column = '`'.$options['device_table'].'`.'.$column; } // Show only permitted devices if ($user_limited) { if (safe_count($GLOBALS['permissions']['device'])) { $query_permitted[] = " $column IN (". implode(',', array_keys($GLOBALS['permissions']['device'])). ')'; } else { // Exclude all entries, because there is no permitted devices $query_permitted[] = ' 0'; } } // Also don't show ignored and disabled devices (except on 'device' and 'devices' pages) $devices_excluded = []; if (strpos($page, 'device') !== 0) { if ($options['hide_ignored'] && safe_count($GLOBALS['cache']['devices']['ignored'])) { $devices_excluded = array_merge($devices_excluded, $GLOBALS['cache']['devices']['ignored']); } if ($options['hide_disabled'] && safe_count($GLOBALS['cache']['devices']['disabled'])) { $devices_excluded = array_merge($devices_excluded, $GLOBALS['cache']['devices']['disabled']); } } if (count($devices_excluded)) { // Set query with excluded devices $query_permitted[] = " $column NOT IN (". implode(',', array_unique($devices_excluded)). ')'; } // At the end excluded entries with empty/null device_id (wrong entries) //$query_permitted[] = " ($column != '' AND $column IS NOT NULL)"; $query_permitted[] = " $column IS NOT NULL"; // Note: SELECT '' = 0; is TRUE $query_part[] = implode(" AND ", $query_permitted); unset($query_permitted); break; // Ports permission query case 'port': case 'ports': $column = '`port_id`'; if (isset($options['port_table'])) { $column = '`'.$options['port_table'].'`.'.$column; } // If port IDs stored in SESSION use it (used in ajax) //if (!isset($GLOBALS['cache']['ports']) && isset($_SESSION['cache']['ports'])) //{ // $GLOBALS['cache']['ports'] = $_SESSION['cache']['ports']; //} // Show only permitted ports if ($user_limited) { if (safe_count($GLOBALS['permissions']['port'])) { $query_permitted[] = " $column IN (" . implode(',', array_keys($GLOBALS['permissions']['port'])) . ')'; } else { // Exclude all entries, because there is no permitted ports $query_permitted[] = '0'; } } $ports_excluded = array(); // Don't show ports with disabled polling. if (safe_count($GLOBALS['cache']['ports']['poll_disabled'])) { $ports_excluded = array_merge($ports_excluded, $GLOBALS['cache']['ports']['poll_disabled']); //foreach ($GLOBALS['cache']['ports']['poll_disabled'] as $entry) //{ // $ports_excluded[] = $entry; //} //$ports_excluded = array_unique($ports_excluded); } // Don't show deleted ports (except on 'deleted-ports' page) if ($page !== 'deleted-ports' && safe_count($GLOBALS['cache']['ports']['deleted'])) { $ports_excluded = array_merge($ports_excluded, $GLOBALS['cache']['ports']['deleted']); //foreach ($GLOBALS['cache']['ports']['deleted'] as $entry) //{ // $ports_excluded[] = $entry; //} //$ports_excluded = array_unique($ports_excluded); } if ($page !== 'device' && !in_array('device', $type_array)) { // Don't show ports for disabled devices (except on 'device' page or if 'device' permissions already queried) if ($options['hide_disabled'] && !$user_limited && safe_count($GLOBALS['cache']['ports']['device_disabled'])) { $ports_excluded = array_merge($ports_excluded, $GLOBALS['cache']['ports']['device_disabled']); //foreach ($GLOBALS['cache']['ports']['device_disabled'] as $entry) //{ // $ports_excluded[] = $entry; //} //$ports_excluded = array_unique($ports_excluded); } // Don't show ports for ignored devices (except on 'device' page) if ($options['hide_ignored'] && safe_count($GLOBALS['cache']['ports']['device_ignored'])) { $ports_excluded = array_merge($ports_excluded, $GLOBALS['cache']['ports']['device_ignored']); //foreach ($GLOBALS['cache']['ports']['device_ignored'] as $entry) //{ // $ports_excluded[] = $entry; //} //$ports_excluded = array_unique($ports_excluded); } } // Don't show ignored ports (only on some pages!) if (($page === 'overview' || $options['hide_ignored']) && safe_count($GLOBALS['cache']['ports']['ignored'])) { $ports_excluded = array_merge($ports_excluded, $GLOBALS['cache']['ports']['ignored']); //foreach ($GLOBALS['cache']['ports']['ignored'] as $entry) //{ // $ports_excluded[] = $entry; //} //$ports_excluded = array_unique($ports_excluded); } unset($entry); if (count($ports_excluded)) { // Set query with excluded ports $query_permitted[] = $column . " NOT IN (". implode(',', array_unique($ports_excluded)). ')'; } // At the end excluded entries with empty/null port_id (wrong entries) if (!isset($options['port_null']) || !$options['port_null']) { //$query_permitted[] = "($column != '' AND $column IS NOT NULL)"; $query_permitted[] = "$column IS NOT NULL"; } elseif (!$user_limited && safe_count($query_permitted)) { // FIXME. derp code, need rewrite //$query_permitted[] = safe_count($query_permitted) ? "OR $column IS NULL" : "$column IS NULL"; $query_permitted[] = "OR $column IS NULL"; } $query_permitted = implode(" AND ", (array)$query_permitted); if (!safe_empty($query_permitted)) { $query_part[] = str_replace(" AND OR ", ' OR ', $query_permitted); } unset($query_permitted); break; case 'sensor': case 'sensors': // For sensors // FIXME -- this is easily generifyable, just use translate_table_array() $column = '`sensor_id`'; if (isset($options['sensor_table'])) { $column = '`'.$options['sensor_table'].'`.'.$column; } // If IDs stored in SESSION use it (used in ajax) //if (!isset($GLOBALS['cache']['sensors']) && isset($_SESSION['cache']['sensors'])) //{ // $GLOBALS['cache']['sensors'] = $_SESSION['cache']['sensors']; //} // Show only permitted entities if ($user_limited) { if (safe_count($GLOBALS['permissions']['sensor'])) { $query_permitted .= " $column IN ("; $query_permitted .= implode(',', array_keys($GLOBALS['permissions']['sensor'])); $query_permitted .= ')'; } else { // Exclude all entries, because there are no permitted entities $query_permitted .= '0'; } $query_part[] = $query_permitted; unset($query_permitted); } break; case 'alert': case 'alerts': // For generic alert $column = '`alert_table_id`'; // Show only permitted entities if ($user_limited) { if (safe_count($GLOBALS['permissions']['alert'])) { $query_permitted .= " $column IN ("; $query_permitted .= implode(',', array_keys($GLOBALS['permissions']['alert'])); $query_permitted .= ')'; } else { // Exclude all entries, because there are no permitted entities $query_permitted .= '0'; } $query_part[] = $query_permitted; unset($query_permitted); } break; case 'bill': case 'bills': // For bills break; } } if (count($query_part)) { //r($query_part); if ($user_limited) { // Limited user must use OR for include multiple entities $query_permitted = " AND ((".implode(") OR (", $query_part)."))"; } else { // Unlimited used must use AND for exclude multiple hidden entities $query_permitted = " AND ((".implode(") AND (", $query_part)."))"; } } $query_permitted .= ' '; //r($query_permitted); return $query_permitted; } // TESTME needs unit testing // DOCME needs phpdoc block function dashboard_exists($dash_id) { return dbExist('dashboards', '`dash_id` = ?', [ $dash_id ]); //return count(dbFetchRow("SELECT * FROM `dashboards` WHERE `dash_id` = ?", array($dash_id))); } // TESTME needs unit testing // DOCME needs phpdoc block function get_user_prefs($user_id) { $prefs = array(); foreach (dbFetchRows("SELECT * FROM `users_prefs` WHERE `user_id` = ?", array($user_id)) as $entry) { $prefs[$entry['pref']] = $entry; } return $prefs; } // TESTME needs unit testing // DOCME needs phpdoc block function get_user_pref($user_id, $pref) { if ($entry = dbFetchRow("SELECT `value` FROM `users_prefs` WHERE `user_id` = ? AND `pref` = ?", array($user_id, $pref))) { return $entry['value']; } return NULL; } // TESTME needs unit testing // DOCME needs phpdoc block function set_user_pref($user_id, $pref, $value) { //if (dbFetchCell("SELECT COUNT(*) FROM `users_prefs` WHERE `user_id` = ? AND `pref` = ?", array($user_id, $pref))) if (dbExist('users_prefs', '`user_id` = ? AND `pref` = ?', array($user_id, $pref))) { $id = dbUpdate(array('value' => $value), 'users_prefs', '`user_id` = ? AND `pref` = ?', array($user_id, $pref)); } else { $id = dbInsert(array('user_id' => $user_id, 'pref' => $pref, 'value' => $value), 'users_prefs'); } return $id; } // TESTME needs unit testing // DOCME needs phpdoc block function del_user_pref($user_id, $pref) { return dbDelete('users_prefs', "`user_id` = ? AND `pref` = ?", array($user_id, $pref)); } // Load configuration from user SQL into supplied variable (pass by reference!) function load_user_config(&$load_config, $user_id) { global $config; /* $config_defined = get_defined_settings(); // defined in config.php // Override some whitelisted definitions from config.php foreach ($config_defined as $key => $definition) { //if (is_null($config['definitions_whitelist'])) { print_error("NULL on $key"); } else { print_warning("ARRAY on $key"); } if (in_array($key, $GLOBALS['config']['definitions_whitelist']) && // Always use global config here! is_array($definition) && is_array($config[$key])) { // Fix mib definitions for dumb users, who copied old defaults.php // where mibs was just MIB => 1, // This definition should be array // Fetch first element and validate that this is array if ($key === 'mibs' && !is_array(array_shift(array_values($definition)))) { continue; } $config[$key] = array_replace_recursive($config[$key], $definition); } } */ if (!$prefs = dbFetchRows("SELECT * FROM `users_prefs` WHERE `user_id` = ? AND `pref` NOT IN (?, ?)", [ $user_id, 'atom_key', 'api_key' ])) { // No user prefs set return FALSE; } // Always use global config here! include($config['install_dir'] . '/includes/config-variables.inc.php'); // Same format as in global config! // User prefs always override global config //foreach (dbFetchRows("SELECT * FROM `config`") as $item) { foreach ($prefs as $item) { if (!isset($config_variable[$item['pref']]['useredit']) || !$config_variable[$item['pref']]['useredit']) { // Load only permitted settings print_debug("User [$user_id] setting '{$item['pref']}' not permitted by definitions."); continue; } // Convert boo|bee|baa config value into $config['boo']['bee']['baa'] $tree = explode('|', $item['pref']); //if (array_key_exists($tree[0], $config_defined)) { continue; } // This complete skip option if first level key defined in $config // Unfortunately, I don't know of a better way to do this... // Perhaps using array_map() ? Unclear... hacky. :[ // FIXME use a loop with references! (cf. nested location menu) switch (count($tree)) { case 1: //if (isset($config_defined[$tree[0]])) { continue; } // Note, false for null values //if (array_key_exists($tree[0], $config_defined)) { break; } $load_config[$tree[0]] = safe_unserialize($item['value']); //r($load_config[$tree[0]]); //r($_SESSION); break; case 2: //if (isset($config_defined[$tree[0]][$tree[1]])) { break; } // Note, false for null values $load_config[$tree[0]][$tree[1]] = safe_unserialize($item['value']); break; case 3: //if (isset($config_defined[$tree[0]][$tree[1]][$tree[2]])) { break; } // Note, false for null values $load_config[$tree[0]][$tree[1]][$tree[2]] = safe_unserialize($item['value']); break; case 4: //if (isset($config_defined[$tree[0]][$tree[1]][$tree[2]][$tree[3]])) { break; } // Note, false for null values $load_config[$tree[0]][$tree[1]][$tree[2]][$tree[3]] = safe_unserialize($item['value']); break; case 5: //if (isset($config_defined[$tree[0]][$tree[1]][$tree[2]][$tree[3]][$tree[4]])) { break; } // Note, false for null values $load_config[$tree[0]][$tree[1]][$tree[2]][$tree[3]][$tree[4]] = safe_unserialize($item['value']); break; default: print_error("Too many array levels for SQL configuration parser!"); } } } function process_sql_vars($vars) { global $config; // Always use global config here! include($config['install_dir'] . '/includes/config-variables.inc.php'); $deletes = array(); $sets = array(); $errors = array(); $set_attribs = array(); // set obs_attribs // Submit button pressed foreach ($vars as $varname => $value) { if (str_starts($varname, 'varset_')) { $varname = substr($varname, 7); $sqlname = str_replace('__', '|', $varname); $sqlset = get_var_true($value); // value sets in sql $content = $vars[$varname]; $confname = '$config[\'' . implode("']['",explode('|',$sqlname)) . '\']'; $section = $config_variable[$sqlname]['section']; if ($vars[$varname . '_custom']) { $ok = FALSE; if (isset($config_variable[$sqlname]['edition']) && $config_variable[$sqlname]['edition'] != OBSERVIUM_EDITION) { // Skip variables not allowed for current Observium edition continue; } if (isset($config_sections[$section]['edition']) && $config_sections[$section]['edition'] != OBSERVIUM_EDITION) { // Skip sections not allowed for current Observium edition continue; } // Split enum|foo|bar into enum foo|bar list($vartype, $varparams) = explode('|', $config_variable[$sqlname]['type'], 2); $params = array(); // If a callback function is defined, use this to fill params. if ($config_variable[$sqlname]['params_call'] && function_exists($config_variable[$sqlname]['params_call'])) { $params = call_user_func($config_variable[$sqlname]['params_call']); // Else if the params are defined directly, use these. } elseif (is_array($config_variable[$sqlname]['params'])) { $params = $config_variable[$sqlname]['params']; } elseif (!empty($varparams)) { // Else use parameters specified in variable type (e.g. enum|1|2|5|10) foreach (explode('|', $varparams) as $param) { $params[$param] = array('name' => nicecase($param)); } } switch ($vartype) { case 'int': case 'integer': case 'float': if (is_numeric($content)) { $ok = TRUE; } else { $errors[] = $config_variable[$sqlname]['name'] . " ($confname) should be of numeric type. Setting '" . escape_html($content) . "' ignored."; } break; case 'bool': case 'boolean': switch ($content) { case 'on': case '1': $content = 1; $ok = TRUE; break; case 'off': // Won't actually happen. When "unchecked" the field is simply not transmitted... case '0': case '': // ... which we catch here. $content = 0; $ok = TRUE; break; default: $ok = FALSE; $errors[] = $config_variable[$sqlname]['name'] . " ($confname) should be of type bool. Setting '" . escape_html($content) . "' ignored."; } break; case 'enum': if (!array_key_exists($content, $params)) { $ok = FALSE; $errors[] = $config_variable[$sqlname]['name'] . " ($confname) should be one of " . implode(', ', $params) . ". Setting '" . escape_html($content) . "' ignored."; } else { $ok = TRUE; } break; case 'enum-array': //r($content); //r($params); foreach ($content as $value) { // Check all values if (!array_key_exists($value, $params)) { $ok = FALSE; $errors[] = $config_variable[$sqlname]['name'] . " ($confname) all values should be one of this list " . implode(', ', $params) . ". Settings '" . implode(', ', $content) . "' ignored."; break; } $ok = TRUE; } break; case 'enum-key-value': //r($content); //r($params); if (isset($content['key'], $content['value'])) { $tmp = $content; $content = []; foreach ($tmp['key'] as $i => $key) { if (safe_empty($key) && safe_empty($tmp['value'][$i])) { continue; } // skip empty key-value pair $content[$key] = $tmp['value'][$i]; } $ok = TRUE; //r($content); } break; case 'enum-freeinput': //r($content); //r($params); // FIXME, need validate values if (is_null($content)) { // Empty array allowed, for override defaults $content = array(); $ok = TRUE; } foreach ($content as $value) { $ok = TRUE; } break; case 'password': case 'string': $ok = TRUE; break; default: $ok = FALSE; $errors[] = $config_variable[$sqlname]['name'] . " ($confname) is of unknown type (" . $config_variable[$sqlname]['type'] . ")"; break; } if ($ok) { $sets[$sqlname] = $content; // Set an obs_attrib, example for syslog trigger //r($config_variable[$sqlname]); if (isset($config_variable[$sqlname]['set_attrib']) && strlen($config_variable[$sqlname]['set_attrib'])) { $set_attribs[$config_variable[$sqlname]['set_attrib']] = $config['time']['now']; } } } elseif ($sqlset) { $deletes[] = $sqlname; // Set an obs_attrib, example for syslog trigger //r($config_variable[$sqlname]); if (isset($config_variable[$sqlname]['set_attrib']) && strlen($config_variable[$sqlname]['set_attrib'])) { $set_attribs[$config_variable[$sqlname]['set_attrib']] = $config['time']['now']; } } } } return [ 'sets' => $sets, 'set_attribs' => $set_attribs, 'deletes' => $deletes, 'errors' => $errors ]; } /** * Convert amqp|conn|host into returning value of $arrayvar['amqp']['conn']['host'] * * @param string $sqlname Variable name * @param array $arrayvar Array where to see param * @param Boolean $try_isset If True, return isset($sqlname) check, else return variable content * @return mixed */ function sql_to_array($sqlname, $arrayvar, $try_isset = TRUE) { list($key, $pop_sqlname) = explode('|', $sqlname, 2); if (!is_array($arrayvar)) { return FALSE; } $isset = array_key_exists($key, $arrayvar); if (safe_empty($pop_sqlname)) { // Reached the variable, return its content, or FALSE if it's not set if ($try_isset) { return $isset; } return $isset ? $arrayvar[$key] : NULL; } if ($isset) { // Recurse to lower level return sql_to_array($pop_sqlname, $arrayvar[$key], $try_isset); } return FALSE; } // TESTME needs unit testing // DOCME needs phpdoc block function get_smokeping_files($rdebug = 0) { global $config; $smokeping_files = array(); if ($rdebug) { echo('- Recursing through ' . $config['smokeping']['dir'] . '
'); } if (isset($config['smokeping']['master_hostname'])) { $master_hostname = $config['smokeping']['master_hostname']; } else { $master_hostname = $config['own_hostname'] ?: get_localhost(); } if (is_dir($config['smokeping']['dir'])) { foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($config['smokeping']['dir'])) as $file) { if (basename($file) != "." && basename($file) != ".." && strstr($file, ".rrd")) { if ($rdebug) { echo('- Found file ending in ".rrd": ' . basename($file) . '
'); } if (strstr($file, "~")) { list($target,$slave) = explode("~", basename($file,".rrd")); if ($rdebug) { echo('- Determined to be a slave file for target ' . $target . '
'); } $target = str_replace($config['smokeping']['split_char'], ".", $target); if ($config['smokeping']['suffix']) { $target = $target.$config['smokeping']['suffix']; if ($rdebug) { echo('- Suffix is configured, target is now ' . $target . '
'); } } $smokeping_files['incoming'][$target][$slave] = $file; $smokeping_files['outgoing'][$slave][$target] = $file; } else { $target = basename($file,".rrd"); if ($rdebug) { echo('- Determined to be a local file, for target ' . $target . '
'); } $target = str_replace($config['smokeping']['split_char'], ".", $target); if ($rdebug) { echo('- After replacing configured split_char ' . $config['smokeping']['split_char'] . ' by . target is ' . $target . '
'); } if ($config['smokeping']['suffix']) { $target = $target.$config['smokeping']['suffix']; if ($rdebug) { echo('- Suffix is configured, target is now ' . $target . '
'); } } $smokeping_files['incoming'][$target][$master_hostname] = $file; $smokeping_files['outgoing'][$master_hostname][$target] = $file; } } } } else { if ($rdebug) { echo("- Smokeping RRD directory not found: " . $config['smokeping']['dir']); } } return $smokeping_files; } /** * Darkens or lightens a colour * Found via http://codepad.org/MTGLWVd0 * * First argument is the colour in hex, second argument is how dark it should be 1=same, 2=50% * * @return string * @param string $rgb * @param int $darker */ function darken_color($rgb, $darker=2) { if (strpos($rgb, '#') !== FALSE) { $hash = '#'; $rgb = str_replace('#', '', $rgb); } else { $hash = ''; } $len = strlen($rgb); if ($len == 6) {} // Passed RGB else if ($len == 8) { // Passed RGBA, remove alpha channel $rgb = substr($rgb, 0, 6); } else { $rgb = FALSE; } if ($rgb === FALSE) { return $hash.'000000'; } $darker = ($darker > 1) ? $darker : 1; list($R16, $G16, $B16) = str_split($rgb, 2); $R = sprintf("%02X", floor(hexdec($R16) / $darker)); $G = sprintf("%02X", floor(hexdec($G16) / $darker)); $B = sprintf("%02X", floor(hexdec($B16) / $darker)); return $hash.$R.$G.$B; } function json_output($status, $message) { header("Content-type: application/json; charset=utf-8"); echo safe_json_encode([ "status" => $status, "message" => $message ]); exit(); } /** * Register an HTML resource * * Registers resource for use later (will be re-inserted via output buffer handler) * CSS and JS files default to the css/ and js/ directories respectively. * Scripts are inserted literally as passed in $name. * * @param string $type Type of resource (css/js/script) * @param string $content Filename or script content or array (for meta) */ // TESTME needs unit testing function register_html_resource($type, $content) { // If no path specified, default to subdirectory of resource type (for CSS and JS only) $type = strtolower($type); if (in_array($type, array('css', 'js')) && strpos($content, '/') === FALSE) { $content = $type . '/' . $content; } // Insert into global variable, used in html callback function $GLOBALS['cache_html']['resources'][$type][] = $content; } /** * Register an HTML title section * * Registers title section for use in the html tag. * Calls can be stacked, and will be concatenated later by the HTML callback function. * * @param string $title Section title content */ // TESTME needs unit testing function register_html_title($title) { $GLOBALS['cache_html']['title'][] = $title; } /** * Register an HTML alert block displayed in top of page. * * @param string $text Alert message * @param string $title Alert title if passed * @param string $severity Severity in list: info, danger, warning, success, recovery, suppressed, delay, disabled */ function register_html_alert($text, $title = NULL, $severity = 'info') { // FIXME handle severity parameter with colour or icon? $ui_alerts = '<div width="100%" class="alert alert-' . $severity . '">'; if (!safe_empty($title)) { $ui_alerts .= '<h4>' . $title . '</h4>'; } $ui_alerts .= $text . '</div>'; $GLOBALS['cache_html']['ui_alerts'][] = $ui_alerts; } /** * Register an HTML panel section * * Registers left panel section. * Calls can be stacked, and will be concatenated later by the HTML callback function. * * @param string $html Section panel content */ // TESTME needs unit testing function register_html_panel($html = '') { $GLOBALS['cache_html']['page_panel'] = $html; } /** * Redirect to specified URL * * @param string $url Redirecting URL */ function redirect_to_url($url) { if (safe_empty($url) || $url === '#') { return; } // Empty url, do not redirect $parse = parse_url($url); //r($url); if (!isset($parse['scheme']) && !str_starts($url, '/')) { // When this is not full url or not started with / $url = '/' . $url; } if (headers_sent()) { // HTML headers already sent, use JS than register_html_resource('script', "location.href='$url'"); } else { // Just use headers header('Location: '.$url); } } function generate_colour_gradient($start_colour, $end_colour, $steps) { if($steps < 4) { $steps = 4; } $FromRGB['r'] = hexdec(substr($start_colour, 0, 2)); $FromRGB['g'] = hexdec(substr($start_colour, 2, 2)); $FromRGB['b'] = hexdec(substr($start_colour, 4, 2)); $ToRGB['r'] = hexdec(substr($end_colour, 0, 2)); $ToRGB['g'] = hexdec(substr($end_colour, 2, 2)); $ToRGB['b'] = hexdec(substr($end_colour, 4, 2)); $StepRGB['r'] = ($FromRGB['r'] - $ToRGB['r']) / ($steps - 1); $StepRGB['g'] = ($FromRGB['g'] - $ToRGB['g']) / ($steps - 1); $StepRGB['b'] = ($FromRGB['b'] - $ToRGB['b']) / ($steps - 1); $GradientColors = array(); for($i = 0; $i < $steps; $i++) { $RGB['r'] = floor($FromRGB['r'] - ($StepRGB['r'] * $i)); $RGB['g'] = floor($FromRGB['g'] - ($StepRGB['g'] * $i)); $RGB['b'] = floor($FromRGB['b'] - ($StepRGB['b'] * $i)); $HexRGB['r'] = sprintf('%02x', ($RGB['r'])); $HexRGB['g'] = sprintf('%02x', ($RGB['g'])); $HexRGB['b'] = sprintf('%02x', ($RGB['b'])); $GradientColors[] = implode(NULL, $HexRGB); } $GradientColors = array_filter($GradientColors, "c_len"); return $GradientColors; } function c_len($val){ return (strlen($val) == 6 ? true : false ); } function adjust_colour_brightness($hex, $steps) { // Steps should be between -255 and 255. Negative = darker, positive = lighter $steps = max(-255, min(255, $steps)); // Normalize into a six character long hex string $hex = str_replace('#', '', $hex); if (strlen($hex) == 3) { $hex = str_repeat(substr($hex,0,1), 2).str_repeat(substr($hex,1,1), 2).str_repeat(substr($hex,2,1), 2); } // Split into three parts: R, G and B $color_parts = str_split($hex, 2); $return =''; foreach ($color_parts as $color) { $color = hexdec($color); // Convert to decimal $color = max(0,min(255,$color + $steps)); // Adjust color $return .= str_pad(dechex($color), 2, '0', STR_PAD_LEFT); // Make two char hex code } return $return; } /** * Highlight (or replace with specific strings) part of string. * Optionally can search full words of search strings. * * @param string $text Text where need highlight search string * @param array $search Search array. Can be string, simple array or array with 'search', 'replace' pairs * @param string $replace Default is just * @param bool $words If True search full words * * @return string */ function html_highlight($text, $search = [], $replace = '', $words = FALSE) { if (empty($replace)) { // Default is highlight as danger class $replace = $words ? '<em class="text-danger">$1</em>' : '<em class="text-danger">$0</em>'; } $entries = []; foreach ((array)$search as $entry) { if (isset($entry['search'])) { if (!isset($entry['replace'])) { $entry['replace'] = $replace; } $text = html_highlight($text, $entry['search'], $entry['replace'], $words); continue; } if (strlen($entry) == 0) { continue; } $entry = preg_quote($entry, '%'); // allow limited regex patterns in search strings (currently only for interfaces links) //$patterns = [ '\\\\d\+' => '\d+', ]; $entries[] = str_replace('\\\\d\+', '\d+', $entry); } if (!count($entries)) { return $text; } $search_pattern = '(' . implode('|', $entries) . ')'; if ($words) { // Search full words $search_pattern = str_replace('(?:', '(', OBS_PATTERN_START) . $search_pattern . str_replace('(?:', '(', OBS_PATTERN_END); // append start and end in pattern search $replace = '$1' . $replace . '$3'; } else { // Search any search string $search_pattern = '%' . $search_pattern . '%i'; } return preg_replace($search_pattern, $replace, $text); } /** * Silly class to assign and remember a unique class for a type. * * @param string $type * @param string $group * * @return string */ function get_type_class($type, $group = "unknown") { global $cache; if (isset($cache['type_class'][$group][$type])) { return $cache['type_class'][$group][$type]['class']; } $classes = [ 'primary', 'success', 'warning', 'error', 'suppressed' ]; if (isset($cache['type_class'][$group]['NEXT'])) { $next = $cache['type_class'][$group]['NEXT']; } else { $next = 0; } $cache['type_class'][$group][$type]['class'] = $classes[$next]; if (isset($classes[$next+1])) { $next++; } else { $next = 0; } $cache['type_class'][$group]['NEXT'] = $next; return $cache['type_class'][$group][$type]['class']; } /** * Silly class to return a label using persistent class for a certain string/type within a given group * * @param string $type * @param string $group * * @return string */ function get_type_class_label($type, $group = "unknown") { return '<span class="label label-'.get_type_class($type, $group).'">'.$type.'</span>'; } // EOF