1<?php 2 3/** 4 * Observium 5 * 6 * This file is part of Observium. 7 * 8 * @package observium 9 * @subpackage functions 10 * @copyright (C) 2006-2013 Adam Armstrong, (C) 2013-2019 Observium Limited 11 * 12 */ 13 14// Notifications and alerts in bottom navbar 15$notifications = array(); 16$alerts = array(); 17 18// Enable caching, currently only for WUI 19include_once($config['install_dir'] .'/includes/cache.inc.php'); 20 21include_once($config['html_dir'].'/includes/graphs/functions.inc.php'); 22 23$print_functions = array('addresses', 'events', 'mac_addresses', 'rows', 24 'status', 'arptable', 'fdbtable', 'navbar', 25 'search', 'syslogs', 'inventory', 'alert', 26 'authlog', 'dot1xtable', 'alert_log', 'logalert', 27 'common', 'routing', 'neighbours', 'billing'); 28 29foreach ($print_functions as $item) 30{ 31 $print_path = $config['html_dir'].'/includes/print/'.$item.'.inc.php'; 32 if (is_file($print_path)) { include($print_path); } 33} 34 35// Load generic entity include 36include($config['html_dir'].'/includes/entities/generic.inc.php'); 37 38// Load all per-entity includes 39foreach ($config['entities'] as $entity_type => $item) 40{ 41 $path = $config['html_dir'].'/includes/entities/'.$entity_type.'.inc.php'; 42 if (is_file($path)) { include($path); } 43} 44 45/** 46 * Used for replace some strings at end of run all html scripts 47 * 48 * @param string $buffer HTML buffer from ob_start() 49 * @return string Changed buffer 50 */ 51function html_callback($buffer) 52{ 53 global $config; 54 55 // Install registered CSS/JS links 56 $types = array( 57 'css' => ' <link href="%%STRING%%?v=' . OBSERVIUM_VERSION . '" rel="stylesheet" type="text/css" />' . PHP_EOL, 58 'style' => ' <style type="text/css">' . PHP_EOL . '%%STRING%%' . PHP_EOL . ' </style>' . PHP_EOL, 59 'js' => ' <script type="text/javascript" src="%%STRING%%?v=' . OBSERVIUM_VERSION . '"></script>' . PHP_EOL, 60 'script' => ' <script type="text/javascript">' . PHP_EOL . 61 ' <!-- Begin' . PHP_EOL . '%%STRING%%' . PHP_EOL . 62 ' // End -->' . PHP_EOL . ' </script>' . PHP_EOL, 63 'meta' => ' <meta http-equiv="%%STRING_http-equiv%%" content="%%STRING_content%%" />' . PHP_EOL, 64 ); 65 66 foreach ($types as $type => $string) 67 { 68 $uptype = strtoupper($type); 69 if (isset($GLOBALS['cache_html']['resources'][$type])) 70 { 71 $$type = '<!-- ' . $uptype . ' BEGIN -->' . PHP_EOL; 72 foreach (array_unique($GLOBALS['cache_html']['resources'][$type]) as $content) // Do not use global $cache variable, because it is reset before flush ob_cache 73 { 74 if (is_array($content)) 75 { 76 // for meta 77 foreach($content as $param => $value) 78 { 79 $string = str_replace('%%STRING_'.$param.'%%', $value, $string); 80 } 81 $$type .= $string; 82 } else { 83 $$type .= str_replace('%%STRING%%', $content, $string); 84 } 85 } 86 $$type .= ' <!-- ' . $uptype . ' END -->' . PHP_EOL; 87 $buffer = str_replace('<!-- ##' . $uptype . '_CACHE## -->' . PHP_EOL, $$type, $buffer); 88 } else { 89 // Clean template string 90 $buffer = str_replace('<!-- ##' . $uptype . '_CACHE## -->', '', $buffer); 91 } 92 } 93 94 // Replace page title as specified by the page modules 95 if (!is_array($GLOBALS['cache_html']['title'])) 96 { 97 // Title not set by any page, fall back to nicecase'd page name: 98 if ($GLOBALS['vars']['page'] && $_SESSION['authenticated']) 99 { 100 $GLOBALS['cache_html']['title'] = array(nicecase($GLOBALS['vars']['page'])); 101 } else { 102 // HALP. Likely main page, doesn't need anything else... 103 $GLOBALS['cache_html']['title'] = array(); 104 } 105 } 106 107 // If suffix is set, put it in the back 108 if ($config['page_title_suffix']) { $GLOBALS['cache_html']['title'][] = $config['page_title_suffix']; } 109 110 // If prefix is set, put it in front 111 if ($config['page_title_prefix']) { array_unshift($GLOBALS['cache_html']['title'], $config['page_title_prefix']); } 112 113 // Build title with separators 114 $title = implode($config['page_title_separator'], $GLOBALS['cache_html']['title']); 115 116 // Replace title placeholder by actual title 117 $buffer = str_replace('##TITLE##', escape_html($title), $buffer); 118 119 // Page panel 120 $buffer = str_replace('##PAGE_PANEL##', $GLOBALS['cache_html']['page_panel'], $buffer); 121 122 // UI Alerts 123 $buffer = str_replace('##UI_ALERTS##', $GLOBALS['ui_alerts'], $buffer); 124 125 // Return modified HTML page source 126 return $buffer; 127} 128 129/** 130 * Parse $_GET, $_POST and REQUEST_URI into $vars array 131 * 132 * @param array $vars_order Request variables order (POST, URI, GET) 133 * @param boolean $auth this var or ($_SESSION['authenticated']) used for allow to use var_decode() 134 * @return array array of vars 135 */ 136function get_vars($vars_order = array(), $auth = FALSE) 137{ 138 if (is_string($vars_order)) 139 { 140 $vars_order = explode(' ', $vars_order); 141 } 142 else if (empty($vars_order) || !is_array($vars_order)) 143 { 144 $vars_order = array('POST', 'URI', 'GET'); // Default order 145 } 146 147 // XSS script regex 148 // <sCrIpT> < / s c r i p t > 149 // javascript:alert("Hello world");/ 150 $prevent_xss = '!(^\s*(J\s*A\s*V\s*A\s*)?S\s*C\s*R\s*I\s*P\s*T\s*:|<\s*/?\s*S\s*C\s*R\s*I\s*P\s*T\s*>)!i'; 151 152 // Allow to use var_decode(), this prevent to use potentially unsafe serialize functions 153 $auth = $auth || $_SESSION['authenticated']; 154 155 $vars = array(); 156 foreach ($vars_order as $order) 157 { 158 $order = strtoupper($order); 159 switch ($order) 160 { 161 case 'POST': 162 // Parse POST variables into $vars 163 foreach ($_POST as $name => $value) 164 { 165 if (!isset($vars[$name])) 166 { 167 $vars[$name] = $auth ? var_decode($value) : $value; 168 if (preg_match($prevent_xss, $vars[$name])) 169 { 170 // Prevent any <script> html tag inside vars, exclude any possible XSS with scripts 171 unset($vars[$name]); 172 } 173 } 174 } 175 break; 176 case 'URI': 177 case 'URL': 178 // Parse URI into $vars 179 $segments = explode('/', trim($_SERVER['REQUEST_URI'], '/')); 180 foreach ($segments as $pos => $segment) 181 { 182 //$segment = urldecode($segment); 183 if ($pos == "0" && !str_contains($segment, '=')) 184 { 185 if (!preg_match($prevent_xss, $segment)) 186 { 187 // Prevent any <script> html tag inside vars, exclude any possible XSS with scripts 188 $segment = urldecode($segment); 189 $vars['page'] = $segment; 190 } 191 } else { 192 list($name, $value) = explode('=', $segment, 2); 193 if (!isset($vars[$name])) 194 { 195 if (!isset($value) || $value === '') 196 { 197 $vars[$name] = 'yes'; 198 } else { 199 $value = str_replace('%7F', '/', urldecode($value)); // %7F (DEL, delete) - not defined in HTML 4 standard 200 if (preg_match($prevent_xss, $value)) 201 { 202 // Prevent any <script> html tag inside vars, exclude any possible XSS with scripts 203 continue; 204 } 205 if (strpos($value, ',')) 206 { 207 // Here commas list (convert to array) 208 $vars[$name] = explode(',', $value); 209 } else { 210 // Here can be string as encoded array 211 $vars[$name] = $auth ? var_decode($value) : $value; 212 if (is_string($vars[$name]) && preg_match($prevent_xss, $vars[$name])) 213 { 214 // Prevent any <script> html tag inside vars, exclude any possible XSS with scripts 215 unset($vars[$name]); 216 } 217 } 218 if (strpos($vars[$name], '%1F') !== FALSE) 219 { 220 $vars[$name] = str_replace('%1F', ',', $vars[$name]); // %1F (US, unit separator) - not defined in HTML 4 standard 221 } 222 } 223 } 224 } 225 } 226 break; 227 case 'GET': 228 // Parse GET variable into $vars 229 foreach ($_GET as $name => $value) 230 { 231 if (!isset($vars[$name])) 232 { 233 $value = str_replace('%7F', '/', urldecode($value)); // %7F (DEL, delete) - not defined in HTML 4 standard 234 if (preg_match($prevent_xss, $value)) 235 { 236 // Prevent any <script> html tag inside vars, exclude any possible XSS with scripts 237 continue; 238 } 239 if (strpos($value, ',')) 240 { 241 // Here commas list (convert to array) 242 $vars[$name] = explode(',', $value); 243 } else { 244 // Here can be string as encoded array 245 $vars[$name] = $auth ? var_decode($value) : $value; 246 if (is_string($vars[$name]) && preg_match($prevent_xss, $vars[$name])) 247 { 248 // Prevent any <script> html tag inside vars, exclude any possible XSS with scripts 249 unset($vars[$name]); 250 } 251 } 252 if (strpos($vars[$name], '%1F') !== FALSE) 253 { 254 $vars[$name] = str_replace('%1F', ',', $vars[$name]); // %1F (US, unit separator) - not defined in HTML 4 standard 255 } 256 } 257 } 258 break; 259 } 260 } 261 262 // Always convert location to array 263 if (isset($vars['location'])) 264 { 265 if ($vars['location'] === '') 266 { 267 // Unset location if is empty string 268 unset($vars['location']); 269 } 270 else if (is_array($vars['location'])) 271 { 272 // Additionally decode locations if array entries encoded 273 foreach ($vars['location'] as $k => $location) 274 { 275 $vars['location'][$k] = $auth ? var_decode($location) : $location; 276 } 277 } else { 278 // All other location strings covert to array 279 $vars['location'] = array($vars['location']); 280 } 281 } 282 283 //r($vars); 284 return($vars); 285} 286 287/** 288 * Validate requests by compare session and request tokens. 289 * This prevents a CSRF attacks 290 * 291 * @param string|array $token Passed from request token or array with 'requesttoken' param inside. 292 * @return boolean TRUE if session requesttoken same as passed from request 293 */ 294function request_token_valid($token = NULL) 295{ 296 if (is_array($token)) 297 { 298 // If $vars array passed, fetch our default 'requesttoken' param 299 $token = $token['requesttoken']; 300 } 301 302 //print_vars($_SESSION['requesttoken']); 303 //print_vars($token); 304 305 // See: https://stackoverflow.com/questions/6287903/how-to-properly-add-csrf-token-using-php 306 // Session token generated after valid user auth in html/includes/authenticate.inc.php 307 if (empty($_SESSION['requesttoken'])) 308 { 309 // User not authenticated 310 //print_warning("Request passed by unauthorized user."); 311 return FALSE; 312 } 313 else if (empty($token)) 314 { 315 // Token not passed, WARNING seems as CSRF attack 316 print_error("WARNING. Possible CSRF attack with EMPTY request token."); 317 ///FIXME. need an user actions log 318 return FALSE; 319 } 320 else if (hash_equals($_SESSION['requesttoken'], $token)) 321 { 322 // Correct session and request tokens, all good 323 return TRUE; 324 } else { 325 // Passed incorrect request token, 326 // WARNING seems as CSRF attack 327 print_error("WARNING. Possible CSRF attack with INCORRECT request token."); 328 ///FIXME. need an user actions log 329 return FALSE; 330 } 331} 332 333/** 334 * Detect if current URI is link to graph 335 * 336 * @return boolean TRUE if current script is graph 337 */ 338// TESTME needs unit testing 339function is_graph() 340{ 341 if (!defined('OBS_GRAPH')) 342 { 343 // defined in html/graph.php 344 define('OBS_GRAPH', FALSE); 345 } 346 347 return OBS_GRAPH; 348 //return (realpath($_SERVER['SCRIPT_FILENAME']) === realpath($GLOBALS['config']['html_dir'].'/graph.php')); 349} 350 351// TESTME needs unit testing 352/** 353 * Generates base64 data uri with alert graph 354 * 355 * @return string 356 */ 357function generate_alert_graph($graph_array) 358{ 359 global $config; 360 361 $vars = $graph_array; 362 $auth = (is_cli() ? TRUE : $GLOBALS['auth']); // Always set $auth to true for cli 363 $vars['image_data_uri'] = TRUE; 364 $vars['height'] = '150'; 365 $vars['width'] = '400'; 366 $vars['legend'] = 'no'; 367 $vars['from'] = $config['time']['twoday']; 368 $vars['to'] = $config['time']['now']; 369 370 include($config['html_dir'].'/includes/graphs/graph.inc.php'); 371 372 return $image_data_uri; 373} 374 375// TESTME needs unit testing 376// DOCME needs phpdoc block 377function datetime_preset($preset) 378{ 379 $begin_fmt = 'Y-m-d 00:00:00'; 380 $end_fmt = 'Y-m-d 23:59:59'; 381 382 switch($preset) 383 { 384 case 'sixhours': 385 $from = date('Y-m-d H:i:00', strtotime('-6 hours')); 386 $to = date('Y-m-d H:i:59'); 387 break; 388 case 'today': 389 $from = date($begin_fmt); 390 $to = date($end_fmt); 391 break; 392 case 'yesterday': 393 $from = date($begin_fmt, strtotime('-1 day')); 394 $to = date($end_fmt, strtotime('-1 day')); 395 break; 396 case 'tweek': 397 $from = (date('l') == 'Monday') ? date($begin_fmt) : date($begin_fmt, strtotime('last Monday')); 398 $to = (date('l') == 'Sunday') ? date($end_fmt) : date($end_fmt, strtotime('next Sunday')); 399 break; 400 case 'lweek': 401 $from = date($begin_fmt, strtotime('-6 days')); 402 $to = date($end_fmt); 403 break; 404 case 'tmonth': 405 $tmonth = date('Y-m'); 406 $from = $tmonth.'-01 00:00:00'; 407 $to = date($end_fmt, strtotime($tmonth.' next month - 1 hour')); 408 break; 409 case 'lmonth': 410 $from = date($begin_fmt, strtotime('previous month + 1 day')); 411 $to = date($end_fmt); 412 break; 413 case 'tquarter': 414 case 'lquarter': 415 $quarter = ceil(date('m') / 3); // Current quarter 416 if ($preset == 'lquarter') 417 { 418 $quarter = $quarter - 1; // Previous quarter 419 } 420 $year = date('Y'); 421 if ($quarter < 1) 422 { 423 $year -= 1; 424 $quarter = 4; 425 } 426 $tmonth = $quarter * 3; 427 $fmonth = $tmonth - 2; 428 429 $from = $year.'-'.zeropad($fmonth).'-01 00:00:00'; 430 $to = date('Y-m-t 23:59:59', strtotime($year.'-'.$tmonth.'-01')); 431 break; 432 case 'tyear': 433 $from = date('Y-01-01 00:00:00'); 434 $to = date('Y-12-31 23:59:59'); 435 break; 436 case 'lyear': 437 $from = date($begin_fmt, strtotime('previous year + 1 day')); 438 $to = date($end_fmt); 439 break; 440 } 441 442 return array('from' => $from, 'to' => $to); 443} 444 445// TESTME needs unit testing 446// DOCME needs phpdoc block 447function bug() 448{ 449 echo('<div class="alert alert-error"> 450 <button type="button" class="close" data-dismiss="alert">×</button> 451 <strong>Bug!</strong> Please report this to the Observium development team. 452</div>'); 453} 454 455/** 456 * This function determines type of web browser for current User-Agent (mobile/tablet/generic). 457 * For more detailed browser info and custom User-Agent use detect_browser() 458 * 459 * @return string Return type of browser (generic/mobile/tablet) 460 */ 461function detect_browser_type() 462{ 463 $ua_info = detect_browser(); 464 465 return $ua_info['type']; 466} 467 468/** 469 * This function determines detailed info of web browser by User-Agent agent string. 470 * If User-Agent not passed, used current from $_SERVER['HTTP_USER_AGENT'] 471 * 472 * @param string $user_agent Custom User-Agent string, by default, the value of HTTP User-Agent header is used 473 * 474 * @return array Return detected browser info: user_agent, type, icon, platform, browser, version, 475 * browser_full - full browser name (ie: Chrome 43.0) 476 * svg - supported or not svg images (TRUE|FALSE), 477 * screen_ratio - for HiDPI screens it more that 1, 478 * screen_resolution - full resolution of client screen (if exist), 479 * screen_size - initial size of browser window (if exist) 480 */ 481// TESTME! needs unit testing 482function detect_browser($user_agent = NULL) 483{ 484 $ua_custom = !is_null($user_agent); // Used custom user agent? 485 486 if (!$ua_custom && isset($GLOBALS['cache']['detect_browser'])) 487 { 488 //if (isset($_COOKIE['observium_screen_ratio']) && !isset($GLOBALS['cache']['detect_browser']['screen_resolution'])) 489 //{ 490 // r($_COOKIE); 491 //} 492 // Return cached info 493 return $GLOBALS['cache']['detect_browser']; 494 } 495 496 $detect = new Mobile_Detect; 497 498 if ($ua_custom) 499 { 500 // Set custom User-Agent 501 $detect->setUserAgent($user_agent); 502 } else { 503 $user_agent = $_SERVER['HTTP_USER_AGENT']; 504 } 505 506 // Default type and icon 507 $type = 'generic'; 508 $icon = 'icon-laptop'; 509 if ($detect->isMobile()) 510 { 511 // Any phone device (exclude tablets). 512 $type = 'mobile'; 513 $icon = 'glyphicon glyphicon-phone'; 514 if ($detect->isTablet()) 515 { 516 // Any tablet device. 517 $type = 'tablet'; 518 $icon = 'icon-tablet'; 519 } 520 } 521 522 // Load additional function 523 if (!function_exists('parse_user_agent')) 524 { 525 include_once($GLOBALS['config']['install_dir'].'/libs/UserAgentParser.php'); 526 } 527 528 // Detect Browser name, version and platform 529 if (!empty($user_agent)) 530 { 531 $ua_info = parse_user_agent($user_agent); 532 } else { 533 $ua_info = array(); 534 } 535 536 $detect_browser = array('user_agent' => $user_agent, 537 'type' => $type, 538 'icon' => $icon, 539 'browser_full' => $ua_info['browser'] . ' ' . preg_replace('/^([^\.]+(?:\.[^\.]+)?).*$/', '\1', $ua_info['version']), 540 'browser' => $ua_info['browser'], 541 'version' => $ua_info['version'], 542 'platform' => $ua_info['platform']); 543 544 // For custom UA, do not cache and return only base User-Agent info 545 if ($ua_custom) 546 { 547 return $detect_browser; 548 } 549 550 // Load screen and DPI detector. This set cookies with: 551 // $_COOKIE['observium_screen_ratio'] - if ratio >= 2, than HiDPI screen is used 552 // $_COOKIE['observium_screen_resolution'] - screen resolution 'width x height', ie: 1920x1080 553 // $_COOKIE['observium_screen_size'] - current window size (less than resolution) 'width x height', ie: 1097x456 554 register_html_resource('js', 'observium-screen.js'); 555 556 // Additional browser info (screen_ratio, screen_size, svg) 557 if ($ua_info['browser'] == 'Firefox' && version_compare($ua_info['version'], '47.0') < 0) 558 { 559 // Do not use srcset in FF, while issue open: 560 // https://bugzilla.mozilla.org/show_bug.cgi?id=1149357 561 // Update, seems as in 47.0 partially fixed 562 $zoom = 1; 563 } 564 else if (isset($_COOKIE['observium_screen_ratio'])) 565 { 566 // Note, Opera uses ratio 1.5 567 $zoom = round($_COOKIE['observium_screen_ratio']); // Use int zoom 568 } else { 569 // If JS not supported or cookie not set, use default zoom 2 (for allow srcset) 570 $zoom = 2; 571 } 572 $detect_browser['screen_ratio'] = $zoom; 573 //$detect_browser['svg'] = ($ua_info['browser'] == 'Firefox'); // SVG supported or allowed 574 if (isset($_COOKIE['observium_screen_resolution'])) 575 { 576 $detect_browser['screen_resolution'] = $_COOKIE['observium_screen_resolution']; 577 //$detect_browser['screen_size'] = $_COOKIE['observium_screen_size']; 578 } 579 580 $GLOBALS['cache']['detect_browser'] = $detect_browser; // Store to cache 581 582 //r($GLOBALS['cache']['detect_browser']); 583 return $GLOBALS['cache']['detect_browser']; 584} 585 586// TESTME needs unit testing 587// DOCME needs phpdoc block 588function data_uri($file, $mime) 589{ 590 $contents = file_get_contents($file); 591 $base64 = base64_encode($contents); 592 593 return ('data:' . $mime . ';base64,' . $base64); 594} 595 596// TESTME needs unit testing 597// DOCME needs phpdoc block 598function toner_map($descr, $colour) 599{ 600 foreach ($GLOBALS['config']['toner'][$colour] as $str) 601 { 602 if (stripos($descr, $str) !== FALSE) { return TRUE; } 603 } 604 605 return FALSE; 606} 607 608// TESTME needs unit testing 609// DOCME needs phpdoc block 610function toner_to_colour($descr, $percent) 611{ 612 if (substr($descr, -1) == 'C' || toner_map($descr, "cyan" )) { $colour['left'] = "B6F6F6"; $colour['right'] = "33B4B1"; } 613 if (substr($descr, -1) == 'M' || toner_map($descr, "magenta")) { $colour['left'] = "FBA8E6"; $colour['right'] = "D028A6"; } 614 if (substr($descr, -1) == 'Y' || toner_map($descr, "yellow" )) { $colour['left'] = "FFF764"; $colour['right'] = "DDD000"; } 615 if (substr($descr, -1) == 'K' || toner_map($descr, "black" )) { $colour['left'] = "888787"; $colour['right'] = "555555"; } 616 if (substr($descr, -1) == 'R' || toner_map($descr, "red" )) { $colour['left'] = "FB6A4A"; $colour['right'] = "CB181D"; } 617 618 if (!isset($colour['left'])) { $colour = get_percentage_colours(100-$percent); $colour['found'] = FALSE; } else { $colour['found'] = TRUE; } 619 620 return $colour; 621} 622 623// TESTME needs unit testing 624// DOCME needs phpdoc block 625function generate_link($text, $vars, $new_vars = array(), $escape = TRUE) 626{ 627 if ($escape) { $text = escape_html($text); } 628 return '<a href="'.generate_url($vars, $new_vars).'">'.$text.'</a>'; 629} 630 631// TESTME needs unit testing 632// DOCME needs phpdoc block 633function pagination(&$vars, $total, $return_vars = FALSE) 634{ 635 $pagesizes = array(10,20,50,100,500,1000,10000,50000); // Permitted pagesizes 636 if (is_numeric($vars['pagesize'])) 637 { 638 $per_page = (int)$vars['pagesize']; 639 } 640 else if (isset($_SESSION['pagesize'])) 641 { 642 $per_page = $_SESSION['pagesize']; 643 } else { 644 $per_page = $GLOBALS['config']['web_pagesize']; 645 } 646 if (!$vars['short']) 647 { 648 // Permit fixed pagesizes only (except $vars['short'] == TRUE) 649 foreach ($pagesizes as $pagesize) 650 { 651 if ($per_page <= $pagesize) { $per_page = $pagesize; break; } 652 } 653 if (isset($vars['pagesize']) && $vars['pagesize'] != $_SESSION['pagesize']) 654 { 655 if ($vars['pagesize'] != $GLOBALS['config']['web_pagesize']) 656 { 657 session_set_var('pagesize', $per_page); // Store pagesize in session only if changed default 658 } 659 else if (isset($_SESSION['pagesize'])) 660 { 661 session_unset_var('pagesize'); // Reset pagesize from session 662 } 663 } 664 } 665 $vars['pagesize'] = $per_page; // Return back current pagesize 666 667 $page = (int)$vars['pageno']; 668 $lastpage = ceil($total/$per_page); 669 if ($page < 1) { $page = 1; } 670 else if (!$return_vars && $lastpage < $page) { $page = (int)$lastpage; } 671 $vars['pageno'] = $page; // Return back current pageno 672 673 if ($return_vars) { return ''; } // Silent exit (needed for detect default pagesize/pageno) 674 675 $start = ($page - 1) * $per_page; 676 $prev = $page - 1; 677 $next = $page + 1; 678 $lpm1 = $lastpage - 1; 679 680 $adjacents = 3; 681 $pagination = ''; 682 683 if ($total > 99 || $total > $per_page) 684 { 685 686 if($total > 9999) { $total_text = format_si($total); } else { $total_text = $total; } 687 688 689 $pagination .= '<div class="row">' . PHP_EOL . 690 ' <div class="col-lg-1 col-md-2 col-sm-2" style="display: inline-block;">' . PHP_EOL . 691 //' <span class="btn disabled" style="line-height: 20px;">'.$total.' Items</span>' . PHP_EOL . 692 ' <div class="box box-solid" style="padding: 4px 12px;">'.$total_text.' Items</div>' . PHP_EOL . 693 ' </div>' . PHP_EOL . 694 ' <div class="col-lg-10 col-md-8 col-sm-8">' . PHP_EOL . 695 ' <div class="pagination pagination-centered"><ul>' . PHP_EOL; 696 697 if ($prev) 698 { 699 //$pagination .= ' <li><a href="'.generate_url($vars, array('pageno' => 1)).'">First</a></li>' . PHP_EOL; 700 $pagination .= ' <li><a href="'.generate_url($vars, array('pageno' => $prev)).'">Prev</a></li>' . PHP_EOL; 701 } 702 703 if ($lastpage < 7 + ($adjacents * 2)) 704 { 705 for ($counter = 1; $counter <= $lastpage; $counter++) 706 { 707 if ($counter == $page) 708 { 709 $pagination.= "<li class='active'><a>$counter</a></li>"; 710 } else { 711 $pagination.= "<li><a href='".generate_url($vars, array('pageno' => $counter))."'>$counter</a></li>"; 712 } 713 } 714 } 715 elseif ($lastpage > 5 + ($adjacents * 2)) 716 { 717 if ($page < 1 + ($adjacents * 2)) 718 { 719 for ($counter = 1; $counter < 4 + ($adjacents * 2); $counter++) 720 { 721 if ($counter == $page) 722 { 723 $pagination .= "<li class='active'><a>$counter</a></li>"; 724 } else { 725 $class = ''; 726 //if ($counter > 9) 727 //{ 728 // $class = ' class="hidden-md hidden-sm hidden-xs"'; 729 //} 730 //else if ($counter > 6) 731 //{ 732 // $class = ' class="hidden-sm hidden-xs"'; 733 //} 734 $pagination .= "<li$class><a href='".generate_url($vars, array('pageno' => $counter))."'>$counter</a></li>"; 735 } 736 } 737 738 $pagination.= "<li><a href='".generate_url($vars, array('pageno' => $lpm1))."'>$lpm1</a></li>"; 739 $pagination.= "<li><a href='".generate_url($vars, array('pageno' => $lastpage))."'>$lastpage</a></li>"; 740 } 741 elseif ($lastpage - ($adjacents * 2) > $page && $page > ($adjacents * 2)) 742 { 743 $pagination.= "<li><a href='".generate_url($vars, array('pageno' => '1'))."'>1</a></li>"; 744 $pagination.= "<li><a href='".generate_url($vars, array('pageno' => '2'))."'>2</a></li>"; 745 746 for ($counter = $page - $adjacents; $counter <= $page + $adjacents; $counter++) 747 { 748 if ($counter == $page) 749 { 750 $pagination.= "<li class='active'><a>$counter</a></li>"; 751 } else { 752 $pagination.= "<li><a href='".generate_url($vars, array('pageno' => $counter))."'>$counter</a></li>"; 753 } 754 } 755 756 $pagination.= "<li><a href='".generate_url($vars, array('pageno' => $lpm1))."'>$lpm1</a></li>"; 757 $pagination.= "<li><a href='".generate_url($vars, array('pageno' => $lastpage))."'>$lastpage</a></li>"; 758 } else { 759 $pagination.= "<li><a href='".generate_url($vars, array('pageno' => '1'))."'>1</a></li>"; 760 $pagination.= "<li><a href='".generate_url($vars, array('pageno' => '2'))."'>2</a></li>"; 761 for ($counter = $lastpage - (2 + ($adjacents * 2)); $counter <= $lastpage; $counter++) 762 { 763 if ($counter == $page) 764 { 765 $pagination.= "<li class='active'><a>$counter</a></li>"; 766 } else { 767 $class = ''; 768 //if ($lastpage - $counter > 9) 769 //{ 770 // $class = ' class="hidden-md hidden-sm hidden-xs"'; 771 //} 772 //else if ($lastpage - $counter > 6) 773 //{ 774 // $class = ' class="hidden-sm hidden-xs"'; 775 //} 776 $pagination.= "<li$class><a href='".generate_url($vars, array('pageno' => $counter))."'>$counter</a></li>"; 777 } 778 } 779 } 780 } 781 782 if ($page < $counter - 1) 783 { 784 $pagination.= "<li><a href='".generate_url($vars, array('pageno' => $next))."'>Next</a></li>"; 785 # No need for "Last" as we don't have "First", 1, 2 and the 2 last pages are always in the list. 786 #$pagination.= "<li><a href='".generate_url($vars, array('pageno' => $lastpage))."'>Last</a></li>"; 787 } 788 else if ($lastpage > 1) 789 { 790 $pagination.= "<li class='active'><a>Next</a></li>"; 791 #$pagination.= "<li class='active'><a>Last</a></li>"; 792 } 793 794 $pagination.= "</ul></div></div>"; 795 796 //$values = array('' => array('name')) 797 foreach ($pagesizes as $pagesize) 798 { 799 $value = generate_url($vars, array('pagesize' => $pagesize, 'pageno' => floor($start / $pagesize))); 800 $name = ($pagesize == $GLOBALS['config']['web_pagesize'] ? "[ $pagesize ]" : $pagesize); 801 $values[$value] = array('name' => $name, 'class' => 'text-center'); 802 } 803 $element = array('type' => 'select', 804 'class' => 'pagination', 805 'id' => 'pagesize', 806 'name' => '# '.$per_page, 807 'width' => '90px', 808 'onchange' => "window.open(this.options[this.selectedIndex].value,'_top')", 809 'value' => $per_page, 810 'data-style' => 'box', 811 'values' => $values); 812 813 $pagination.= ' 814 <div class="col-lg-1 col-md-2 col-sm-2"> 815 <form class="pull-right pagination" action="#">'; 816 817 $pagination .= generate_form_element($element); 818 819 $pagination .= '</form></div></div>'; 820 } 821 822 return $pagination; 823} 824 825// TESTME needs unit testing 826// DOCME needs phpdoc block 827function generate_url($vars, $new_vars = array()) 828{ 829 $vars = ($vars) ? array_merge($vars, $new_vars) : $new_vars; 830 831 $url = $vars['page']; 832 if ($url[strlen($url)-1] !== '/') { $url .= '/'; } 833 unset($vars['page']); 834 835 foreach ($vars as $var => $value) 836 { 837 if ($var == "username" || $var == "password") 838 { 839 // Ignore these vars. They shouldn't end up in URLs. 840 } 841 else if (is_array($value)) 842 { 843 $url .= urlencode($var) . '=' . var_encode($value) . '/'; 844 } 845 else if ($value == "0" || $value != "" && strstr($var, "opt") === FALSE && is_numeric($var) === FALSE) 846 { 847 $url .= urlencode($var) . '=' . urlencode(str_replace('/', '%7F', $value)).'/'; // %7F converted back to / in get_vars() 848 } 849 } 850 851 // If we're being generated outside of the web interface, prefix the generated URL to make it work properly. 852 if (is_cli()) 853 { 854 if ($GLOBALS['config']['web_url'] == 'http://localhost:80/') 855 { 856 // override default web_url by http://localhost/ 857 $url = 'http://'.get_localhost().'/'.$url; 858 } else { 859 $url = $GLOBALS['config']['web_url'] . $url; 860 } 861 } 862 863 return($url); 864} 865 866// TESTME needs unit testing 867// DOCME needs phpdoc block 868function generate_feed_url($vars) 869{ 870 $url = FALSE; 871 if (!class_exists('SimpleXMLElement')) { return $url; } // Break if class SimpleXMLElement is not available. 872 873 if (is_numeric($_SESSION['user_id']) && is_numeric($_SESSION['userlevel'])) 874 { 875 $key = get_user_pref($_SESSION['user_id'], 'atom_key'); 876 } 877 if ($key) 878 { 879 $param = array(rtrim($GLOBALS['config']['base_url'], '/').'/feed.php?id='.$_SESSION['user_id']); 880 $param[] = 'hash='.encrypt($_SESSION['user_id'].'|'.$_SESSION['userlevel'].'|'.$_SESSION['auth_mechanism'], $key); 881 882 $feed_type = 'atom'; 883 foreach ($vars as $var => $value) 884 { 885 if ($value != '') 886 { 887 switch ($var) 888 { 889 case 'v': 890 if ($value == 'rss') 891 { 892 $param[] = "$var=rss"; 893 $feed_type = 'rss'; 894 } 895 break; 896 case 'feed': 897 $title = "Observium :: ".ucfirst($value)." Feed"; 898 $param[] = 'size='.$GLOBALS['config']['frontpage']['eventlog']['items']; 899 // no break here 900 case 'size': 901 $param[] = "$var=$value"; 902 break; 903 } 904 } 905 } 906 907 $baseurl = implode('&', $param); 908 909 $url = '<link href="'.$baseurl.'" rel="alternate" title="'.escape_html($title).'" type="application/'.$feed_type.'+xml" />'; 910 } 911 912 return $url; 913} 914 915// TESTME needs unit testing 916// DOCME needs phpdoc block 917function generate_location_url($location, $vars = array()) 918{ 919 if ($location === '') { $location = OBS_VAR_UNSET; } 920 $value = var_encode($location); 921 return generate_url(array('page' => 'devices', 'location' => $value), $vars); 922} 923 924// TESTME needs unit testing 925// DOCME needs phpdoc block 926function generate_overlib_content($graph_array, $text = NULL, $escape = TRUE) 927{ 928 global $config; 929 930 $graph_array['height'] = "100"; 931 $graph_array['width'] = "210"; 932 933 if ($escape) { $text = escape_html($text); } 934 935 $content = '<div style="width: 590px;"><span style="font-weight: bold; font-size: 16px;">'.$text.'</span><br />'; 936 /* 937 $box_args = array('body-style' => 'width: 590px;'); 938 if (strlen($text)) 939 { 940 $box_args['title'] = $text; 941 } 942 $content = generate_box_open($box_args); 943 */ 944 foreach (array('day', 'week', 'month', 'year') as $period) 945 { 946 $graph_array['from'] = $config['time'][$period]; 947 $content .= generate_graph_tag($graph_array); 948 } 949 $content .= "</div>"; 950 //$content .= generate_box_close(); 951 952 return $content; 953} 954 955// TESTME needs unit testing 956// DOCME needs phpdoc block 957function get_percentage_colours($percentage) 958{ 959 960 if ($percentage > '90') { $background['left']='cb181d'; $background['right']='fb6a4a'; $background['class'] = 'error'; } 961 elseif ($percentage > '80') { $background['left']='cc4c02'; $background['right']='fe9929'; $background['class'] = 'warning'; } 962 elseif ($percentage > '60') { $background['left']='6a51a3'; $background['right']='9e9ac8'; $background['class'] = 'information'; } 963 elseif ($percentage > '30') { $background['left']='045a8d'; $background['right']='74a9cf'; $background['class'] = 'information'; } 964 else { $background['left']='4d9221'; $background['right']='7fbc41'; $background['class'] = 'information'; } 965 966 return($background); 967} 968 969/** 970 * Generate common popup links which uses ajax/entitypopup.php 971 * 972 * @param string $type Popup type, see possible types in html/ajax/entitypopup.php 973 * @param string $text Text used as link name and ajax data 974 * @param array $vars Array for generate url 975 * @param string Additional css classes for link 976 * @param boolean $escape Escape or not text in url 977 * @return string Returns string with link, when hover on this link show popup message based on type 978 */ 979function generate_popup_link($type, $text = NULL, $vars = array(), $class = NULL, $escape = TRUE) 980{ 981 if (!is_string($type) || !is_string($text)) { return ''; } 982 983 if ($type == 'ip') 984 { 985 list($ip, $mask) = explode('/', $text, 2); 986 $ip_version = get_ip_version($ip); 987 if ($ip_version === 6) 988 { 989 // Autocompress IPv6 addresses 990 $ip = Net_IPv6::compress($ip); 991 $text = $ip; 992 if (strlen($mask)) 993 { 994 $text .= '/' . $mask; 995 } 996 } 997 if (!$ip_version || in_array($ip, array('0.0.0.0', '127.0.0.1', '::', '::1'))) 998 { 999 return $text; 1000 } 1001 } 1002 $url = (count($vars) ? generate_url($vars) : 'javascript:void(0)'); // If vars empty, set link not clickable 1003 $data = $text; 1004 if ($escape) { $text = escape_html($text); } 1005 1006 return '<a href="'.$url.'" class="entity-popup'.($class ? " $class" : '').'" data-eid="'.$data.'" data-etype="'.$type.'">'.$text.'</a>'; 1007} 1008 1009/** 1010 * Generate mouseover links with static tooltip from URL, link text, contents and a class. 1011 * 1012 * Tooltips with static position and linked to current object. 1013 * Note, mostly same as overlib_link(), except tooltip position. 1014 * Always display tooltip if content not empty 1015 * 1016 * @param string $url URL string 1017 * @param string $text Text displayed as link 1018 * @param string $contents Text content displayed in mouseover tooltip (only for non-mobile devices) 1019 * @param string $class Css class name used for link 1020 * @param boolean $escape Escape or not link text 1021 * @return string 1022 */ 1023// TESTME needs unit testing 1024function generate_tooltip_link($url, $text, $contents = '', $class = NULL, $escape = FALSE) 1025{ 1026 global $config, $link_iter; 1027 1028 $link_iter++; 1029 1030 $href = (strlen($url) ? 'href="' . $url . '"' : ''); 1031 if ($escape) { $text = escape_html($text); } 1032 1033 // Allow the Grinch to disable popups and destroy Christmas. 1034 $allow_mobile = (in_array(detect_browser_type(), array('mobile', 'tablet')) ? $config['web_mouseover_mobile'] : TRUE); 1035 if ($config['web_mouseover'] && strlen($contents) && $allow_mobile) 1036 { 1037 $output = '<a '.$href.' class="'.$class.'" style="cursor: pointer;" data-rel="tooltip" data-tooltip="'.escape_html($contents).'">'.$text.'</a>'; 1038 //$output = '<a '.$href.' class="'.$class.'" data-toggle="tooltip" title="'.escape_html($contents).'">'.$text.'</a>'; 1039 } else { 1040 $output = '<a '.$href.' class="'.$class.'">'.$text.'</a>'; 1041 } 1042 1043 return $output; 1044} 1045 1046/** 1047 * Generate mouseover links from URL, link text, contents and a class. 1048 * 1049 * Tooltips followed by mouse cursor. 1050 * Note, by default text NOT escaped for compatability with many old magic code usage. 1051 * 1052 * @param string $url URL string 1053 * @param string $text Text displayed as link 1054 * @param string $contents Text content displayed in mouseover tooltip (only for non-mobile devices) 1055 * @param string $class Css class name used for link 1056 * @param boolean $escape Escape or not link text 1057 */ 1058// TESTME needs unit testing 1059// RENAMEME to generate_mouseover_link() or something similar 1060function overlib_link($url, $text, $contents, $class = NULL, $escape = FALSE) 1061{ 1062 global $config, $link_iter; 1063 1064 $link_iter++; 1065 1066 $href = (strlen($url) ? 'href="' . $url . '"' : ''); 1067 if ($escape) { $text = escape_html($text); } 1068 1069 // Allow the Grinch to disable popups and destroy Christmas. 1070 $allow_mobile = (in_array(detect_browser_type(), array('mobile', 'tablet')) ? $config['web_mouseover_mobile'] : TRUE); 1071 if ($config['web_mouseover'] && strlen($contents) && $allow_mobile) 1072 { 1073 $output = '<a '.$href.' class="tooltip-from-data '.$class.'" style="cursor: pointer;" data-tooltip="'.escape_html($contents).'">'.$text.'</a>'; 1074 } else { 1075 $output = '<a '.$href.' class="'.$class.'">'.$text.'</a>'; 1076 } 1077 1078 return $output; 1079} 1080 1081/** 1082 * Generate menu links with item counts from URL, link text, contents and a class. 1083 * 1084 * Tooltips with static position and linked to current object. 1085 * Note, mostly same as overlib_link(), except tooltip position. 1086 * Always display tooltip if content not empty 1087 * 1088 * @param string $url URL string 1089 * @param string $text Text displayed as link 1090 * @param string $count Counts displayed at right 1091 * @param string $class Css class name used for count (default is 'label') 1092 * @param boolean $escape Escape or not link text 1093 */ 1094// TESTME needs unit testing 1095function generate_menu_link($url, $text, $count = NULL, $class = 'label', $escape = FALSE, $alert_count = NULL) 1096{ 1097 $href = (strlen($url) ? 'href="' . $url . '"' : ''); 1098 if ($escape) { $text = escape_html($text); } 1099 1100 $output = '<a role="menuitem" ' . $href . '><span>' . $text . '</span>'; 1101 1102 if (is_numeric($alert_count)) 1103 { 1104 $output .= '<span class="label label-danger">' . $alert_count . '</span>'; 1105 } 1106 1107 if (is_numeric($count)) 1108 { 1109 $output .= '<span class="' . $class . '">' . $count . '</span>'; 1110 } 1111 1112 $output .= '</a>'; 1113 1114 return $output; 1115} 1116 1117 1118/** 1119 * Generate menu links with item counts from URL, link text, contents and a class. 1120 * 1121 * Replaces previous function with multiple arguments. Should be used for all navbar menus 1122 * 1123 * @param string $array Array of options 1124 */ 1125// TESTME needs unit testing 1126function generate_menu_link_new($array) 1127{ 1128 1129 $array = array_merge(array( 1130 'count' => NULL, 1131 'escape' => FALSE, 1132 'class' => 'label' 1133 ), $array); 1134 1135 $link_opts = ''; 1136 if (isset($array['link_opts'])) { $link_opts .= ' ' . $array['link_opts']; } 1137 if (isset($array['alt'])) { $link_opts .= ' data-rel="tooltip" data-tooltip="'.$array['alt'].'"'; } 1138 if (isset($array['id'])) { $link_opts .= ' id="'.$array['id'].'"'; } 1139 1140 if (empty($array['url']) || $array['url'] == '#') { $array['url'] = 'javascript:void(0)'; } 1141 1142 if ($array['escape']) { $array['text'] = escape_html($array['text']); } 1143 1144 $output = '<a role="menuitem" href="'.$array['url'].'" '.$link_opts.'>'; 1145 1146 $output .= '<span>'; 1147 if (isset($array['icon'])) 1148 { 1149 $output .= '<i class="' . $array['icon'] . '"></i> '; 1150 } 1151 $output .= $array['text'] . '</span>'; 1152 1153 // Counter label(s) in navbar menu 1154 if (isset($array['count_array']) && count($array['count_array'])) { 1155 // Multiple counts as group 1156 $count_items = []; 1157 // Ok/Up 1158 if ($array['count_array']['ok']) { $count_items[] = ['event' => 'success', 'text' => $array['count_array']['ok']]; } 1159 else if ($array['count_array']['up']) { $count_items[] = ['event' => 'success', 'text' => $array['count_array']['up']]; } 1160 // Warning 1161 if ($array['count_array']['warning']) { $count_items[] = ['event' => 'warning', 'text' => $array['count_array']['warning']]; } 1162 // Alert/Down 1163 if ($array['count_array']['alert']) { $count_items[] = ['event' => 'danger', 'text' => $array['count_array']['alert']]; } 1164 else if ($array['count_array']['down']) { $count_items[] = ['event' => 'danger', 'text' => $array['count_array']['down']]; } 1165 // Ignored 1166 if ($array['count_array']['ignored']) { $count_items[] = ['event' => 'default', 'text' => $array['count_array']['ignored']]; } 1167 // Disabled 1168 if ($array['count_array']['disabled']) { $count_items[] = ['event' => 'inverse', 'text' => $array['count_array']['disabled']]; } 1169 // Fallback to just count 1170 if (!count($count_items) && strlen($array['count_array']['count'])) { 1171 $count_items[] = ['event' => 'default', 'text' => $array['count_array']['count']]; 1172 } 1173 1174 //r(get_label_group($count_items)); 1175 $output .= get_label_group($count_items); 1176 } else { 1177 // single counts 1178 if (is_numeric($array['alert_count'])) 1179 { 1180 $output .= ' <span class="label label-danger">' . $array['alert_count'] . '</span> '; 1181 } 1182 1183 if (is_numeric($array['count'])) 1184 { 1185 $output .= ' <span class="' . $array['class'] . '">' . $array['count'] . '</span>'; 1186 } 1187 } 1188 1189 $output .= '</a>'; 1190 1191 return $output; 1192} 1193 1194 1195// Generate a typical 4-graph popup using $graph_array 1196// TESTME needs unit testing 1197// DOCME needs phpdoc block 1198function generate_graph_popup($graph_array) 1199{ 1200 global $config; 1201 1202 // Todo - this should have entity headers where appropriate, too. 1203 1204 // Take $graph_array and print day,week,month,year graps in overlib, hovered over graph 1205 1206 $original_from = $graph_array['from']; 1207 1208 $graph = generate_graph_tag($graph_array); 1209 1210 /* 1211 $box_args = array('body-style' => 'width: 850px;'); 1212 if (strlen($graph_array['popup_title'])) 1213 { 1214 $box_args['title'] = $graph_array['popup_title']; 1215 } 1216 $content = generate_box_open($box_args); 1217 */ 1218 unset($graph_array['style']); 1219 $content = '<div class=entity-title><h4>'.$graph_array['popup_title'].'</h4></div>'; 1220 $content .= '<div style="width: 850px">'; 1221 $graph_array['legend'] = "yes"; 1222 $graph_array['height'] = "100"; 1223 $graph_array['width'] = "340"; 1224 $graph_array['from'] = $config['time']['day']; 1225 $content .= generate_graph_tag($graph_array); 1226 $graph_array['from'] = $config['time']['week']; 1227 $content .= generate_graph_tag($graph_array); 1228 $graph_array['from'] = $config['time']['month']; 1229 $content .= generate_graph_tag($graph_array); 1230 $graph_array['from'] = $config['time']['year']; 1231 $content .= generate_graph_tag($graph_array); 1232 $content .= "</div>"; 1233 //$content .= generate_box_close(); 1234 1235 $graph_array['from'] = $original_from; 1236 1237 $graph_array['link'] = generate_url($graph_array, array('page' => 'graphs', 'height' => NULL, 'width' => NULL, 'bg' => NULL)); 1238 1239 return overlib_link($graph_array['link'], $graph, $content, NULL); 1240} 1241 1242// output the popup generated in generate_graph_popup(); 1243// TESTME needs unit testing 1244// DOCME needs phpdoc block 1245function print_graph_popup($graph_array) 1246{ 1247 echo(generate_graph_popup($graph_array)); 1248} 1249 1250// TESTME needs unit testing 1251// DOCME needs phpdoc block 1252function permissions_cache($user_id) 1253{ 1254 $permissions = array(); 1255 1256 foreach (dbFetchRows("SELECT * FROM `entity_permissions` WHERE `user_id` = ?", array($user_id)) as $entity) 1257 { 1258 switch($entity['entity_type']) 1259 { 1260 case "group": // this is a group, so expand it's members into an array 1261 $group = get_group_by_id($entity['entity_id']); 1262 foreach(get_group_entities($entity['entity_id']) as $group_entity_id) 1263 { 1264 $permissions[$group['entity_type']][$group_entity_id] = TRUE; 1265 } 1266 //break; // And also store self group permission in cache 1267 default: 1268 $permissions[$entity['entity_type']][$entity['entity_id']] = TRUE; 1269 break; 1270 } 1271 } 1272 1273 // Alerts 1274 $alert = array(); 1275 foreach (dbFetchRows('SELECT `alert_table_id`, `device_id`, `entity_id`, `entity_type` FROM `alert_table`') as $alert_table_entry) 1276 { 1277 //r($alert_table_entry); 1278 if (is_entity_permitted($alert_table_entry['entity_id'], $alert_table_entry['entity_type'], $alert_table_entry['device_id'], $permissions)) 1279 { 1280 $alert[$alert_table_entry['alert_table_id']] = TRUE; 1281 } 1282 } 1283 if (count($alert)) 1284 { 1285 $permissions['alert'] = $alert; 1286 } 1287 1288 return $permissions; 1289} 1290 1291/** 1292 * Return WEB client remote IP address. 1293 * In mostly cases (also by default) this is just $_SERVER['REMOTE_ADDR'], 1294 * but if config options ($config['web_remote_addr_header']) set, this can use specified HTTP headers 1295 * 1296 * @param boolean Use or not HTTP header specified in $config['web_remote_addr_header'] 1297 * @return string IP address of remote client 1298 */ 1299function get_remote_addr($use_http_header = FALSE) 1300{ 1301 if ($use_http_header) 1302 { 1303 // Note, this headers is very dangerous for use as auth! 1304 switch ($config['web_remote_addr_header']) 1305 { 1306 case 'CF-Connecting-IP': // CloudFlare network 1307 case 'X-Real-IP': 1308 case 'Client-IP': 1309 case 'X-Forwarded-For': 1310 $header = 'HTTP_' . strtoupper(str_replace('-', '_', $config['web_remote_addr_header'])); 1311 if (!empty($_SERVER[$header]) && preg_match(OBS_PATTERN_IP_FULL, $_SERVER[$header], $matches)) 1312 { 1313 // HTTP header founded and it contains valid IP address 1314 return $matches[1]; 1315 } 1316 break; 1317 } 1318 } 1319 1320 // By default just use server remote address 1321 return $_SERVER['REMOTE_ADDR']; 1322} 1323 1324/** 1325 * Every time you call session_start(), PHP adds another 1326 * identical session cookie to the response header. Do this 1327 * enough times, and your response header becomes big enough 1328 * to choke the web server. 1329 * 1330 * This method clears out the duplicate session cookies. You can 1331 * call it after each time you've called session_start(), or call it 1332 * just before you send your headers. 1333 */ 1334function clear_duplicate_cookies() { 1335 // If headers have already been sent, there's nothing we can do 1336 if (headers_sent()) { 1337 return; 1338 } 1339 1340 $cookies = array(); 1341 foreach (headers_list() as $header) { 1342 // Identify cookie headers 1343 if (strpos($header, 'Set-Cookie:') === 0) { 1344 $cookies[] = $header; 1345 } 1346 } 1347 // Removes all cookie headers, including duplicates 1348 header_remove('Set-Cookie'); 1349 1350 // Restore one copy of each cookie 1351 foreach(array_unique($cookies) as $cookie) { 1352 header($cookie, false); 1353 } 1354} 1355 1356/** 1357 * Store cached device/port/etc permitted IDs into $_SESSION['cache'] 1358 * 1359 * IDs collected in html/includes/cache-data.inc.php 1360 * This function used mostly in print_search() or print_form(), see html/includes/print/search.inc.php 1361 * Cached IDs from $_SESSION used in ajax forms by generate_query_permitted() 1362 * 1363 * @return null 1364 */ 1365function permissions_cache_session() 1366{ 1367 if (!$_SESSION['authenticated']) { return; } 1368 1369 if (isset($GLOBALS['permissions_cached_session'])) { return; } // skip if this function already run. FIXME? 1370 1371 @session_start(); // Re-enable write to session 1372 1373 // Store device IDs in SESSION var for use to check permissions with ajax queries 1374 foreach (array('permitted', 'disabled', 'ignored') as $key) 1375 { 1376 $_SESSION['cache']['devices'][$key] = $GLOBALS['cache']['devices'][$key]; 1377 } 1378 1379 // Store port IDs in SESSION var for use to check permissions with ajax queries 1380 foreach (array('permitted', 'deleted', 'errored', 'ignored', 'poll_disabled', 'device_disabled', 'device_ignored') as $key) 1381 { 1382 $_SESSION['cache']['ports'][$key] = $GLOBALS['cache']['ports'][$key]; 1383 } 1384 1385 $GLOBALS['permissions_cached_session'] = TRUE; 1386 1387 session_commit(); // Write and close session 1388} 1389 1390// TESTME needs unit testing 1391// DOCME needs phpdoc block 1392function bill_permitted($bill_id) 1393{ 1394 global $permissions; 1395 1396 if ($_SESSION['userlevel'] >= "5") 1397 { 1398 $allowed = TRUE; 1399 } elseif ($permissions['bill'][$bill_id]) { 1400 $allowed = TRUE; 1401 } else { 1402 $allowed = FALSE; 1403 } 1404 1405 return $allowed; 1406} 1407 1408 1409 1410// TESTME needs unit testing 1411// MOVEME to includes/functions.inc.php 1412/** 1413 * Returns a device_id when given an entity_id and an entity_type. Returns FALSE if the device isn't found. 1414 * 1415 * @param $entity_id 1416 * @param $entity_type 1417 * 1418 * @return bool|integer 1419 */ 1420function get_device_id_by_entity_id($entity_id, $entity_type) 1421{ 1422 // $entity = get_entity_by_id_cache($entity_type, $entity_id); 1423 $translate = entity_type_translate_array($entity_type); 1424 1425 if (isset($translate['device_id_field']) && $translate['device_id_field'] && 1426 is_numeric($entity_id) && $entity_type) 1427 { 1428 $device_id = dbFetchCell('SELECT `' . $translate['device_id_field'] . '` FROM `' . $translate['table']. '` WHERE `' . $translate['id_field'] . '` = ?', array($entity_id)); 1429 } 1430 if (is_numeric($device_id)) 1431 { 1432 return $device_id; 1433 } else { 1434 return FALSE; 1435 } 1436} 1437 1438// TESTME needs unit testing 1439// DOCME needs phpdoc block 1440function port_permitted($port_id, $device_id = NULL) 1441{ 1442 return is_entity_permitted($port_id, 'port', $device_id); 1443} 1444 1445// TESTME needs unit testing 1446// DOCME needs phpdoc block 1447function port_permitted_array(&$ports) 1448{ 1449 // Strip out the ports the user isn't allowed to see, if they don't have global rights 1450 if ($_SESSION['userlevel'] < '7') 1451 { 1452 foreach ($ports as $key => $port) 1453 { 1454 if (!port_permitted($port['port_id'], $port['device_id'])) 1455 { 1456 unset($ports[$key]); 1457 } 1458 } 1459 } 1460} 1461 1462function entity_permitted_array(&$entities, $entity_type) 1463{ 1464 1465 $entity_type_data = entity_type_translate_array($entity_type); 1466 1467 // Strip out the entities the user isn't allowed to see, if they don't have global view rights 1468 if (!isset($_SESSION['user_limited']) || $_SESSION['user_limited']) 1469 { 1470 foreach ($entities as $key => $entity) 1471 { 1472 if (!is_entity_permitted($entity[$entity_type_data['id_field']], $entity_type, $entity['device_id'])) 1473 { 1474 unset($entities[$key]); 1475 } 1476 } 1477 } 1478} 1479 1480 1481// TESTME needs unit testing 1482// DOCME needs phpdoc block 1483function application_permitted($app_id, $device_id = NULL) 1484{ 1485 global $permissions; 1486 1487 if (is_numeric($app_id)) 1488 { 1489 if (!$device_id) { $device_id = get_device_id_by_app_id ($app_id); } 1490 if ($_SESSION['userlevel'] >= "5") { 1491 $allowed = TRUE; 1492 } elseif (device_permitted($device_id)) { 1493 $allowed = TRUE; 1494 } elseif ($permissions['application'][$app_id]) { 1495 $allowed = TRUE; 1496 } else { 1497 $allowed = FALSE; 1498 } 1499 } else { 1500 $allowed = FALSE; 1501 } 1502 1503 return $allowed; 1504} 1505 1506// TESTME needs unit testing 1507// DOCME needs phpdoc block 1508function device_permitted($device_id) 1509{ 1510 global $permissions; 1511 1512 if ($_SESSION['userlevel'] >= "5") 1513 { 1514 $allowed = true; 1515 } elseif ($permissions['device'][$device_id]) { 1516 $allowed = true; 1517 } else { 1518 $allowed = false; 1519 } 1520 1521 return $allowed; 1522} 1523 1524// TESTME needs unit testing 1525// DOCME needs phpdoc block 1526function print_graph_tag($args) 1527{ 1528 echo(generate_graph_tag($args)); 1529} 1530 1531// TESTME needs unit testing 1532// DOCME needs phpdoc block 1533function generate_graph_tag($args, $return_array = FALSE) 1534{ 1535 1536 if (empty($args)) { return ''; } // Quick return if passed empty array 1537 1538 $style = 'max-width: 100%; width: auto; vertical-align: top;'; 1539 if (isset($args['style'])) 1540 { 1541 if (is_array($args['style'])) 1542 { 1543 $style .= implode("; ", $args['style']) . ';'; 1544 } else { 1545 $style .= $args['style'] . ';'; 1546 } 1547 unset($args['style']); 1548 } 1549 1550 if (isset($args['img_id'])) 1551 { 1552 $i['img_id'] = $args['img_id']; 1553 } else { 1554 $i['img_id'] = generate_random_string(8); 1555 } 1556 1557 // Detect allowed screen ratio for current browser 1558 $ua_info = detect_browser(); 1559 $zoom = $ua_info['screen_ratio']; 1560 1561 if ($zoom >= 2) 1562 { 1563 // Add img srcset for HiDPI screens 1564 $args_x = $args; 1565 $args_x['zoom'] = $zoom; 1566 $srcset = ' srcset="'.generate_graph_url($args_x).' '.$args_x['zoom'].'x"'; 1567 $i['srcset'] = $attribs; 1568 } else{ 1569 $srcset = ''; 1570 } 1571 1572 if(isset($args['class'])) 1573 { $attribs .= ' class="'.$args['class'].'"'; unset($args['class']); } 1574 1575 1576 $img_url = generate_graph_url($args); 1577 1578 $i['img_url'] = $img_url; 1579 $i['img_tag'] = '<img id="' . $i['img_id'] . '" src="' . $img_url . '"' . $srcset . $attribs.' style="' . $style . '" alt="" />'; 1580 1581 1582 if($return_array === TRUE) 1583 { 1584 return $i; 1585 } else { 1586 return $i['img_tag']; 1587 } 1588} 1589 1590 1591function generate_graph_url($args) 1592{ 1593 1594 foreach ($args as $key => $arg) 1595 { 1596 if (is_array($arg)) { $arg = var_encode($arg); } // Encode arrays 1597 $urlargs[] = $key."=".$arg; 1598 } 1599 1600 $url = 'graph.php?' . implode('&',$urlargs); 1601 1602 if (is_cli()) 1603 { 1604 if ($GLOBALS['config']['web_url'] == 'http://localhost:80/') 1605 { 1606 // override default web_url by http://localhost/ 1607 $url = 'http://'.get_localhost().'/'.$url; 1608 } else { 1609 $url = $GLOBALS['config']['web_url'] . $url; 1610 } 1611 } 1612 1613 return $url; 1614 1615} 1616 1617// TESTME needs unit testing 1618// DOCME needs phpdoc block 1619function generate_graph_js_state($args) 1620{ 1621 // we are going to assume we know roughly what the graph url looks like here. 1622 // TODO: Add sensible defaults 1623 $from = (is_numeric($args['from']) ? $args['from'] : 0); 1624 $to = (is_numeric($args['to']) ? $args['to'] : 0); 1625 $width = (is_numeric($args['width']) ? $args['width'] : 0); 1626 $height = (is_numeric($args['height']) ? $args['height'] : 0); 1627 $legend = str_replace("'", "", $args['legend']); 1628 1629 $state = <<<STATE 1630<script type="text/javascript"> 1631document.graphFrom = $from; 1632document.graphTo = $to; 1633document.graphWidth = $width; 1634document.graphHeight = $height; 1635document.graphLegend = '$legend'; 1636</script> 1637STATE; 1638 1639 return $state; 1640} 1641 1642/** 1643 * Generate Percentage Bar 1644 * 1645 * This function generates an Observium percentage bar from a supplied array of arguments. 1646 * It is possible to draw a bar that does not work at all, 1647 * So care should be taken to make sure values are valid. 1648 * 1649 * @param array $args 1650 * @return string 1651 */ 1652 1653// TESTME needs unit testing 1654function percentage_bar($args) 1655{ 1656 if (strlen($args['bg'])) { $style .= 'background-color:'.$args['bg'].';'; } 1657 if (strlen($args['border'])) { $style .= 'border-color:'.$args['border'].';'; } 1658 if (strlen($args['width'])) { $style .= 'width:'.$args['width'].';'; } 1659 if (strlen($args['text_c'])) { $style_b .= 'color:'.$args['text_c'].';'; } 1660 1661 $total = '0'; 1662 $output = '<div class="percbar" style="'.$style.'">'; 1663 foreach ($args['bars'] as $bar) 1664 { 1665 $output .= '<div class="bar" style="width:'.$bar['percent'].'%; background-color:'.$bar['colour'].';"></div>'; 1666 $total += $bar['percent']; 1667 } 1668 $left = '100' - $total; 1669 if ($left > 0) { $output .= '<div class="bar" style="width:'.$left.'%;"></div>'; } 1670 1671 if ($left >= 0) { $output .= '<div class="bar-text" style="margin-left: -100px; margin-top: 0px; float: right; text-align: right; '.$style_b.'">'.$args['text'].'</div>'; } 1672 1673 foreach ($args['bars'] as $bar) 1674 { 1675 $output .= '<div class="bar-text" style="width:'.$bar['percent'].'%; max-width:'.$bar['percent'].'%; padding-left: 4px;">'.$bar['text'].'</div>'; 1676 } 1677# if ($left > '0') { $output .= '<div class="bar-text" style="margin-left: -100px; margin-top: -16px; float: right; text-align: right; '.$style_b.'">'.$args['text'].'</div>'; } 1678 1679 $output .= '</div>'; 1680 1681 return $output; 1682} 1683 1684// Legacy function 1685// DO NOT USE THIS. Please replace instances of it with percentage_bar from above. 1686// TESTME needs unit testing 1687// DOCME needs phpdoc block 1688function print_percentage_bar($width, $height, $percent, $left_text, $left_colour, $left_background, $right_text, $right_colour, $right_background) 1689{ 1690 1691 if ($percent > "100") { $size_percent = "100"; } else { $size_percent = $percent; } 1692 1693 $percentage_bar['border'] = "#".$left_background; 1694 $percentage_bar['bg'] = "#".$right_background; 1695 $percentage_bar['width'] = $width; 1696 $percentage_bar['text'] = $right_text; 1697 $percentage_bar['bars'][0] = array('percent' => $size_percent, 'colour' => '#'.$left_background, 'text' => $left_text); 1698 1699 $output = percentage_bar($percentage_bar); 1700 1701 return $output; 1702} 1703 1704// DOCME needs phpdoc block 1705function print_optionbar_start($height = 0, $width = 0, $marginbottom = 5) 1706{ 1707 echo(PHP_EOL . '<div class="box box-solid well-shaded">' . PHP_EOL); 1708} 1709 1710// DOCME needs phpdoc block 1711function print_optionbar_end() 1712{ 1713 echo(PHP_EOL . ' </div>' . PHP_EOL); 1714} 1715 1716// TESTME needs unit testing 1717// DOCME needs phpdoc block 1718function geteventicon($message) 1719{ 1720 if ($message == "Device status changed to Down") { $icon = "server_connect.png"; } 1721 if ($message == "Device status changed to Up") { $icon = "server_go.png"; } 1722 if ($message == "Interface went down" || $message == "Interface changed state to Down") { $icon = "if-disconnect.png"; } 1723 if ($message == "Interface went up" || $message == "Interface changed state to Up") { $icon = "if-connect.png"; } 1724 if ($message == "Interface disabled") { $icon = "if-disable.png"; } 1725 if ($message == "Interface enabled") { $icon = "if-enable.png"; } 1726 if (isset($icon)) { return $icon; } else { return false; } 1727} 1728 1729function get_entity_icon($entity) 1730{ 1731 1732 $config['entities'][$entity['type']]['icon']; 1733 1734} 1735 1736// TESTME needs unit testing 1737// DOCME needs phpdoc block 1738function overlibprint($text) 1739{ 1740 return "onmouseover=\"return overlib('" . $text . "');\" onmouseout=\"return nd();\""; 1741} 1742 1743// TESTME needs unit testing 1744// DOCME needs phpdoc block 1745function device_link_class($device) 1746{ 1747 if (isset($device['status']) && $device['status'] == '0') { $class = "red"; } else { $class = ""; } 1748 if (isset($device['ignore']) && $device['ignore'] == '1') 1749 { 1750 $class = "grey"; 1751 if (isset($device['status']) && $device['status'] == '1') { $class = "green"; } 1752 } 1753 if (isset($device['disabled']) && $device['disabled'] == '1') { $class = "grey"; } 1754 1755 return $class; 1756} 1757 1758/** 1759 * Return cached locations list 1760 * 1761 * If filter used, return locations avialable only for specified params. 1762 * Without filter return all avialable locations (cached) 1763 * 1764 * @param array $filter 1765 * @return array 1766 */ 1767// TESTME needs unit testing 1768function get_locations($filter = array()) 1769{ 1770 foreach ($filter as $var => $value) 1771 { 1772 switch ($var) 1773 { 1774 case 'location_lat': 1775 case 'location_lon': 1776 case 'location_country': 1777 case 'location_state': 1778 case 'location_county': 1779 case 'location_city': 1780 // Check geo params only when GEO enabled globally 1781 if (!$GLOBALS['config']['geocoding']['enable']) { break; } 1782 case 'location': 1783 $where_array[$var] = generate_query_values($value, $var); 1784 break; 1785 } 1786 } 1787 1788 if (count($where_array)) 1789 { 1790 // Return only founded locations 1791 $where = implode('', $where_array) . $GLOBALS['cache']['where']['devices_permitted']; 1792 $locations = dbFetchColumn("SELECT DISTINCT `location` FROM `devices_locations` WHERE 1 $where;"); 1793 } else { 1794 $locations = array(); 1795 foreach ($GLOBALS['cache']['device_locations'] as $location => $count) 1796 { 1797 $locations[] = $location; 1798 } 1799 } 1800 sort($locations); 1801 1802 return $locations; 1803} 1804 1805// TESTME needs unit testing 1806// DOCME needs phpdoc block 1807function foldersize($path) 1808{ 1809 $total_size = 0; 1810 $files = scandir($path); 1811 $total_files = 0; 1812 1813 foreach ($files as $t) 1814 { 1815 if (is_dir(rtrim($path, '/') . '/' . $t)) 1816 { 1817 if ($t<>"." && $t<>"..") 1818 { 1819 $size = foldersize(rtrim($path, '/') . '/' . $t); 1820 $total_size += $size; 1821 } 1822 } else { 1823 $size = filesize(rtrim($path, '/') . '/' . $t); 1824 $total_size += $size; 1825 $total_files++; 1826 } 1827 } 1828 1829 return array($total_size, $total_files); 1830} 1831 1832// return the filename of the device RANCID config file 1833// TESTME needs unit testing 1834// DOCME needs phpdoc block 1835function get_rancid_filename($hostname, $rdebug = FALSE) 1836{ 1837 global $config; 1838 1839 $hostnames = array($hostname); 1840 1841 if ($rdebug) { echo("Hostname: $hostname<br />"); } 1842 1843 // Also check non-FQDN hostname. 1844 list($shortname) = explode('.', $hostname); 1845 1846 if ($rdebug) { echo("Short hostname: $shortname<br />"); } 1847 1848 if ($shortname != $hostname) 1849 { 1850 $hostnames[] = $shortname; 1851 if ($rdebug) { echo("Hostname different from short hostname, looking for both<br />"); } 1852 } 1853 1854 // Addition of a domain suffix for non-FQDN device names. 1855 if (isset($config['rancid_suffix']) && $config['rancid_suffix'] !== '') 1856 { 1857 $hostnames[] = $hostname . '.' . trim($config['rancid_suffix'], ' .'); 1858 if ($rdebug) { echo("RANCID suffix configured, also looking for " . $hostname . '.' . trim($config['rancid_suffix'], ' .') . "<br />"); } 1859 } 1860 1861 foreach ($config['rancid_configs'] as $config_path) 1862 { 1863 if ($config_path[strlen($config_path)-1] != '/') { $config_path .= '/'; } 1864 if ($rdebug) { echo("Looking in configured directory: <b>$config_path</b><br />"); } 1865 1866 foreach ($hostnames as $host) 1867 { 1868 if (is_file($config_path . $host)) 1869 { 1870 if ($rdebug) { echo("File <b>" . $config_path . $host . "</b> found.<br />"); } 1871 return $config_path . $host; 1872 } else { 1873 if ($rdebug) { echo("File <b>" . $config_path . $host . "</b> not found.<br />"); } 1874 } 1875 } 1876 } 1877 1878 return FALSE; 1879} 1880 1881// return the filename of the device NFSEN rrd file 1882// TESTME needs unit testing 1883// DOCME needs phpdoc block 1884function get_nfsen_filename($hostname) 1885{ 1886 global $config; 1887 1888 $nfsen_rrds = (is_array($config['nfsen_rrds']) ? $config['nfsen_rrds'] : array($config['nfsen_rrds'])); 1889 foreach ($nfsen_rrds as $nfsen_rrd) 1890 { 1891 if ($nfsen_rrd[strlen($nfsen_rrd)-1] != '/') { $nfsen_rrd .= '/'; } 1892 $basefilename_underscored = preg_replace('/\./', $config['nfsen_split_char'], $hostname); 1893 1894 // Remove suffix and prefix from basename 1895 $nfsen_filename = $basefilename_underscored; 1896 if (isset($config['nfsen_suffix']) && strlen($config['nfsen_suffix'])) 1897 { 1898 $nfsen_filename = (strstr($nfsen_filename, $config['nfsen_suffix'], TRUE)); 1899 } 1900 if (isset($config['nfsen_prefix']) && strlen($config['nfsen_prefix'])) 1901 { 1902 $nfsen_filename = (strstr($nfsen_filename, $config['nfsen_prefix'])); 1903 } 1904 1905 $nfsen_rrd_file = $nfsen_rrd . $nfsen_filename . '.rrd'; 1906 if (is_file($nfsen_rrd_file)) 1907 { 1908 return $nfsen_rrd_file; 1909 } 1910 } 1911 1912 return FALSE; 1913} 1914 1915// Note, by default text NOT escaped. 1916// TESTME needs unit testing 1917// DOCME needs phpdoc block 1918function generate_ap_link($args, $text = NULL, $type = NULL, $escape = FALSE) 1919{ 1920 global $config; 1921 1922 humanize_port($args); 1923 1924 if (!$text) { $text = escape_html($args['port_label']); } 1925 if ($type) { $args['graph_type'] = $type; } 1926 if (!isset($args['graph_type'])) { $args['graph_type'] = 'port_bits'; } 1927 1928 if (!isset($args['hostname'])) { $args = array_merge($args, device_by_id_cache($args['device_id'])); } 1929 1930 $content = "<div class=entity-title>". $args['text'] . " - " . escape_html($args['port_label']) . "</div>"; 1931 if ($args['ifAlias']) { $content .= escape_html($args['ifAlias']) . "<br />"; } 1932 $content .= "<div style=\'width: 850px\'>"; 1933 $graph_array['type'] = $args['graph_type']; 1934 $graph_array['legend'] = "yes"; 1935 $graph_array['height'] = "100"; 1936 $graph_array['width'] = "340"; 1937 $graph_array['to'] = $config['time']['now']; 1938 $graph_array['from'] = $config['time']['day']; 1939 $graph_array['id'] = $args['accesspoint_id']; 1940 $content .= generate_graph_tag($graph_array); 1941 $graph_array['from'] = $config['time']['week']; 1942 $content .= generate_graph_tag($graph_array); 1943 $graph_array['from'] = $config['time']['month']; 1944 $content .= generate_graph_tag($graph_array); 1945 $graph_array['from'] = $config['time']['year']; 1946 $content .= generate_graph_tag($graph_array); 1947 $content .= "</div>"; 1948 1949 $url = generate_ap_url($args); 1950 if (port_permitted($args['interface_id'], $args['device_id'])) 1951 { 1952 return overlib_link($url, $text, $content, $class, $escape); 1953 } else { 1954 return $text; 1955 } 1956} 1957 1958// TESTME needs unit testing 1959// DOCME needs phpdoc block 1960function generate_ap_url($ap, $vars=array()) 1961{ 1962 return generate_url(array('page' => 'device', 'device' => $ap['device_id'], 'tab' => 'accesspoint', 'ap' => $ap['accesspoint_id']), $vars); 1963} 1964 1965/** 1966 * Generate SQL WHERE string with check permissions and ignores for device_id, port_id and other 1967 * 1968 * Note, this function uses comparison operator IN. Max number of values in the IN list 1969 * is limited by the 'max_allowed_packet' option (default: 1048576) 1970 * 1971 * Usage examples: 1972 * generate_query_permitted() 1973 * ' AND `device_id` IN (1,4,8,33) AND `device_id` NOT IN (66) AND (`device_id` != '' AND `device_id` IS NOT NULL) ' 1974 * generate_query_permitted(array('device'), array('device_table' => 'D')) 1975 * ' 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) ' 1976 * generate_query_permitted(array('device', 'port'), array('port_table' => 'I')) == 1977 * ' AND `device_id` IN (1,4,8,33) AND `device_id` NOT IN (66) AND (`device_id` != '' AND `device_id` IS NOT NULL) 1978 * 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) ' 1979 * generate_query_permitted(array('device', 'port'), array('port_table' => 'I', 'hide_ignored' => TRUE)) 1980 * This additionaly exclude all ignored devices and ports 1981 * 1982 * @uses html/includes/cache-data.inc.php 1983 * @global integer $_SESSION['userlevel'] 1984 * @global boolean $GLOBALS['config']['web_show_disabled'] 1985 * @global array $GLOBALS['permissions'] 1986 * @global array $GLOBALS['cache']['devices'] 1987 * @global array $GLOBALS['cache']['ports'] 1988 * @global string $GLOBALS['vars']['page'] 1989 * @param array|string $type_array Array with permission types, currently allowed 'devices', 'ports' 1990 * @param array $options Options for each permission type: device_table, port_table, hide_ignored, hide_disabled 1991 * @return string 1992 */ 1993// TESTME needs unit testing 1994function generate_query_permitted($type_array = array('device'), $options = array()) 1995{ 1996 if (!is_array($type_array)) { $type_array = array($type_array); } 1997 $user_limited = ($_SESSION['userlevel'] < 5 ? TRUE : FALSE); 1998 $page = $GLOBALS['vars']['page']; 1999 2000 // If device IDs stored in SESSION use it (used in ajax) 2001 //if (!isset($GLOBALS['cache']['devices']) && isset($_SESSION['cache']['devices'])) 2002 //{ 2003 // $GLOBALS['cache']['devices'] = $_SESSION['cache']['devices']; 2004 //} 2005 2006 if (!isset($GLOBALS['permissions'])) 2007 { 2008 // Note, this function must used after load permissions list! 2009 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!"); 2010 } 2011 // Use option hide_disabled if passed or use config 2012 $options['hide_disabled'] = (isset($options['hide_disabled']) ? (bool)$options['hide_disabled'] : !$GLOBALS['config']['web_show_disabled']); 2013 2014 //$query_permitted = ''; 2015 2016 foreach ($type_array as $type) 2017 { 2018 switch ($type) 2019 { 2020 // Devices permission query 2021 case 'device': 2022 case 'devices': 2023 $column = '`device_id`'; 2024 $query_permitted = array(); 2025 if (isset($options['device_table'])) { $column = '`'.$options['device_table'].'`.'.$column; } 2026 2027 // Show only permitted devices 2028 if ($user_limited) 2029 { 2030 if (count($GLOBALS['permissions']['device'])) 2031 { 2032 $query_permitted[] = " $column IN (". 2033 implode(',', array_keys($GLOBALS['permissions']['device'])). 2034 ')'; 2035 2036 } else { 2037 // Exclude all entries, because there is no permitted devices 2038 $query_permitted[] = ' 0'; 2039 } 2040 } 2041 2042 // Also don't show ignored and disabled devices (except on 'device' and 'devices' pages) 2043 $devices_excluded = array(); 2044 if (strpos($page, 'device') !== 0) 2045 { 2046 if ($options['hide_ignored'] && count($GLOBALS['cache']['devices']['ignored'])) 2047 { 2048 $devices_excluded = array_merge($devices_excluded, $GLOBALS['cache']['devices']['ignored']); 2049 } 2050 if ($options['hide_disabled'] && count($GLOBALS['cache']['devices']['disabled'])) 2051 { 2052 $devices_excluded = array_merge($devices_excluded, $GLOBALS['cache']['devices']['disabled']); 2053 } 2054 } 2055 if (count($devices_excluded)) 2056 { 2057 // Set query with excluded devices 2058 $query_permitted[] = " $column NOT IN (". 2059 implode(',', array_unique($devices_excluded)). 2060 ')'; 2061 } 2062 2063 // At the end excluded entries with empty/null device_id (wrong entries) 2064 //$query_permitted[] = " ($column != '' AND $column IS NOT NULL)"; 2065 $query_permitted[] = " $column IS NOT NULL"; // Note: SELECT '' = 0; is TRUE 2066 $query_part[] = implode(" AND ", $query_permitted); 2067 unset($query_permitted); 2068 break; 2069 // Ports permission query 2070 case 'port': 2071 case 'ports': 2072 $column = '`port_id`'; 2073 if (isset($options['port_table'])) { $column = '`'.$options['port_table'].'`.'.$column; } 2074 2075 // If port IDs stored in SESSION use it (used in ajax) 2076 //if (!isset($GLOBALS['cache']['ports']) && isset($_SESSION['cache']['ports'])) 2077 //{ 2078 // $GLOBALS['cache']['ports'] = $_SESSION['cache']['ports']; 2079 //} 2080 2081 // Show only permitted ports 2082 if ($user_limited) 2083 { 2084 if (count($GLOBALS['permissions']['port'])) 2085 { 2086 $query_permitted[] = " $column IN (" . 2087 implode(',', array_keys($GLOBALS['permissions']['port'])) . 2088 ')'; 2089 } else { 2090 // Exclude all entries, because there is no permitted ports 2091 $query_permitted[] = '0'; 2092 } 2093 } 2094 2095 $ports_excluded = array(); 2096 // Don't show ports with disabled polling. 2097 if (count($GLOBALS['cache']['ports']['poll_disabled'])) 2098 { 2099 $ports_excluded = array_merge($ports_excluded, $GLOBALS['cache']['ports']['poll_disabled']); 2100 //foreach ($GLOBALS['cache']['ports']['poll_disabled'] as $entry) 2101 //{ 2102 // $ports_excluded[] = $entry; 2103 //} 2104 //$ports_excluded = array_unique($ports_excluded); 2105 } 2106 // Don't show deleted ports (except on 'deleted-ports' page) 2107 if ($page != 'deleted-ports' && count($GLOBALS['cache']['ports']['deleted'])) 2108 { 2109 $ports_excluded = array_merge($ports_excluded, $GLOBALS['cache']['ports']['deleted']); 2110 //foreach ($GLOBALS['cache']['ports']['deleted'] as $entry) 2111 //{ 2112 // $ports_excluded[] = $entry; 2113 //} 2114 //$ports_excluded = array_unique($ports_excluded); 2115 } 2116 if ($page != 'device' && !in_array('device', $type_array)) 2117 { 2118 // Don't show ports for disabled devices (except on 'device' page or if 'device' permissions already queried) 2119 if ($options['hide_disabled'] && !$user_limited && count($GLOBALS['cache']['ports']['device_disabled'])) 2120 { 2121 $ports_excluded = array_merge($ports_excluded, $GLOBALS['cache']['ports']['device_disabled']); 2122 //foreach ($GLOBALS['cache']['ports']['device_disabled'] as $entry) 2123 //{ 2124 // $ports_excluded[] = $entry; 2125 //} 2126 //$ports_excluded = array_unique($ports_excluded); 2127 } 2128 // Don't show ports for ignored devices (except on 'device' page) 2129 if ($options['hide_ignored'] && count($GLOBALS['cache']['ports']['device_ignored'])) 2130 { 2131 $ports_excluded = array_merge($ports_excluded, $GLOBALS['cache']['ports']['device_ignored']); 2132 //foreach ($GLOBALS['cache']['ports']['device_ignored'] as $entry) 2133 //{ 2134 // $ports_excluded[] = $entry; 2135 //} 2136 //$ports_excluded = array_unique($ports_excluded); 2137 } 2138 } 2139 // Don't show ignored ports (only on some pages!) 2140 if (($page == 'overview' || $options['hide_ignored']) && count($GLOBALS['cache']['ports']['ignored'])) 2141 { 2142 $ports_excluded = array_merge($ports_excluded, $GLOBALS['cache']['ports']['ignored']); 2143 //foreach ($GLOBALS['cache']['ports']['ignored'] as $entry) 2144 //{ 2145 // $ports_excluded[] = $entry; 2146 //} 2147 //$ports_excluded = array_unique($ports_excluded); 2148 } 2149 unset($entry); 2150 if (count($ports_excluded)) 2151 { 2152 // Set query with excluded ports 2153 $query_permitted[] = $column . " NOT IN (". 2154 implode(',', array_unique($ports_excluded)). 2155 ')'; 2156 2157 } 2158 2159 // At the end excluded entries with empty/null port_id (wrong entries) 2160 //$query_permitted[] = "($column != '' AND $column IS NOT NULL)"; 2161 $query_permitted[] = "$column IS NOT NULL"; 2162 2163 $query_part[] = implode(" AND ", $query_permitted); 2164 unset($query_permitted); 2165 2166 break; 2167 case 'sensor': 2168 case 'sensors': 2169 // For sensors 2170 // FIXME -- this is easily generifyable, just use translate_table_array() 2171 2172 $column = '`sensor_id`'; 2173 2174 if (isset($options['sensor_table'])) { $column = '`'.$options['sensor_table'].'`.'.$column; } 2175 2176 // If IDs stored in SESSION use it (used in ajax) 2177 //if (!isset($GLOBALS['cache']['sensors']) && isset($_SESSION['cache']['sensors'])) 2178 //{ 2179 // $GLOBALS['cache']['sensors'] = $_SESSION['cache']['sensors']; 2180 //} 2181 2182 // Show only permitted entities 2183 if ($user_limited) 2184 { 2185 if (count($GLOBALS['permissions']['sensor'])) 2186 { 2187 $query_permitted .= " $column IN ("; 2188 $query_permitted .= implode(',', array_keys($GLOBALS['permissions']['sensor'])); 2189 $query_permitted .= ')'; 2190 } else { 2191 // Exclude all entries, because there are no permitted entities 2192 $query_permitted .= '0'; 2193 } 2194 $query_part[] = $query_permitted; 2195 unset($query_permitted); 2196 } 2197 2198 break; 2199 2200 case 'alert': 2201 case 'alerts': 2202 // For generic alert 2203 2204 $column = '`alert_table_id`'; 2205 2206 // Show only permitted entities 2207 if ($user_limited) 2208 { 2209 if (count($GLOBALS['permissions']['alert'])) 2210 { 2211 $query_permitted .= " $column IN ("; 2212 $query_permitted .= implode(',', array_keys($GLOBALS['permissions']['alert'])); 2213 $query_permitted .= ')'; 2214 } else { 2215 // Exclude all entries, because there are no permitted entities 2216 $query_permitted .= '0'; 2217 } 2218 $query_part[] = $query_permitted; 2219 unset($query_permitted); 2220 } 2221 2222 break; 2223 case 'bill': 2224 case 'bills': 2225 // For bills 2226 break; 2227 } 2228 } 2229 if (count($query_part)) 2230 { 2231 //r($query_part); 2232 if ($user_limited) 2233 { 2234 // Limited user must use OR for include multiple entities 2235 $query_permitted = " AND ((".implode(") OR (", $query_part)."))"; 2236 } else { 2237 // Unlimited used must use AND for exclude multiple hidden entities 2238 $query_permitted = " AND ((".implode(") AND (", $query_part)."))"; 2239 } 2240 } 2241 2242 $query_permitted .= ' '; 2243 2244 //r($query_permitted); 2245 2246 return $query_permitted; 2247} 2248 2249// TESTME needs unit testing 2250// DOCME needs phpdoc block 2251function get_user_prefs($user_id) 2252{ 2253 $prefs = array(); 2254 foreach (dbFetchRows("SELECT * FROM `users_prefs` WHERE `user_id` = ?", array($user_id)) as $entry) 2255 { 2256 $prefs[$entry['pref']] = $entry; 2257 } 2258 return $prefs; 2259} 2260 2261// TESTME needs unit testing 2262// DOCME needs phpdoc block 2263function get_user_pref($user_id, $pref) 2264{ 2265 if ($entry = dbFetchRow("SELECT `value` FROM `users_prefs` WHERE `user_id` = ? AND `pref` = ?", array($user_id, $pref))) 2266 { 2267 return $entry['value']; 2268 } 2269 else 2270 { 2271 return NULL; 2272 } 2273} 2274 2275// TESTME needs unit testing 2276// DOCME needs phpdoc block 2277function set_user_pref($user_id, $pref, $value) 2278{ 2279 //if (dbFetchCell("SELECT COUNT(*) FROM `users_prefs` WHERE `user_id` = ? AND `pref` = ?", array($user_id, $pref))) 2280 if (dbExist('users_prefs', '`user_id` = ? AND `pref` = ?', array($user_id, $pref))) 2281 { 2282 $id = dbUpdate(array('value' => $value), 'users_prefs', '`user_id` = ? AND `pref` = ?', array($user_id, $pref)); 2283 } else { 2284 $id = dbInsert(array('user_id' => $user_id, 'pref' => $pref, 'value' => $value), 'users_prefs'); 2285 } 2286 return $id; 2287} 2288 2289// TESTME needs unit testing 2290// DOCME needs phpdoc block 2291function del_user_pref($user_id, $pref) 2292{ 2293 return dbDelete('users_prefs', "`user_id` = ? AND `pref` = ?", array($user_id, $pref)); 2294} 2295 2296// TESTME needs unit testing 2297// DOCME needs phpdoc block 2298function get_smokeping_files($rdebug = 0) 2299{ 2300 global $config; 2301 2302 $smokeping_files = array(); 2303 2304 if ($rdebug) { echo('- Recursing through ' . $config['smokeping']['dir'] . '<br />'); } 2305 2306 if (isset($config['smokeping']['master_hostname'])) 2307 { 2308 $master_hostname = $config['smokeping']['master_hostname']; 2309 } else { 2310 $master_hostname = $config['own_hostname']; 2311 } 2312 2313 if (is_dir($config['smokeping']['dir'])) 2314 { 2315 foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($config['smokeping']['dir'])) as $file) 2316 { 2317 if (basename($file) != "." && basename($file) != ".." && strstr($file, ".rrd")) 2318 { 2319 if ($rdebug) { echo('- Found file ending in ".rrd": ' . basename($file) . '<br />'); } 2320 2321 if (strstr($file, "~")) 2322 { 2323 list($target,$slave) = explode("~", basename($file,".rrd")); 2324 if ($rdebug) { echo('- Determined to be a slave file for target <b>' . $target . '</b><br />'); } 2325 $target = str_replace($config['smokeping']['split_char'], ".", $target); 2326 if ($config['smokeping']['suffix']) { $target = $target.$config['smokeping']['suffix']; if ($rdebug) { echo('- Suffix is configured, target is now <b>' . $target . '</b><br />'); } } 2327 $smokeping_files['incoming'][$target][$slave] = $file; 2328 $smokeping_files['outgoing'][$slave][$target] = $file; 2329 } else { 2330 $target = basename($file,".rrd"); 2331 if ($rdebug) { echo('- Determined to be a local file, for target <b>' . $target . '</b><br />'); } 2332 $target = str_replace($config['smokeping']['split_char'], ".", $target); 2333 if ($rdebug) { echo('- After replacing configured split_char ' . $config['smokeping']['split_char'] . ' by . target is <b>' . $target . '</b><br />'); } 2334 if ($config['smokeping']['suffix']) { $target = $target.$config['smokeping']['suffix']; if ($rdebug) { echo('- Suffix is configured, target is now <b>' . $target . '</b><br />'); } } 2335 $smokeping_files['incoming'][$target][$master_hostname] = $file; 2336 $smokeping_files['outgoing'][$master_hostname][$target] = $file; 2337 } 2338 } 2339 } 2340 } else { 2341 if ($rdebug) { echo("- Smokeping RRD directory not found: " . $config['smokeping']['dir']); } 2342 } 2343 2344 return $smokeping_files; 2345} 2346 2347/** 2348 * Darkens or lightens a colour 2349 * Found via http://codepad.org/MTGLWVd0 2350 * 2351 * First argument is the colour in hex, second argument is how dark it should be 1=same, 2=50% 2352 * 2353 * @return string 2354 * @param string $rgb 2355 * @param int $darker 2356 */ 2357function darken_color($rgb, $darker=2) 2358{ 2359 if (strpos($rgb, '#') !== FALSE) 2360 { 2361 $hash = '#'; 2362 $rgb = str_replace('#', '', $rgb); 2363 } else { 2364 $hash = ''; 2365 } 2366 $len = strlen($rgb); 2367 if ($len == 6) {} // Passed RGB 2368 else if ($len == 8) 2369 { 2370 // Passed RGBA, remove alpha channel 2371 $rgb = substr($rgb, 0, 6); 2372 } else { 2373 $rgb = FALSE; 2374 } 2375 2376 if ($rgb === FALSE) { return $hash.'000000'; } 2377 2378 $darker = ($darker > 1) ? $darker : 1; 2379 2380 list($R16, $G16, $B16) = str_split($rgb, 2); 2381 2382 $R = sprintf("%02X", floor(hexdec($R16) / $darker)); 2383 $G = sprintf("%02X", floor(hexdec($G16) / $darker)); 2384 $B = sprintf("%02X", floor(hexdec($B16) / $darker)); 2385 2386 return $hash.$R.$G.$B; 2387} 2388 2389// Originally from http://stackoverflow.com/questions/6054033/pretty-printing-json-with-php/21162086#21162086 2390// FIXME : This is only required for PHP < 5.4, remove this when our requirements are >= 5.4 2391if (!defined('JSON_UNESCAPED_SLASHES')) { define('JSON_UNESCAPED_SLASHES', 64); } 2392if (!defined('JSON_PRETTY_PRINT')) { define('JSON_PRETTY_PRINT', 128); } 2393if (!defined('JSON_UNESCAPED_UNICODE')) { define('JSON_UNESCAPED_UNICODE', 256); } 2394 2395function json_output($status, $message) 2396{ 2397 header("Content-type: application/json; charset=utf-8"); 2398 echo json_encode(array("status" => $status, "message" => $message)); 2399 2400 exit(); 2401} 2402 2403function _json_encode($data, $options = 448) 2404{ 2405 if (version_compare(PHP_VERSION, '5.4', '>=')) 2406 { 2407 return json_encode($data, $options); 2408 } else { 2409 return _json_format(json_encode($data), $options); 2410 } 2411} 2412 2413function _json_format($json, $options = 448) 2414{ 2415 $prettyPrint = (bool) ($options & JSON_PRETTY_PRINT); 2416 $unescapeUnicode = (bool) ($options & JSON_UNESCAPED_UNICODE); 2417 $unescapeSlashes = (bool) ($options & JSON_UNESCAPED_SLASHES); 2418 if (!$prettyPrint && !$unescapeUnicode && !$unescapeSlashes) 2419 { 2420 return $json; 2421 } 2422 $result = ''; 2423 $pos = 0; 2424 $strLen = strlen($json); 2425 $indentStr = ' '; 2426 $newLine = "\n"; 2427 $outOfQuotes = true; 2428 $buffer = ''; 2429 $noescape = true; 2430 for ($i = 0; $i < $strLen; $i++) 2431 { 2432 // Grab the next character in the string 2433 $char = substr($json, $i, 1); 2434 // Are we inside a quoted string? 2435 if ('"' === $char && $noescape) 2436 { 2437 $outOfQuotes = !$outOfQuotes; 2438 } 2439 if (!$outOfQuotes) 2440 { 2441 $buffer .= $char; 2442 $noescape = '\\' === $char ? !$noescape : true; 2443 continue; 2444 } 2445 elseif ('' !== $buffer) 2446 { 2447 if ($unescapeSlashes) 2448 { 2449 $buffer = str_replace('\\/', '/', $buffer); 2450 } 2451 if ($unescapeUnicode && function_exists('mb_convert_encoding')) 2452 { 2453 // http://stackoverflow.com/questions/2934563/how-to-decode-unicode-escape-sequences-like-u00ed-to-proper-utf-8-encoded-cha 2454 $buffer = preg_replace_callback('/\\\\u([0-9a-f]{4})/i', 2455 function ($match) 2456 { 2457 return mb_convert_encoding(pack('H*', $match[1]), 'UTF-8', 'UCS-2BE'); 2458 }, $buffer); 2459 } 2460 $result .= $buffer . $char; 2461 $buffer = ''; 2462 continue; 2463 } 2464 elseif(false !== strpos(" \t\r\n", $char)) 2465 { 2466 continue; 2467 } 2468 if (':' === $char) 2469 { 2470 // Add a space after the : character 2471 $char .= ' '; 2472 } 2473 elseif (('}' === $char || ']' === $char)) 2474 { 2475 $pos--; 2476 $prevChar = substr($json, $i - 1, 1); 2477 if ('{' !== $prevChar && '[' !== $prevChar) 2478 { 2479 // If this character is the end of an element, 2480 // output a new line and indent the next line 2481 $result .= $newLine; 2482 for ($j = 0; $j < $pos; $j++) 2483 { 2484 $result .= $indentStr; 2485 } 2486 } 2487 else 2488 { 2489 // Collapse empty {} and [] 2490 $result = rtrim($result) . "\n\n" . $indentStr; 2491 } 2492 } 2493 $result .= $char; 2494 // If the last character was the beginning of an element, 2495 // output a new line and indent the next line 2496 if (',' === $char || '{' === $char || '[' === $char) 2497 { 2498 $result .= $newLine; 2499 if ('{' === $char || '[' === $char) 2500 { 2501 $pos++; 2502 } 2503 for ($j = 0; $j < $pos; $j++) 2504 { 2505 $result .= $indentStr; 2506 } 2507 } 2508 } 2509 // If buffer not empty after formating we have an unclosed quote 2510 if (strlen($buffer) > 0) 2511 { 2512 //json is incorrectly formatted 2513 $result = false; 2514 } 2515 return $result; 2516} 2517 2518/** 2519 * Register an HTML resource 2520 * 2521 * Registers resource for use later (will be re-inserted via output buffer handler) 2522 * CSS and JS files default to the css/ and js/ directories respectively. 2523 * Scripts are inserted literally as passed in $name. 2524 * 2525 * @param string $type Type of resource (css/js/script) 2526 * @param string $content Filename or script content or array (for meta) 2527 */ 2528// TESTME needs unit testing 2529function register_html_resource($type, $content) 2530{ 2531 // If no path specified, default to subdirectory of resource type (for CSS and JS only) 2532 $type = strtolower($type); 2533 if (in_array($type, array('css', 'js')) && strpos($content, '/') === FALSE) 2534 { 2535 $content = $type . '/' . $content; 2536 } 2537 2538 // Insert into global variable, used in html callback function 2539 $GLOBALS['cache_html']['resources'][$type][] = $content; 2540} 2541 2542/** 2543 * Register an HTML title section 2544 * 2545 * Registers title section for use in the html <title> tag. 2546 * Calls can be stacked, and will be concatenated later by the HTML callback function. 2547 * 2548 * @param string $title Section title content 2549 */ 2550// TESTME needs unit testing 2551function register_html_title($title) 2552{ 2553 $GLOBALS['cache_html']['title'][] = $title; 2554} 2555 2556 2557/** 2558 * Register an HTML panel section 2559 * 2560 * Registers left panel section. 2561 * Calls can be stacked, and will be concatenated later by the HTML callback function. 2562 * 2563 * @param string $html Section panel content 2564 */ 2565// TESTME needs unit testing 2566function register_html_panel($html = '') 2567{ 2568 $GLOBALS['cache_html']['page_panel'] = $html; 2569} 2570 2571/** 2572 * Redirect to specified URL 2573 * 2574 * @param string $url Redirecting URL 2575 */ 2576function redirect_to_url($url) 2577{ 2578 if (!strlen($url) || $url == '#') { return; } // Empty url, do not redirect 2579 2580 $parse = parse_url($url); 2581 if (!isset($parse['scheme']) && !str_starts($url, '/')) 2582 { 2583 // When this is not full url or not started with / 2584 $url = '/' . $url; 2585 } 2586 2587 if (headers_sent()) 2588 { 2589 // HTML headers already sent, use JS than 2590 register_html_resource('script', "location.href='$url'"); 2591 } else { 2592 // Just use headers 2593 header('Location: '.$url); 2594 } 2595} 2596 2597function generate_colour_gradient($start_colour, $end_colour, $steps) { 2598 2599 if($steps < 4) { $steps = 4; } 2600 2601 $FromRGB['r'] = hexdec(substr($start_colour, 0, 2)); 2602 $FromRGB['g'] = hexdec(substr($start_colour, 2, 2)); 2603 $FromRGB['b'] = hexdec(substr($start_colour, 4, 2)); 2604 2605 $ToRGB['r'] = hexdec(substr($end_colour, 0, 2)); 2606 $ToRGB['g'] = hexdec(substr($end_colour, 2, 2)); 2607 $ToRGB['b'] = hexdec(substr($end_colour, 4, 2)); 2608 2609 $StepRGB['r'] = ($FromRGB['r'] - $ToRGB['r']) / ($steps - 1); 2610 $StepRGB['g'] = ($FromRGB['g'] - $ToRGB['g']) / ($steps - 1); 2611 $StepRGB['b'] = ($FromRGB['b'] - $ToRGB['b']) / ($steps - 1); 2612 2613 $GradientColors = array(); 2614 2615 for($i = 0; $i < $steps; $i++) { 2616 $RGB['r'] = floor($FromRGB['r'] - ($StepRGB['r'] * $i)); 2617 $RGB['g'] = floor($FromRGB['g'] - ($StepRGB['g'] * $i)); 2618 $RGB['b'] = floor($FromRGB['b'] - ($StepRGB['b'] * $i)); 2619 2620 $HexRGB['r'] = sprintf('%02x', ($RGB['r'])); 2621 $HexRGB['g'] = sprintf('%02x', ($RGB['g'])); 2622 $HexRGB['b'] = sprintf('%02x', ($RGB['b'])); 2623 2624 $GradientColors[] = implode(NULL, $HexRGB); 2625 } 2626 $GradientColors = array_filter($GradientColors, "c_len"); 2627 return $GradientColors; 2628} 2629 2630function c_len($val){ 2631 return (strlen($val) == 6 ? true : false ); 2632} 2633 2634function adjust_colour_brightness($hex, $steps) { 2635 // Steps should be between -255 and 255. Negative = darker, positive = lighter 2636 $steps = max(-255, min(255, $steps)); 2637 2638 // Normalize into a six character long hex string 2639 $hex = str_replace('#', '', $hex); 2640 if (strlen($hex) == 3) { 2641 $hex = str_repeat(substr($hex,0,1), 2).str_repeat(substr($hex,1,1), 2).str_repeat(substr($hex,2,1), 2); 2642 } 2643 2644 // Split into three parts: R, G and B 2645 $color_parts = str_split($hex, 2); 2646 2647 $return =''; 2648 foreach ($color_parts as $color) { 2649 $color = hexdec($color); // Convert to decimal 2650 $color = max(0,min(255,$color + $steps)); // Adjust color 2651 $return .= str_pad(dechex($color), 2, '0', STR_PAD_LEFT); // Make two char hex code 2652 } 2653 2654 return $return; 2655} 2656 2657// EOF 2658