config = new Config_Model(); $this->config->read_config(); // print Kohana::debug($this->config->views); } //end __construct() private function rrdtool_execute() { $descriptorspec = [ 0 => [ 'pipe', 'r', ], // stdin is a pipe that the child will read from 1 => [ 'pipe', 'w', ], // stdout is a pipe that the child will write to 2 => [ 'pipe', 'w', ], // stderr is a pipe that the child will write to ]; if (!isset($this->config->conf['rrdtool'])) { return false; } if (!is_executable($this->config->conf['rrdtool'])) { $data = 'ERROR: ' . $this->config->conf['rrdtool'] . " is not executable by PHP\n\n"; return $data; } $rrdtool = $this->config->conf['rrdtool'] . ' - '; /* this is needed by Fontconfig, used by pango, used by rrdtool graph ** it's automatically set up for 'interactive' sessions, but web servers ** don't have it (usually?). If there are 'red screens' instead of graphs, ** there's a good chance this is why */ $fc_cache = $this->config->conf['fontconfig_cache']; putenv('XDG_CACHE_HOME=' . $fc_cache); $xdg_cache = getenv('XDG_CACHE_HOME'); if (!$xdg_cache) { $data = 'ERROR: environment var XDG_CACHE_HOME not defined (should be writable cache dir)'; return $data; } if (!is_dir($xdg_cache) || !is_writeable($xdg_cache)) { $data = 'ERROR: env XDG_CACHE_HOME (' . $xdg_cache . ') is not writable directory'; return $data; } $command = $this->RRD_CMD; $process = proc_open($rrdtool, $descriptorspec, $pipes); $debug = []; $data = ''; if (is_resource($process)) { fwrite($pipes[0], $command); fclose($pipes[0]); stream_set_timeout($pipes[1], 1); $data = stream_get_contents($pipes[1]); stream_set_timeout($pipes[2], 1); $stderr = stream_get_contents($pipes[2]); $stdout_meta = stream_get_meta_data($pipes[1]); if ($stdout_meta['timed_out'] == 1) { $data = "ERROR: Timeout while reading rrdtool data.\n\n"; } fclose($pipes[1]); fclose($pipes[2]); proc_close($process); // Catch STDERR if ($stderr && strlen($stderr) >= 0) { $data = 'ERROR: STDERR => ' . $stderr . "\n\n"; return $data; } // Catch STDOUT < 50 Characters if ($data && strlen($data) < 50) { $data = 'ERROR: STDOUT => ' . $data . "\n\n"; return $data; } } else { $data = 'ERROR: proc_open(' . $rrdtool . ' ... failed'; } //end if return $data; } //end rrdtool_execute() public function doImage($RRD_CMD, $out = 'STDOUT') { $conf = $this->config->conf; // construct $command to rrdtool if (isset($conf['RRD_DAEMON_OPTS']) && $conf['RRD_DAEMON_OPTS'] != '') { $command = ' graph --daemon=' . $conf['RRD_DAEMON_OPTS'] . ' - '; } else { $command = ' graph - '; } $width = 0; $height = 0; if ($out == 'PDF') { if ($conf['pdf_graph_opt']) { $command .= $conf['pdf_graph_opt']; } if (isset($conf['pdf_width']) && is_numeric($conf['pdf_width'])) { $width = abs($conf['pdf_width']); } if (isset($conf['pdf_height']) && is_numeric($conf['pdf_height'])) { $height = abs($conf['pdf_height']); } } else { if ($conf['graph_opt']) { $command .= $conf['graph_opt']; } if (is_numeric($conf['graph_width'])) { $width = abs($conf['graph_width']); } if (is_numeric($conf['graph_height'])) { $height = abs($conf['graph_height']); } } //end if if ($width > 0) { $command .= " --width=$width"; } if ($height > 0) { $command .= " --height=$height"; } if ($height < 81 || (isset($conf['graph_only']) && $conf['graph_only'])) { $command .= ' --only-graph'; } elseif (isset($conf['no_legend']) && $conf['no_legend']) { $command .= ' --no-legend'; } $command .= $RRD_CMD; // Force empty vertical label if (! preg_match_all('/(-l|--vertical-label)/i', $command, $match)) { $command .= " --vertical-label=' ' "; } $this->RRD_CMD = $command; $data = $this->rrdtool_execute(); if ($data) { return $data; } else { return false; } } //end doImage() public function doXport($RRD_CMD) { $conf = $this->config->conf; if (isset($conf['RRD_DAEMON_OPTS']) && $conf['RRD_DAEMON_OPTS'] != '') { $command = ' xport --daemon=' . $conf['RRD_DAEMON_OPTS']; } else { $command = ' xport '; } $command .= $RRD_CMD; $this->RRD_CMD = $command; $data = $this->rrdtool_execute(); $data = preg_replace('/OK.*/', '', $data); if ($data) { return $data; } else { return false; } } //end doXport() public function streamImage($data = false) { if ($data === false) { header('Content-type: image/png'); echo base64_decode( 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A /wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9kCCAoDKSKZ0rEAAAAZdEVYdENv bW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAADUlEQVQI12NgYGBgAAAABQABXvMqOgAAAABJ RU5ErkJggg==' ); return; } if (preg_match('/^ERROR/', $data)) { if (preg_match('/NOT_AUTHORIZED/', $data)) { // TODO: i18n $data .= "\n\nYou are not authorized to view this Image"; // Set font size $font_size = 3; } else { $data .= $this->format_rrd_debug($this->config->conf['rrdtool'] . $this->RRD_CMD); // Set font size $font_size = 2; } $ts = explode("\n", $data); $width = 0; foreach ($ts as $k => $string) { $width = max($width, strlen($string)); } $width = imagefontwidth($font_size) * $width; if ($width <= ($this->config->conf['graph_width'] + 100)) { $width = ($this->config->conf['graph_width'] + 100); } $height = imagefontheight($font_size) * count($ts); if ($height <= ($this->config->conf['graph_height'] + 60)) { $height = ($this->config->conf['graph_height'] + 60); } $el = imagefontheight($font_size); $em = imagefontwidth($font_size); // Create the image pallette $img = imagecreatetruecolor($width, $height); // Dark red background $bg = imagecolorallocate($img, 0xAA, 0x00, 0x00); imagefilledrectangle($img, 0, 0, $width, $height, $bg); // White font color $color = imagecolorallocate($img, 255, 255, 255); foreach ($ts as $k => $string) { // Length of the string $len = strlen($string); // Y-coordinate of character, X changes, Y is static $ypos_offset = 5; $xpos_offset = 5; // Loop through the string for ($i = 0; $i < $len; $i++) { // Position of the character horizontally $xpos = ($i * $em + $ypos_offset); $ypos = ($k * $el + $xpos_offset); // Draw character imagechar($img, $font_size, $xpos, $ypos, $string, $color); // Remove character from string $string = substr($string, 1); } } header('Content-type: image/png'); imagepng($img); imagedestroy($img); } else { header('Content-type: image/png'); echo $data; } //end if } //end streamImage() public function saveImage($data = false) { $img = []; $img['file'] = tempnam($this->config->conf['temp'], 'PNP'); if (!$fh = fopen($img['file'], 'w')) { throw new Kohana_Exception('save-rrd-image', $img['file']); } fwrite($fh, $data); fclose($fh); if (function_exists('imagecreatefrompng')) { $image = imagecreatefrompng($img['file']); imagepng($image, $img['file']); list ($img['width'], $img['height'], $img['type'], $img['attr']) = getimagesize($img['file']); } else { throw new Kohana_Exception('error.gd-missing'); } return $img; } //end saveImage() private function format_rrd_debug($data) { $data = preg_replace('/(HRULE|VDEF|DEF|CDEF|GPRINT|LINE|AREA|COMMENT)/', "\n\${1}", $data); return $data; } //end format_rrd_debug() } //end class