array("pipe", "r"), // stdin is a pipe that the child will read from 1 => array("pipe", "w"), // stdout is a pipe that the child will write to 2 => array("pipe", "w") // stderr is a pipe that the child will write to ); // proc_open rrdtool, using - as a parameter, to specify "remote control mode" $this->_proc = proc_open($rrdtool_bin." -", $descriptorspec, $this->_pipes); var_dump($this->_proc); var_dump($this->_pipes); } function close() { fclose($this->_pipes[0]); fclose($this->_pipes[1]); fclose($this->_pipes[2]); proc_close($this->_proc); } function _run($command) { fwrite($this->_pipes[0], $command."\n"); $data = ""; $line = ""; while (substr($line,0,2) != "OK") { $line = fgets($this->_pipes[1],1024); $data .= $line; } if ($this->debug) { var_dump($data); } // not sure if this is 100% safe or not, according to the docs, // it looks like it should be return (substr($data,0,5) != "ERROR"); } /** Create a new rra * @param string $filename Full path and name of the rrd file to create * @param int $start Start time, timestamp or AT spec (--start) * @param int $step Step value, in seconds (--step) * @param array $ds Array of rrdtool_ds objects for specifying * data sources * @param array $rra Array of rrdtool_rra objects for specifying * round-robin archives */ function create($filename, $start, $step, $ds, $rra) { $options = array(); // create DS options string foreach ($ds as $rrd_ds) { $options[] = "DS:".$rrd_ds->name.":".$rrd_ds->type.":".$rrd_ds->heartbeat.":".$rrd_ds->min.":".$rrd_ds->max; } // create RRA options string foreach ($rra as $rrd_rra) { $options[] = "RRA:".$rrd_rra->cf.":".$rrd_rra->xff.":".$rrd_rra->steps.":".$rrd_rra->rows; } $args = "--step ".$step." ".implode(" ",$options); return $this->_run("create ".$filename." ".$args); } /** Update data in an rra * @param string $filename Full path and name of the rrd file * @param array $data Data values. If array keys are specified, * they should be the DS names, and a template * will be used (--template). * @param int $time The update time to use, or null for 'N' (rrdtool * uses current time) */ function update($filename, $data, $time = null) { $args = ""; if (!isset($data[0])) { // assume there are names for all the items, so use a template $args .= "-t ".implode(":",array_keys($data))." "; } $args .= (!empty($time) ? "N" : $time).implode(":",$data); return $this->_run("update ".$filename." ".$args); } /** Create a graph * This function can be called either instantized, or statically. If it's an instance, * $outputfile must be specified. If called statically, rrdtool is called directly by * an exec() system call (not via pipes, like normal), and if $outputfile is null, then * the raw image data will be returned, and no image file needs to be created on disk * * @param array $options General options. Should be specified using * their full option name as a key. For example, to * set "--upper-limit 10", use * array("upper-limit"=>10) * @param array $items An array of items inherited from the rrdtool_graph * class. Passed as arguments, in the array's order * @param string $outputfile The graph file to create. Note: If being called * statically (ie: rrdtool::graph()) then this should * be the path to the rrdtool binary. */ function graph($options, $items, $outputfile) { $args; foreach ($options as $name=>$value) { $args .= "--".$name." ".$value." "; } foreach (array_keys($items) as $key) { // use array_keys to prevent copying $args .= $items[$key]->output()." "; } if (isset($this)) { // being called as part of a class, run normally return $this->_run("graph ".$args); } else { // special case: being called statically // Note: $args is not necessarily safe for commandline - be careful // with where the input comes from exec(escapeshellcmd($outputfile)." ".$args); } } function info($filename) { // this was more for testing than anything return $this->_run("info ".$filename); } } /** Data source definition */ class rrdtool_ds { var $name; var $type; var $heartbeat; var $min; var $max; function rrdtool_ds($name, $type, $heartbeat, $min = "U", $max = "U") { $this->name = $name; $this->type = $type; $this->heartbeat = $heartbeat; $this->min = $min; $this->max = $max; } } /** Round-robin archive definition */ class rrdtool_rra { var $cf; var $steps; var $rows; var $xff; function rrdtool_rra($cf, $steps, $rows, $xff = 0.5) { $this->cf = $cf; $this->steps = $steps; $this->rows = $rows; $this->xff = $xff; } } class rrdtool_graph { function output() { //abstract -- children must override this return false; } } class rrdtool_graph_def extends rrdtool_graph { var $vname; var $rrdfile; var $ds; var $cf; function rrdtool_graph_def($vname, $rrdfile, $ds, $cf) { $this->vname = $vname; $this->rrdfile = $rrdfile; $this->ds = $ds; $this->cf = $cf; } function output() { // DEF:vname=rrd:ds-name:CF return "DEF:".$this->vname."=".$this->rrdfile.":".$this->ds.":".$this->cf; } } class rrdtool_graph_cdef extends rrdtool_graph { var $vname; var $expr; function rrdtool_graph_cdef($vname, $expr) { $this->vname = $vname; $this->expr = $expr; } function output() { // CDEF:vname=rpn-expression return "CDEF:".$this->vname."=".$this->expr; } } class rrdtool_graph_print extends rrdtool_graph { var $vname; var $cf; var $format; function rrdtool_graph_print($vname, $cf, $format) { $this->vname = $vname; $this->cf = $cf; $this->format = $format; } function output() { // PRINT:vname:CF:format return "PRINT:".$this->vname.":".$this->cf.":".$this->format; } } class rrdtool_graph_gprint extends rrdtool_graph { var $vname; var $cf; var $format; function rrdtool_graph_gprint($vname, $cf, $format) { $this->vname = $vname; $this->cf = $cf; $this->format = $format; } function output() { // GPRINT:vname:CF:format return "GPRINT:".$this->vname.":".$this->cf.":".$this->format; } } class rrdtool_graph_comment extends rrdtool_graph { var $text; function rrdtool_graph_comment($text) { $this->text = $text; } function output() { // COMMENT:text return "COMMENT:".escapeshellarg($this->text); } } class rrdtool_graph_hrule extends rrdtool_graph { var $value; var $color; var $legend; function rrdtool_graph_hrule($value, $color, $legend = false) { $this->value = $value; $this->color = $color; // in "rrggbb" hex format $this->legend = $legend; } function output() { // HRULE:value#rrggbb[:legend] return "HRULE:".$this->value."#".$this->color.(!empty($this->legend) ? ":".escapeshellarg($this->legend) : ""); } } class rrdtool_graph_vrule extends rrdtool_graph { var $value; var $color; var $legend; function rrdtool_graph_vrule($value, $color, $legend = false) { $this->value = $value; $this->color = $color; // in "rrggbb" hex format $this->legend = $legend; } function output() { // VRULE:value#rrggbb[:legend] return "VRULE:".$this->value."#".$this->color.(!empty($this->legend) ? ":".escapeshellarg($this->legend) : ""); } } class rrdtool_graph_line extends rrdtool_graph { var $type; var $value; var $color; var $legend; function rrdtool_graph_line($type, $vname, $color = false, $legend = false) { $this->type = $type; $this->value = $value; $this->color = $color; // in "rrggbb" hex format $this->legend = $legend; } function output() { // LINE{1|2|3}:vname[#rrggbb[:legend]] return "LINE".$this->type.":".$this->value.(!empty($this->color) ? "#".$this->color : "").(!empty($this->legend) ? ":".escapeshellarg($this->legend) : ""); } } class rrdtool_graph_area extends rrdtool_graph { var $vname; var $color; var $legend; function rrdtool_graph_area($vname, $color, $legend = false) { $this->vname = $vname; $this->color = $color; // in "rrggbb" hex format $this->legend = $legend; } function output() { // AREA:vname#rrggbb[:legend] return "AREA:".$this->vname."#".$this->color.(!empty($this->legend) ? ":".escapeshellarg($this->legend) : ""); } } class rrdtool_graph_stack extends rrdtool_graph { var $vname; var $color; var $legend; function rrdtool_graph_stack($vname, $color, $legend = false) { $this->vname = $vname; $this->color = $color; // in "rrggbb" hex format $this->legend = $legend; } function output() { // STACK:vname#rrggbb[:legend] return "STACK:".$this->vname."#".$this->color.(!empty($this->legend) ? ":".escapeshellarg($this->legend) : ""); } } /** Examples: Update a couple files: $rrd = new rrdtool("/usr/local/rrdtool/bin/rrdtool"); $rrd->update("/path/to/rra/cisternlevel_16.rrd", array(45)); $rrd->update("/path/to/rra/wellcurrent_17.rrd", array("ds1"=>7,"ds2"=>12)); $rrd->close(); Generate a graph: $options = array( "title"=>"Demo Graph", "imgformat"=>"PNG" ); $items = array( new rrdtool_graph_def("bps-in","bps_router1.rrd","bps-in","AVERAGE"), new rrdtool_graph_def("bps-out","bps_router1.rrd","bps-out","AVERAGE"), new rrdtool_graph_line("bps-in","0000FF","Traffic out"), new rrdtool_graph_area("bps-out","00FF00","Traffic in") ); header("Content-type: image/png"); echo rrdtool::graph($options, $items); */ ?>