"Fossies" - the Fresh Open Source Software Archive

Member "ganglia-web-3.7.2/functions.php" (8 Jun 2016, 42133 Bytes) of package /linux/www/ganglia-web-3.7.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) PHP source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "functions.php" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 3.7.1_vs_3.7.2.

    1 <?php
    2 
    3 #
    4 # Some common functions for the Ganglia PHP website.
    5 # Assumes the Gmeta XML tree has already been parsed,
    6 # and the global variables $metrics, $clusters, and $hosts
    7 # have been set.
    8 #
    9 
   10 include_once ( dirname(__FILE__) . "/lib/json.php" );
   11 
   12 #
   13 # Load event API driver.
   14 #
   15 $driver = ucfirst(strtolower( !isset($conf['overlay_events_provider']) ? "Json" : $conf['overlay_events_provider'] ));
   16 if (file_exists( dirname(__FILE__) . "/lib/Events/Driver_${driver}.php")) {
   17   include_once( dirname(__FILE__) . "/lib/Events/Driver_${driver}.php" );
   18 }
   19 
   20 #------------------------------------------------------------------------------
   21 # Allows a form of inheritance for template files.
   22 # If a file does not exist in the chosen template, the
   23 # default is used. Cuts down on code duplication.
   24 function template ($name)
   25 {
   26    global $conf;
   27 
   28    $fn = "./templates/${conf['template_name']}/$name";
   29    $default = "./templates/default/$name";
   30 
   31    if (file_exists($fn)) {
   32       return $fn;
   33    }
   34    else {
   35       return $default;
   36    }
   37 }
   38 
   39 #------------------------------------------------------------------------------
   40 # Creates a hidden input field in a form. Used to save CGI variables.
   41 function hiddenvar ($name, $var)
   42 {
   43 
   44    $hidden = "";
   45    if ($var) {
   46       #$url = rawurlencode($var);
   47       $hidden = "<input type=\"hidden\" name=\"$name\" value=\"$var\">\n";
   48    }
   49    return $hidden;
   50 }
   51 
   52 #------------------------------------------------------------------------------
   53 # Gives a readable time string, from a "number of seconds" integer.
   54 # Often used to compute uptime.
   55 function uptime($uptimeS)
   56 {
   57    $uptimeD=intval($uptimeS/86400);
   58    $uptimeS=$uptimeD ? $uptimeS % ($uptimeD*86400) : $uptimeS;
   59    $uptimeH=intval($uptimeS/3600);
   60    $uptimeS=$uptimeH ? $uptimeS % ($uptimeH*3600) : $uptimeS;
   61    $uptimeM=intval($uptimeS/60);
   62    $uptimeS=$uptimeM ? $uptimeS % ($uptimeM*60) : $uptimeS;
   63 
   64    $s = ($uptimeD!=1) ? "s" : "";
   65    return sprintf("$uptimeD day$s, %d:%02d:%02d",$uptimeH,$uptimeM,$uptimeS);
   66 }
   67 
   68 #------------------------------------------------------------------------------
   69 # Try to determine a nodes location in the cluster. Attempts to find the
   70 # LOCATION attribute first. Requires the host attribute array from 
   71 # $hosts[$cluster][$name], where $name is the hostname.
   72 # Returns [-1,-1,-1] if we could not determine location.
   73 #
   74 function findlocation($attrs)
   75 {
   76    $rack=$rank=$plane=-1;
   77 
   78    $loc=$attrs['LOCATION'];
   79    if ($loc) {
   80       sscanf($loc, "%d,%d,%d", $rack, $rank, $plane);
   81       #echo "Found LOCATION: $rack, $rank, $plane.<br>";
   82    }
   83    if ($rack<0 or $rank<0) {
   84       # Try to parse the host name. Assumes a compute-<rack>-<rank>
   85       # naming scheme.
   86       $n=sscanf($attrs['NAME'], "compute-%d-%d", $rack, $rank);
   87       $plane=0;
   88    }
   89    return array($rack,$rank,$plane);
   90 }
   91 
   92 
   93 #------------------------------------------------------------------------------
   94 function cluster_sum($name, $metrics)
   95 {
   96    $sum = 0;
   97 
   98    foreach ($metrics as $host => $val)
   99       {
  100          if(isset($val[$name]['VAL'])) $sum += $val[$name]['VAL'];
  101       }
  102 
  103    return $sum;
  104 }
  105 
  106 #------------------------------------------------------------------------------
  107 function cluster_min($name, $metrics)
  108 {
  109    $min = "";
  110 
  111    foreach ($metrics as $host => $val)
  112       {
  113          $v = $val[$name]['VAL'];
  114          if (!is_numeric($min) or $min < $v)
  115             {
  116                $min = $v;
  117                $minhost = $host;
  118             }
  119       }
  120    return array($min, $minhost);
  121 }
  122 
  123 #------------------------------------------------------------------------------
  124 #
  125 # A useful function for giving the correct picture for a given
  126 # load. Scope is "node | cluster | grid". Value is 0 <= v <= 1.
  127 function load_image ($scope, $value)
  128 {
  129    global $conf;
  130 
  131    $scaled_load = $value / $conf['load_scale'];
  132    if ($scaled_load>1.00) {
  133       $image = template("images/${scope}_overloaded.jpg");
  134    }
  135    else if ($scaled_load>=0.75) {
  136       $image = template("images/${scope}_75-100.jpg");
  137    }
  138    else if ($scaled_load >= 0.50) {
  139       $image = template("images/${scope}_50-74.jpg");
  140    }
  141    else if ($scaled_load>=0.25) {
  142       $image = template("images/${scope}_25-49.jpg");
  143    }
  144    else {
  145       $image = template("images/${scope}_0-24.jpg");
  146    }
  147 
  148    return $image;
  149 }
  150 
  151 #------------------------------------------------------------------------------
  152 # A similar function that specifies the background color for a graph
  153 # based on load. Quantizes the load figure into 6 sets.
  154 function load_color ($value)
  155 {
  156    global $conf;
  157 
  158    $scaled_load = $value / $conf['load_scale'];
  159    if ($scaled_load>1.00) {
  160       $color = $conf['load_colors']["100+"];
  161    }
  162    else if ($scaled_load>=0.75) {
  163       $color = $conf['load_colors']["75-100"];
  164    }
  165    else if ($scaled_load >= 0.50) {
  166       $color = $conf['load_colors']["50-75"];
  167    }
  168    else if ($scaled_load>=0.25) {
  169       $color = $conf['load_colors']["25-50"];
  170    }
  171    else if ($scaled_load < 0.0)
  172       $color = $conf['load_colors']["down"];
  173    else {
  174       $color = $conf['load_colors']["0-25"];
  175    }
  176 
  177    return $color;
  178 }
  179 
  180 #------------------------------------------------------------------------------
  181 #
  182 # Just a useful function to print the HTML for
  183 # the load/death of a cluster node
  184 function node_image ($metrics)
  185 {
  186    global $hosts_down;
  187 
  188    # More rigorous checking if variables are set before trying to use them.
  189    if ( isset($metrics['cpu_num']['VAL']) and $metrics['cpu_num']['VAL'] != 0 ) {
  190         $cpu_num = $metrics['cpu_num']['VAL'];
  191    } else {
  192         $cpu_num = 1;
  193    }
  194 
  195    if ( isset($metrics['load_one']['VAL']) ) {
  196         $load_one = $metrics['load_one']['VAL'];
  197    } else {
  198         $load_one = 0;
  199    }
  200 
  201    $value = $load_one / $cpu_num;
  202 
  203    # Check if the host is down
  204    # RFM - Added isset() check to eliminate error messages in ssl_error_log
  205    if (isset($hosts_down) and $hosts_down)
  206          $image = template("images/node_dead.jpg");
  207    else
  208          $image = load_image("node", $value);
  209 
  210    return $image;
  211 }
  212 
  213 #------------------------------------------------------------------------------
  214 #
  215 # Finds the min/max over a set of metric graphs. Nodes is
  216 # an array keyed by host names.
  217 #
  218 function find_limits($clustername, 
  219              $nodes, 
  220              $metricname, 
  221              $start, 
  222              $end, 
  223              $metrics,
  224              $conf,
  225              $rrd_options) {
  226   if (!count($metrics))
  227     return array(0, 0);
  228 
  229   $firsthost = key($metrics);
  230    
  231   if (array_key_exists($metricname, $metrics[$firsthost])) {
  232     if ($metrics[$firsthost][$metricname]['TYPE'] == "string"
  233         or $metrics[$firsthost][$metricname]['SLOPE'] == "zero")
  234       return array(0,0);
  235   } else {
  236     return array(0,0);
  237   }
  238 
  239   $max = 0;
  240   $min = 0;
  241   if ($conf['graph_engine'] == "graphite") {
  242     $target = $conf['graphite_prefix'] . 
  243       $clustername . ".[a-zA-Z0-9]*." . $metricname . ".sum";
  244     $raw_highestMax = file_get_contents($conf['graphite_url_base'] . "?target=highestMax(" . $target . ",1)&from=" . $start . "&until=" . $end . "&format=json");
  245     $highestMax = json_decode($raw_highestMax, TRUE);
  246     $highestMaxDatapoints = $highestMax[0]['datapoints'];
  247     $maxdatapoints = array();
  248     foreach ($highestMaxDatapoints as $datapoint) {
  249       array_push($maxdatapoints, $datapoint[0]);
  250     }
  251     $max = max($maxdatapoints);
  252   } else {
  253     foreach (array_keys($nodes) as $host) {
  254       $rrd_dir = "{$conf['rrds']}/$clustername/$host";
  255       $rrd_file = "$rrd_dir/$metricname.rrd";
  256       if (file_exists($rrd_file)) {
  257     if (extension_loaded('rrd')) {
  258       $values = rrd_fetch($rrd_file,
  259                   array("--start", $start,
  260                     "--end", $end,
  261                     "AVERAGE"));
  262 
  263       $values = (array_filter(array_values($values['data']['sum']),
  264                   'is_finite'));
  265       $thismax = max($values);
  266       $thismin = min($values);
  267     } else {
  268       $command = $conf['rrdtool'] . " graph /dev/null $rrd_options ".
  269         "--start '$start' --end '$end' ".
  270         "DEF:limits='$rrd_dir/$metricname.rrd':'sum':AVERAGE ".
  271         "PRINT:limits:MAX:%.2lf ".
  272         "PRINT:limits:MIN:%.2lf";
  273       $out = array();
  274       exec($command, $out);
  275       if (isset($out[1])) {
  276         $thismax = $out[1];
  277       } else {
  278         $thismax = NULL;
  279       }
  280       if (!is_numeric($thismax)) 
  281         continue;
  282       $thismin = $out[2];
  283       if (!is_numeric($thismin))
  284         continue;
  285     }
  286 
  287     if ($max < $thismax) 
  288       $max = $thismax;
  289 
  290     if ($min > $thismin)
  291       $min = $thismin;
  292     //echo "$host: $thismin - $thismax<br>\n";
  293       }
  294     }
  295   }
  296   return array($min, $max);
  297 }
  298 
  299 #------------------------------------------------------------------------------
  300 #
  301 # Finds the avg of the given cluster & metric from the summary rrds.
  302 #
  303 function find_avg($clustername, $hostname, $metricname)
  304 {
  305     global $conf, $start, $end, $rrd_options;
  306     $avg = 0;
  307 
  308     if ($hostname)
  309         $sum_dir = "${conf['rrds']}/$clustername/$hostname";
  310     else
  311         $sum_dir = "${conf['rrds']}/$clustername/__SummaryInfo__";
  312 
  313     $command = $conf['rrdtool'] . " graph /dev/null $rrd_options ".
  314         "--start $start --end $end ".
  315         "DEF:avg='$sum_dir/$metricname.rrd':'sum':AVERAGE ".
  316         "PRINT:avg:AVERAGE:%.2lf ";
  317     exec($command, $out);
  318     if ( isset($out[1]) ) 
  319       $avg = $out[1];
  320     else
  321       $avg = 0;
  322     #echo "$sum_dir: avg($metricname)=$avg<br>\n";
  323     return $avg;
  324 }
  325 
  326 #------------------------------------------------------------------------------
  327 # Alternate between even and odd row styles.
  328 function rowstyle()
  329 {
  330    static $style;
  331 
  332    if ($style == "even") { $style = "odd"; }
  333    else { $style = "even"; }
  334 
  335    return $style;
  336 }
  337 
  338 #------------------------------------------------------------------------------
  339 # Return a version of the string which is safe for display on a web page.
  340 # Potentially dangerous characters are converted to HTML entities.  
  341 # Resulting string is not URL-encoded.
  342 function clean_string( $string )
  343 {
  344   return htmlentities( $string );
  345 }
  346 #------------------------------------------------------------------------------
  347 function sanitize ( $string ) {
  348   return  escapeshellcmd( clean_string( rawurldecode( $string ) ) ) ;
  349 }
  350 
  351 #------------------------------------------------------------------------------
  352 # If arg is a valid number, return it.  Otherwise, return null.
  353 function clean_number( $value )
  354 {
  355   return is_numeric( $value ) ? $value : null;
  356 }
  357 
  358 #------------------------------------------------------------------------------
  359 # Return true if string is a 3 or 6 character hex color.Return false otherwise.
  360 function is_valid_hex_color( $string )
  361 {
  362   $return_value = false;
  363   if( strlen( $string ) == 6 || strlen( $string ) == 3 ) {
  364     if( preg_match( '/^[0-9a-fA-F]+$/', $string ) ) {
  365       $return_value = true;
  366     }
  367   }
  368   return $return_value;
  369     
  370 }
  371 
  372 #------------------------------------------------------------------------------
  373 # Allowed view name characters are alphanumeric plus space, dash and underscore
  374 function is_proper_view_name( $string )
  375 {
  376   if(preg_match("/[^a-zA-z0-9_\-\ ]/", $string)){
  377     return false;
  378   } else {
  379     return true;
  380   }
  381 }
  382 
  383 
  384 #------------------------------------------------------------------------------
  385 # Return a shortened version of a FQDN
  386 # if "hostname" is numeric only, assume it is an IP instead
  387 # 
  388 function strip_domainname( $hostname ) {
  389     $postition = strpos($hostname, '.');
  390     $name = substr( $hostname , 0, $postition );
  391     if ( FALSE === $postition || is_numeric($name) ) {
  392         return $hostname;
  393     } else {
  394         return $name;
  395     }
  396 }
  397 
  398 #------------------------------------------------------------------------------
  399 # Read a file containing key value pairs
  400 function file_to_hash($filename, $sep)
  401 {
  402   
  403   $lines = file($filename, FILE_IGNORE_NEW_LINES);
  404   
  405   foreach ($lines as $line) 
  406   {
  407     list($k, $v) = explode($sep, rtrim($line));
  408     $params[$k] = $v;
  409   }
  410 
  411   return $params;
  412 }
  413 
  414 #------------------------------------------------------------------------------
  415 # Read a file containing key value pairs
  416 # Multiple values permitted for each key
  417 function file_to_hash_multi($filename, $sep)
  418 {
  419  
  420   $lines = file($filename);
  421  
  422   foreach ($lines as $line)
  423   {
  424     list($k, $v) = explode($sep, rtrim($line));
  425     $params[$k][] = $v;
  426   }
  427 
  428   return $params;
  429 }
  430 
  431 #------------------------------------------------------------------------------
  432 # Obtain a list of distinct values from an array of arrays
  433 function hash_get_distinct_values($h)
  434 {
  435   $values = array();
  436   $values_done = array();
  437   foreach($h as $k => $v)
  438   {
  439     if($values_done[$v] != "x")
  440     {
  441       $values_done[$v] = "x";
  442       $values[] = $v;
  443     } 
  444   }
  445   return $values;
  446 }
  447 
  448 $filter_defs = array();
  449 
  450 #------------------------------------------------------------------------------
  451 # Scan $conf['filter_dir'] and populate $filter_defs
  452 function discover_filters()
  453 {
  454   global $conf, $filter_defs;
  455 
  456   # Check whether filtering is configured or not
  457   if(!isset($conf['filter_dir']))
  458     return;
  459 
  460   if(!is_dir($conf['filter_dir']))
  461   {
  462     error_log("discover_filters(): not a directory: ${conf['filter_dir']}");
  463     return;
  464   }
  465 
  466   if($dh = opendir($conf['filter_dir']))
  467   {
  468     while(($filter_conf_filename = readdir($dh)) !== false) {
  469       if(!is_dir($filter_conf_filename))
  470       {
  471         # Parse the file contents
  472         $full_filename = "${conf['filter_dir']}/$filter_conf_filename";
  473         $filter_params = file_to_hash($full_filename, '=');
  474         $filter_shortname = $filter_params["shortname"];
  475         $filter_type = $filter_params["type"];
  476         if($filter_type = "url")
  477         {
  478           $filter_data_url = $filter_params['url'];
  479           $filter_defs[$filter_shortname] = $filter_params;
  480           $filter_defs[$filter_shortname]["data"] = file_to_hash($filter_data_url, ',');
  481           $filter_defs[$filter_shortname]["choices"] = hash_get_distinct_values($filter_defs[$filter_shortname]["data"]);
  482         }
  483       }
  484     }
  485     closedir($dh);
  486   }
  487 }
  488 
  489 $filter_permit_list = NULL;
  490 
  491 #------------------------------------------------------------------------------
  492 # Initialise the filter permit list, if necessary
  493 function filter_init()
  494 {
  495    global $conf, $filter_permit_list, $filter_defs, $choose_filter;
  496 
  497    if(!is_null($filter_permit_list))
  498    {
  499       return;
  500    }
  501 
  502    if(!isset($conf['filter_dir']))
  503    {
  504       $filter_permit_list = FALSE;
  505       return;
  506    }
  507 
  508    $filter_permit_list = array();
  509    $filter_count = 0;
  510 
  511    foreach($choose_filter as $filter_shortname => $filter_choice)
  512    {
  513       if($filter_choice == "")
  514          continue; 
  515 
  516       $filter_params = $filter_defs[$filter_shortname];
  517       if($filter_count == 0)
  518       {
  519          foreach($filter_params["data"] as $key => $value)
  520          {
  521             if($value == $filter_choice)
  522                $filter_permit_list[$key] = $key;
  523          }
  524       }
  525       else
  526       {
  527          foreach($filter_permit_list as $key => $value)
  528          {
  529             $remove_key = TRUE;
  530             if(isset($filter_params["data"][$key]))
  531             {
  532                if($filter_params["data"][$key] == $filter_choice)
  533                {
  534                   $remove_key = FALSE;
  535                } 
  536             }
  537             if($remove_key)
  538             {
  539                unset($filter_permit_list[$key]);
  540             }
  541          }
  542       }
  543       $filter_count++;
  544    }
  545 
  546    if($filter_count == 0)
  547       $filter_permit_list = FALSE;
  548 
  549 }
  550 
  551 #------------------------------------------------------------------------------
  552 # Decide whether the given source is permitted by the filters, if any
  553 function filter_permit($source_name)
  554 {
  555    global $filter_permit_list;
  556 
  557    filter_init();
  558    
  559    # Handle the case where filtering is not active
  560    if(!is_array($filter_permit_list))
  561       return true;
  562 
  563    return isset($filter_permit_list[$source_name]);
  564 }
  565 
  566 $VIEW_NAME_SEP = '--';
  567 
  568 function viewName($view) {
  569   global $VIEW_NAME_SEP;
  570 
  571   $vn = '';
  572   if ($view['parent'] != NULL)
  573     $vn = str_replace('/', $VIEW_NAME_SEP, $view['parent']) . $VIEW_NAME_SEP;
  574   $vn .= $view['view_name'];
  575   return $vn;
  576 }
  577 
  578 class ViewList {
  579   private $available_views;
  580 
  581   public function __construct() {
  582     $this->available_views = get_available_views();
  583   }
  584 
  585   public function viewExists($view_name) {
  586     foreach ($this->available_views as $view) {
  587       if ($view['view_name'] == $view_name) {
  588     return TRUE;
  589       }
  590     }
  591     return FALSE;
  592   }
  593 
  594   public function getView($view_name) {
  595     foreach ($this->available_views as $view) {
  596       if (viewName($view) == $view_name) {
  597     return $view;
  598       }
  599     }
  600     return NULL;
  601   }
  602 
  603   public function removeView($view_name) {
  604     foreach ($this->available_views as $key => $view) {
  605       if (viewName($view) == $view_name) {
  606     unset($this->available_views[$key]);
  607     return;
  608       }
  609     }
  610   }
  611 
  612   public function getViews() {
  613     return $this->available_views;
  614   }
  615 }
  616 
  617 function getViewItems($view, $range, $cs, $ce) {
  618   $view_elements = get_view_graph_elements($view);
  619   $view_items = array();
  620   if (count($view_elements) != 0) {
  621     $graphargs = "";
  622     if ($cs)
  623       $graphargs .= "&amp;cs=" . rawurlencode($cs);
  624     if ($ce)
  625       $graphargs .= "&amp;ce=" . rawurlencode($ce);
  626     
  627     foreach ($view_elements as $element) {
  628       $canBeDecomposed = isset($element['aggregate_graph']) ||
  629     ((strpos($element['graph_args'], 'vn=') !== FALSE) &&
  630      (strpos($element['graph_args'], 'item_id=') !== FALSE));
  631       $view_items[] = 
  632     array("legend" => isset($element['hostname']) ? 
  633           $element['hostname'] : "Aggregate graph",
  634           "url_args" => htmlentities($element['graph_args']) . 
  635           "&amp;r=" . $range . $graphargs,
  636           "aggregate_graph" => isset($element['aggregate_graph']) ? 1 : 0,
  637           "canBeDecomposed" => $canBeDecomposed ? 1 : 0);
  638     }
  639   }
  640   return $view_items;
  641 }
  642 
  643 ///////////////////////////////////////////////////////////////////////////////
  644 // Get all the available views
  645 ///////////////////////////////////////////////////////////////////////////////
  646 function get_available_views() {
  647   global $conf;
  648   
  649   /* -----------------------------------------------------------------------
  650   Find available views by looking in the GANGLIA_DIR/conf directory
  651   anything that matches view_*.json. Read them all and build a available_views
  652   array
  653   ----------------------------------------------------------------------- */
  654   $available_views = array();
  655 
  656   if ($handle = opendir($conf['views_dir'])) {
  657     while (false !== ($file = readdir($handle))) {
  658       if (preg_match("/^view_(.*)\.json$/", $file, $out)) {
  659     $view_config_file = $conf['views_dir'] . "/" . $file;
  660     if (!is_file ($view_config_file)) {
  661       echo("Can't read view config file " . 
  662            $view_config_file . ". Please check permissions");
  663     }
  664 
  665     $view = json_decode(file_get_contents($view_config_file), TRUE);
  666     // Check whether view type has been specified ie. regex. 
  667     // If not it's standard view
  668     $view_type = 
  669       isset($view['view_type']) ? $view['view_type'] : "standard";
  670     $default_size = isset($view['default_size']) ? 
  671       $view['default_size'] : $conf['default_view_graph_size'];
  672     $view_parent = 
  673       isset($view['parent']) ? $view['parent'] : NULL;
  674     $common_y_axis = 
  675       isset($view['common_y_axis']) ? $view['common_y_axis'] : 0;
  676 
  677     $available_views[] = array ("file_name" => $view_config_file, 
  678                     "view_name" => $view['view_name'],
  679                     "default_size" => $default_size, 
  680                     "items" => $view['items'], 
  681                     "view_type" => $view_type,
  682                     "parent" => $view_parent,
  683                     "common_y_axis" => $common_y_axis);
  684     unset($view);
  685       }
  686     }
  687     closedir($handle);
  688   }
  689   
  690   foreach ($available_views as $key => $row) {
  691     $name[$key] = strtolower($row['view_name']);
  692   }
  693   
  694   @array_multisort($name, SORT_ASC, $available_views);
  695   
  696   return $available_views; 
  697 }
  698 
  699 ///////////////////////////////////////////////////////////////////////////////
  700 // Get image graph URLS
  701 // This function returns an array of graph URLs to be used when rendering the 
  702 // view. It returns only the base ie. cluster, host, metric information. 
  703 // It is up to the caller to add proper size information, time ranges etc.
  704 ///////////////////////////////////////////////////////////////////////////////
  705 function get_view_graph_elements($view) {
  706   global $conf, $index_array;
  707 
  708   retrieve_metrics_cache();
  709   
  710   $view_elements = array();
  711 
  712   // set the default size from the view or global config
  713   if ( isset($conf['default_view_graph_size']) ) {
  714     $default_size = $conf['default_view_graph_size'];
  715   }
  716 
  717   if ( isset($view['default_size']) ) {
  718     $default_size = $view['default_size'];
  719   }
  720 
  721 
  722   switch ( $view['view_type'] ) {
  723   case "standard":
  724     // Does view have any items/graphs defined
  725     if ( count($view['items']) == 0 ) {
  726       continue;
  727       // print "No graphs defined for this view. Please add some";
  728     } else {
  729       // Loop through graph items
  730       foreach ($view['items'] as $item_id => $item) {
  731     // Check if item is an aggregate graph
  732     if (isset($item['aggregate_graph'])) {
  733       foreach ( $item['host_regex'] as $reg_id => $regex_array ) {
  734         $graph_args_array[] = "hreg[]=" . urlencode($regex_array["regex"]);
  735       }
  736 
  737       if (isset($item['metric_regex'])) {
  738         foreach ( $item['metric_regex'] as $reg_id => $regex_array ) {
  739           $graph_args_array[] = 
  740         "mreg[]=" . urlencode($regex_array["regex"]);
  741               $mreg[] = $regex_array["regex"];
  742         }
  743       }
  744 
  745           if ( isset($item['size']) ) {
  746             $graph_args_array[] = "z=" . $item['size'];
  747           } else {
  748             $graph_args_array[] = "z=" . $default_size;
  749           }
  750 
  751           if ( isset($item['sortit']) ) {
  752             $graph_args_array[] = "sortit=" . $item['sortit'];
  753           }
  754       
  755       // If graph type is not specified default to line graph
  756       if (isset($item['graph_type']) && 
  757           in_array($item['graph_type'], array('line', 'stack')))
  758         $graph_args_array[] = "gtype=" . $item['graph_type'];
  759       else
  760         $graph_args_array[] = "gtype=line";
  761       
  762       if (isset($item['upper_limit']))
  763         $graph_args_array[] = "x=" . $item['upper_limit'];
  764       
  765       if (isset($item['lower_limit']))
  766         $graph_args_array[] = "n=" . $item['lower_limit'];
  767       
  768       if (isset($item['vertical_label']))
  769         $graph_args_array[] = "vl=" . urlencode($item['vertical_label']);
  770       
  771       if (isset($item['title']))
  772         $graph_args_array[] = "title=" . urlencode($item['title']);
  773 
  774       if (isset($item['metric']))
  775         $graph_args_array[] = "m=" . $item['metric'];
  776 
  777           if (isset($item['glegend']))
  778             $graph_args_array[] = "glegend=" . $item["glegend"];
  779 
  780       if (isset($item['cluster']))
  781         $graph_args_array[] = "c=" . urlencode($item['cluster']);
  782 
  783       if (isset($item['exclude_host_from_legend_label']))
  784         $graph_args_array[] = 
  785           "lgnd_xh=" . $item['exclude_host_from_legend_label'];
  786       
  787       $graph_args_array[] = "aggregate=1";
  788       $view_elements[] = 
  789         array("graph_args" => join("&", $graph_args_array), 
  790           "aggregate_graph" => 1,
  791           "name" => isset($item['title']) && $item['title'] != "" ? 
  792           $item['title'] : $mreg[0] . " Aggregate graph");
  793       
  794       unset($graph_args_array);
  795           
  796       // Check whether it's a composite graph/report. 
  797       // It needs to have an item id
  798     } else if ($item['item_id']) {
  799       $graph_args_array[] = "vn=" . $view['view_name'];
  800           $graph_args_array[] = "item_id=" . $item['item_id'];
  801 
  802       $view_elements[] = 
  803         array("graph_args" => join("&", $graph_args_array));
  804           unset($graph_args_array);
  805           
  806       // It's standard metric graph          
  807         } else {
  808       // Is it a metric or a graph(report)
  809       if (isset($item['metric'])) {
  810         $graph_args_array[] = "m=" . $item['metric'];
  811         $name = $item['metric'];
  812       } else {
  813         $graph_args_array[] = "g=" . urlencode($item['graph']);
  814         $name = $item['graph'];
  815       }
  816           if ( isset($item['size']) ) {
  817             $graph_args_array[] = "z=" . $item['size'];
  818           } else {
  819             $graph_args_array[] = "z=" . $default_size;
  820           }
  821 
  822       if (isset($item['hostname'])) {
  823             $hostname = $item['hostname'];
  824             $cluster = array_key_exists($hostname, $index_array['cluster']) ?
  825           $index_array['cluster'][$hostname][0] : NULL;
  826         $graph_args_array[] = "h=" . urlencode($hostname);
  827           } else if (isset($item['cluster'])) {
  828         $hostname = "";
  829             $cluster = $item['cluster'];
  830       } else {
  831             $hostname = "";
  832             $cluster = "";
  833       }
  834       $graph_args_array[] = "c=" . urlencode($cluster);
  835 
  836       if (isset($item['upper_limit']))
  837         $graph_args_array[] = "x=" . $item['upper_limit'];
  838       
  839       if (isset($item['lower_limit']))
  840         $graph_args_array[] = "n=" . $item['lower_limit'];
  841       
  842       if (isset($item['vertical_label']))
  843         $graph_args_array[] = "vl=" . urlencode($item['vertical_label']);
  844       
  845       if (isset($item['title']))
  846         $graph_args_array[] = "title=" . urlencode($item['title']);
  847       
  848           if (isset($item['warning'])) {
  849             $view_e['warning'] = $item['warning'];
  850             $graph_args_array[] = "warn=" . $item['warning'];
  851           }
  852           if (isset($item['critical'])) {
  853             $view_e['critical'] = $item['critical'];
  854             $graph_args_array[] = "crit=" . $item['critical'];
  855           }
  856 
  857           if (isset($item['alias'])) {
  858         $view_e['alias'] = $item['alias'];
  859           }
  860 
  861           $view_e["graph_args"] = join("&", $graph_args_array);
  862           $view_e['hostname'] = $hostname;
  863           $view_e['cluster'] = $cluster;
  864           $view_e['name'] = $name;
  865       
  866       $view_elements[] = $view_e;
  867       
  868           unset($view_e);
  869       unset($graph_args_array);
  870     }
  871       } // end of foreach ( $view['items']
  872     } // end of if ( count($view['items'])
  873     break;
  874 
  875     ///////////////////////////////////////////////////////////////////////////
  876     // Currently only supports matching hosts.
  877     ///////////////////////////////////////////////////////////////////////////
  878   case "regex":
  879     foreach ($view['items'] as $item_id => $item) {
  880       // Is it a metric or a graph(report)
  881       if ( isset($item['metric']) ) {
  882     $metric_suffix = "m=" . $item['metric'];
  883     $name = $item['metric'];
  884       } else {
  885     $metric_suffix = "g=" . $item['graph'];
  886     $name = $item['graph'];
  887       }
  888       
  889       // Find hosts matching a criteria
  890       $query = $item['hostname'];
  891       foreach ( $index_array['hosts'] as $key => $host_name ) {
  892     if (preg_match("/$query/", $host_name)) {
  893       $clusters = $index_array['cluster'][$host_name];
  894       foreach ($clusters AS $cluster) {
  895         $graph_args_array[] = "h=" . urlencode($host_name);
  896         $graph_args_array[] = "c=" . urlencode($cluster);
  897 
  898         $view_elements[] = 
  899           array("graph_args" => $metric_suffix . "&" . join("&", $graph_args_array), 
  900             "hostname" => $host_name,
  901             "cluster" => $cluster,
  902             "name" => $name);
  903         
  904         unset($graph_args_array);
  905       }
  906     }
  907       }
  908     } // end of foreach ( $view['items'] as $item_id => $item )
  909     break;;
  910   } // end of switch ( $view['view_type'] ) {
  911   return ($view_elements);
  912 }
  913 
  914 function legendEntry($vname, $legend_items) {
  915   $legend = "";
  916   if (in_array("now", $legend_items))
  917     $legend .= "VDEF:{$vname}_last={$vname},LAST ";
  918 
  919   if (in_array("min", $legend_items))
  920     $legend .= "VDEF:{$vname}_min={$vname},MINIMUM ";
  921 
  922   if (in_array("avg", $legend_items))
  923     $legend .= "VDEF:{$vname}_avg={$vname},AVERAGE ";
  924 
  925   if (in_array("max", $legend_items))
  926     $legend .= "VDEF:{$vname}_max={$vname},MAXIMUM ";
  927 
  928   $terminate = FALSE;
  929   if (in_array("now", $legend_items)) {
  930     $legend .= "GPRINT:'{$vname}_last':'Now\:%5.1lf%s";
  931     $terminate = TRUE;
  932   }
  933 
  934   if (in_array("min", $legend_items)) {
  935     if ($terminate)
  936       $legend .= "' ";
  937     $legend .= "GPRINT:'{$vname}_min':'Min\:%5.1lf%s";
  938     $terminate = TRUE;
  939   }
  940 
  941   if (in_array("avg", $legend_items)) {
  942     if ($terminate)
  943       $legend .= "' ";
  944     $legend .= "GPRINT:'{$vname}_avg':'Avg\:%5.1lf%s";
  945     $terminate = TRUE;
  946   }
  947 
  948   if (in_array("max", $legend_items)) {
  949     if ($terminate)
  950       $legend .= "' ";
  951     $legend .= "GPRINT:'{$vname}_max':'Max\:%5.1lf%s";
  952     $terminate = TRUE;
  953   }
  954   
  955   if ($terminate)
  956     $legend .= "\\l' ";
  957 
  958   return $legend;
  959 }
  960 
  961 /**
  962  * Check if current user has a privilege (view, edit, etc) on a resource.
  963  * If resource is unspecified, we assume GangliaAcl::ALL.
  964  *
  965  * Examples
  966  *   checkAccess( GangliaAcl::ALL_CLUSTERS, GangliaAcl::EDIT, $conf ); // user has global edit?
  967  *   checkAccess( GangliaAcl::ALL_CLUSTERS, GangliaAcl::VIEW, $conf ); // user has global view?
  968  *   checkAccess( $cluster, GangliaAcl::EDIT, $conf ); // user can edit current cluster?
  969  *   checkAccess( 'cluster1', GangliaAcl::EDIT, $conf ); // user has edit privilege on cluster1?
  970  *   checkAccess( 'cluster1', GangliaAcl::VIEW, $conf ); // user has view privilege on cluster1?
  971  */
  972 function checkAccess($resource, $privilege, $conf) {
  973   
  974   if(!is_array($conf)) {
  975     trigger_error('checkAccess: $conf is not an array.', E_USER_ERROR);
  976   }
  977   if(!isSet($conf['auth_system'])) {
  978     trigger_error("checkAccess: \$conf['auth_system'] is not defined.", E_USER_ERROR);
  979   }
  980   
  981   switch( $conf['auth_system'] ) {
  982     case 'readonly':
  983       $out = ($privilege == GangliaAcl::VIEW);
  984       break;
  985       
  986     case 'enabled':
  987       // TODO: 'edit' needs to check for writeability of data directory.  error log if edit is allowed but we're unable to due to fs problems.
  988       
  989       $acl = GangliaAcl::getInstance();
  990       $auth = GangliaAuth::getInstance();
  991       
  992       if(!$auth->isAuthenticated()) {
  993         $user = GangliaAcl::GUEST;
  994       } else {
  995         $user = $auth->getUser();
  996       }
  997       
  998       if(!$acl->has($resource)) {
  999         $resource = GangliaAcl::ALL_CLUSTERS;
 1000       }
 1001       
 1002       $out = false;
 1003       if($acl->hasRole($user)) {
 1004         $out = (bool) $acl->isAllowed($user, $resource, $privilege);
 1005       }
 1006       // error_log("checkAccess() user=$user, resource=$resource, priv=$privilege == $out");
 1007       break;
 1008     
 1009     case 'disabled':
 1010       $out = true;
 1011       break;
 1012     
 1013     default:
 1014       trigger_error( "Invalid value '".$conf['auth_system']."' for \$conf['auth_system'].", E_USER_ERROR );
 1015       return false;
 1016   }
 1017   
 1018   return $out;
 1019 }
 1020 
 1021 function viewId($view_name) {
 1022   $id = 'v_' . preg_replace('/[^a-zA-Z0-9_]/', '_', $view_name);
 1023   return $id;
 1024 }
 1025 
 1026 ///////////////////////////////////////////////////////////////////////////////
 1027 // Taken from
 1028 // http://au2.php.net/manual/en/function.json-encode.php#80339
 1029 // Pretty print JSON 
 1030 ///////////////////////////////////////////////////////////////////////////////
 1031 function json_prettyprint($json) 
 1032 { 
 1033     $tab = "  "; 
 1034     $new_json = ""; 
 1035     $indent_level = 0; 
 1036     $in_string = false; 
 1037 
 1038     $len = strlen($json); 
 1039 
 1040     for($c = 0; $c < $len; $c++) 
 1041     { 
 1042         $char = $json[$c]; 
 1043         switch($char) 
 1044         { 
 1045             case '{': 
 1046             case '[': 
 1047                 if(!$in_string) 
 1048                 { 
 1049                     $new_json .= $char . "\n" . str_repeat($tab, $indent_level+1); 
 1050                     $indent_level++; 
 1051                 } 
 1052                 else 
 1053                 { 
 1054                     $new_json .= $char; 
 1055                 } 
 1056                 break; 
 1057             case '}': 
 1058             case ']': 
 1059                 if(!$in_string) 
 1060                 { 
 1061                     $indent_level--; 
 1062                     $new_json .= "\n" . str_repeat($tab, $indent_level) . $char; 
 1063                 } 
 1064                 else 
 1065                 { 
 1066                     $new_json .= $char; 
 1067                 } 
 1068                 break; 
 1069             case ',': 
 1070                 if(!$in_string) 
 1071                 { 
 1072                     $new_json .= ",\n" . str_repeat($tab, $indent_level); 
 1073                 } 
 1074                 else 
 1075                 { 
 1076                     $new_json .= $char; 
 1077                 } 
 1078                 break; 
 1079             case ':': 
 1080                 if(!$in_string) 
 1081                 { 
 1082                     $new_json .= ": "; 
 1083                 } 
 1084                 else 
 1085                 { 
 1086                     $new_json .= $char; 
 1087                 } 
 1088                 break; 
 1089             case '"': 
 1090                 if($c > 0 && $json[$c-1] != '\\') 
 1091                 { 
 1092                     $in_string = !$in_string; 
 1093                 } 
 1094             default: 
 1095                 $new_json .= $char; 
 1096                 break;                    
 1097         } 
 1098     } 
 1099 
 1100     return $new_json; 
 1101 } 
 1102 
 1103 function ganglia_cache_metrics() {
 1104     global $conf, $index_array, $hosts, $grid, $clusters, $debug, $metrics;
 1105 
 1106     require dirname(__FILE__) . '/lib/cache.php';
 1107 } // end function ganglia_cache_metrics
 1108 
 1109 
 1110 //////////////////////////////////////////////////////////////////////////////
 1111 //
 1112 //////////////////////////////////////////////////////////////////////////////
 1113 function build_aggregate_graph_config ($graph_type, 
 1114                                        $line_width, 
 1115                                        $hreg,
 1116                                        $mreg,
 1117                                        $glegend,
 1118                                        $exclude_host_from_legend_label,
 1119                                        $sortit = true) {
 1120 
 1121   global $conf, $index_array, $hosts, $grid, $clusters, $debug, $metrics;
 1122   
 1123   retrieve_metrics_cache();
 1124   
 1125   $color_count = count($conf['graph_colors']);
 1126 
 1127   $graph_config["report_name"]=isset($mreg)  ?  sanitize(implode($mreg))   : NULL;
 1128   $graph_config["title"]=isset($mreg)  ?  sanitize(implode($mreg))   : NULL;
 1129   $graph_config["glegend"]=isset($glegend) ? sanitize($glegend) : "show";
 1130 
 1131   $counter = 0;
 1132 
 1133   ///////////////////////////////////////////////////////////////////////////
 1134   // Find matching hosts    
 1135   foreach ( $hreg as $key => $query ) {
 1136     foreach ( $index_array['hosts'] as $key => $host_name ) {
 1137       if ( preg_match("/$query/i", $host_name ) ) {
 1138         // We can have same hostname in multiple clusters
 1139         foreach ($index_array['cluster'][$host_name] AS $cluster) {
 1140             $host_matches[] = $host_name . "|" . $cluster;
 1141         }
 1142       }
 1143     }
 1144   } 
 1145 
 1146   sort($host_matches);
 1147 
 1148   if( isset($mreg)) {
 1149     // Find matching metrics
 1150     foreach ( $mreg as $key => $query ) {
 1151       foreach ( $index_array['metrics'] as $metric_key => $m_name ) {
 1152         if ( preg_match("/$query/i", $metric_key, $metric_subexpr ) ) {
 1153           if (isset($metric_subexpr) && count($metric_subexpr) > 1) {
 1154             $legend = array();
 1155             for ($i = 1; $i < count($metric_subexpr); $i++) {
 1156               $legend[] = $metric_subexpr[$i];
 1157             }
 1158         $metric_matches[$metric_key] = implode(' ', $legend);
 1159           } else {
 1160             $metric_matches[$metric_key] = $metric_key;
 1161           }
 1162         }
 1163       }
 1164     }
 1165     if($sortit) {
 1166       ksort($metric_matches);
 1167     }
 1168   }
 1169   if( isset($metric_matches)){
 1170     $metric_matches_unique = array_unique($metric_matches);
 1171   }
 1172   else{
 1173     $metric_matches_unique = array($metric_name => $metric_name);
 1174   }
 1175 
 1176   if ( isset($host_matches)) {
 1177 
 1178     $host_matches_unique = array_unique($host_matches);
 1179 
 1180     // Create graph_config series from matched hosts and metrics
 1181     foreach ( $host_matches_unique as $key => $host_cluster ) {
 1182 
 1183       $out = explode("|", $host_cluster);
 1184 
 1185       $host_name = $out[0];
 1186       $cluster_name = $out[1];
 1187 
 1188       foreach ( $metric_matches_unique as $m_name => $legend ) {
 1189 
 1190         // We need to cycle the available colors
 1191         $color_index = $counter % $color_count;
 1192 
 1193         // next loop if there is no metric for this hostname
 1194         if( !in_array($host_name, $index_array['metrics'][$m_name]))
 1195           continue;
 1196 
 1197         $label = '';
 1198         if ($exclude_host_from_legend_label) {
 1199       $label = $legend;
 1200         } else {
 1201           if ($conf['strip_domainname'] == True )
 1202             $label = strip_domainname($host_name);
 1203           else
 1204             $label = $host_name;
 1205 
 1206       if (isset($metric_matches) and count($metric_matches_unique) > 1)
 1207             $label .= " $legend";
 1208     }
 1209 
 1210         $graph_config['series'][] = array ( "hostname" => $host_name , "clustername" => $cluster_name,
 1211           "metric" => $m_name,  "color" => $conf['graph_colors'][$color_index], "label" => $label, "line_width" => $line_width, "type" => $graph_type);
 1212 
 1213         $counter++;
 1214 
 1215       }
 1216       }
 1217    }
 1218 
 1219    return $graph_config;
 1220 
 1221 } // function build_aggregate_graph_config () {
 1222 
 1223 
 1224 //////////////////////////////////////////////////////////////////////////////
 1225 //
 1226 //////////////////////////////////////////////////////////////////////////////
 1227 function retrieve_metrics_cache ( $index = "all" ) {
 1228 
 1229    global $conf, $index_array, $hosts, $grid, $clusters, $debug, $metrics, $context;
 1230 
 1231    require dirname(__FILE__) . '/lib/cache.php';
 1232    return;
 1233 } // end of function get_metrics_cache () {
 1234 
 1235 function getHostOverViewData($hostname, 
 1236                              $metrics, 
 1237                              $cluster,
 1238                              $hosts_up, 
 1239                              $hosts_down, 
 1240                              $always_timestamp, 
 1241                              $always_constant, 
 1242                              $data) {
 1243   $data->assign("extra", template("host_extra.tpl"));
 1244 
 1245   $data->assign("host", $hostname);
 1246   $data->assign("node_image", node_image($metrics));
 1247 
 1248   if ($hosts_up)
 1249     $data->assign("node_msg", "This host is up and running."); 
 1250   else
 1251     $data->assign("node_msg", "This host is down."); 
 1252 
 1253   # No reason to go on if this node is down.
 1254   if ($hosts_down)
 1255     return;
 1256 
 1257   foreach ($metrics as $name => $v) {
 1258     if ($v['TYPE'] == "string" or $v['TYPE']=="timestamp" or
 1259         (isset($always_timestamp[$name]) and $always_timestamp[$name])) {
 1260       $s_metrics[$name] = $v;
 1261     } elseif ($v['SLOPE'] == "zero" or
 1262               (isset($always_constant[$name]) and $always_constant[$name])) {
 1263       $c_metrics[$name] = $v;
 1264     }
 1265   }
 1266 
 1267   # in case this is not defined, set to LOCALTIME so uptime will be 0 in the display
 1268   $boottime = null;
 1269   if (isset($metrics['boottime']['VAL']))
 1270     $boottime = $metrics['boottime']['VAL'];
 1271   else
 1272     $boottime = $cluster['LOCALTIME'];
 1273 
 1274   # Add the uptime metric for this host. Cannot be done in ganglia.php,
 1275   # since it requires a fully-parsed XML tree. The classic contructor problem.
 1276   $s_metrics['uptime']['TYPE'] = "string";
 1277   $s_metrics['uptime']['VAL'] = uptime($cluster['LOCALTIME'] - $boottime);
 1278   $s_metrics['uptime']['TITLE'] = "Uptime";
 1279 
 1280   # Add the gmond started timestamps & last reported time (in uptime format) from
 1281   # the HOST tag:
 1282   $s_metrics['gmond_started']['TYPE'] = "timestamp";
 1283   $s_metrics['gmond_started']['VAL'] = $hosts_up['GMOND_STARTED'];
 1284   $s_metrics['gmond_started']['TITLE'] = "Gmond Started";
 1285   $s_metrics['last_reported']['TYPE'] = "string";
 1286   $s_metrics['last_reported']['VAL'] = uptime($cluster['LOCALTIME'] - $hosts_up['REPORTED']);
 1287   $s_metrics['last_reported']['TITLE'] = "Last Reported";
 1288 
 1289   $s_metrics['ip_address']['TITLE'] = "IP Address";
 1290   $s_metrics['ip_address']['VAL'] = $hosts_up['IP'];
 1291   $s_metrics['ip_address']['TYPE'] = "string";
 1292   $s_metrics['location']['TITLE'] = "Location";
 1293   $s_metrics['location']['VAL'] = $hosts_up['LOCATION'];
 1294   $s_metrics['location']['TYPE'] = "string";
 1295 
 1296   # String metrics
 1297   if (is_array($s_metrics)) {
 1298     $s_metrics_data = array();
 1299     ksort($s_metrics);
 1300     foreach ($s_metrics as $name => $v) {
 1301       # RFM - If units aren't defined for metric, make it be the empty string
 1302       ! array_key_exists('UNITS', $v) and $v['UNITS'] = "";
 1303       if (isset($v['TITLE'])) {
 1304         $s_metrics_data[$name]["name"] = $v['TITLE'];
 1305       } else {
 1306         $s_metrics_data[$name]["name"] = $name;
 1307       }
 1308       if ($v['TYPE']=="timestamp" or 
 1309           (isset($always_timestamp[$name]) and $always_timestamp[$name])) {
 1310         $s_metrics_data[$name]["value"] = date("r", $v['VAL']);
 1311       } else {
 1312         $s_metrics_data[$name]["value"] = $v['VAL'] . " " . $v['UNITS'];
 1313       }
 1314     }
 1315   }
 1316   $data->assign("s_metrics_data", $s_metrics_data);
 1317 
 1318   # Constant metrics.
 1319   $c_metrics_data = null;
 1320   if (isset($c_metrics) and is_array($c_metrics)) {
 1321     $c_metrics_data = array();
 1322     ksort($c_metrics);
 1323     foreach ($c_metrics as $name => $v) {
 1324       if (isset($v['TITLE']))  {
 1325         $c_metrics_data[$name]["name"] =  $v['TITLE'];
 1326       } else {
 1327         $c_metrics_data[$name]["name"] = $name;
 1328       }
 1329       $c_metrics_data[$name]["value"] = "$v[VAL] $v[UNITS]";
 1330     }
 1331   }
 1332   $data->assign("c_metrics_data", $c_metrics_data);
 1333 }
 1334 
 1335 function buildMetricMaps($metrics,
 1336              $always_timestamp,
 1337              $always_constant,
 1338              $baseGraphArgs) {
 1339   $metricMap = NULL;
 1340   $metricGroupMap = NULL;
 1341   foreach ($metrics as $name => $metric) {
 1342     if ($metric['TYPE'] == "string" or 
 1343     $metric['TYPE'] == "timestamp" or
 1344     (isset($always_timestamp[$name]) and $always_timestamp[$name])) {
 1345     } elseif ($metric['SLOPE'] == "zero" or
 1346           (isset($always_constant[$name]) and $always_constant[$name])) {
 1347     } else {
 1348       $graphArgs = $baseGraphArgs . "&amp;v=$metric[VAL]&amp;m=$name";
 1349       # Adding units to graph 2003 by Jason Smith <smithj4@bnl.gov>.
 1350       if ($metric['UNITS']) {
 1351     $encodeUnits = rawurlencode($metric['UNITS']);
 1352     $graphArgs .= "&amp;vl=$encodeUnits";
 1353       }
 1354       if (isset($metric['TITLE'])) {
 1355     $title = $metric['TITLE'];
 1356     $encodeTitle = rawurlencode($title);
 1357     $graphArgs .= "&amp;ti=$encodeTitle";
 1358       }
 1359       // dump_var($graphArgs, "graphArgs");
 1360 
 1361       $metricMap[$name]['graph'] = $graphArgs;
 1362       $metricMap[$name]['description'] = 
 1363     isset($metric['DESC']) ? $metric['DESC'] : '';
 1364       $metricMap[$name]['title'] = 
 1365     isset($metric['TITLE']) ? $metric['TITLE'] : '';
 1366 
 1367       # Setup an array of groups that can be used for sorting in group view
 1368       if ( isset($metrics[$name]['GROUP']) ) {
 1369     $groups = $metrics[$name]['GROUP'];
 1370       } else {
 1371     $groups = array("");
 1372       }
 1373 
 1374       foreach ($groups as $group) {
 1375     if (isset($metricGroupMap[$group])) {
 1376       $metricGroupMap[$group] = 
 1377         array_merge($metricGroupMap[$group], (array)$name);
 1378     } else {
 1379       $metricGroupMap[$group] = array($name);
 1380     }
 1381       }
 1382     } // if
 1383   } // foreach
 1384   return array($metricMap, $metricGroupMap);
 1385 }
 1386 
 1387 // keep url decoding until it looks good
 1388 function heuristic_urldecode($blob) {
 1389   while (substr($blob,0,1) == "%") {
 1390     $blob = rawurldecode($blob);
 1391   }
 1392   return $blob;
 1393 }
 1394 
 1395 // alternative passthru() implementation to avoid incomplete images shown in
 1396 // browsers.
 1397 function my_passthru($command) {
 1398   $tf = tempnam('/tmp', 'ganglia-graph.');
 1399   $ret = exec("$command > $tf");
 1400   $size = filesize($tf);
 1401   header("Content-Length: $size");
 1402   $fp = fopen($tf, 'rb');
 1403   fpassthru($fp);
 1404   fclose($fp);
 1405   unlink($tf);
 1406 }
 1407 
 1408 ?>