00001 <?php
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00057 class Process_GraphViz {
00063 var $dotCommand = 'dot';
00064
00065 var $pid;
00066
00072 var $neatoCommand = 'neato';
00073
00079 var $graph;
00080
00088 function Process_GraphViz($directed = true, $attributes = array()) {
00089 $this->setDirected($directed);
00090 $this->setAttributes($attributes);
00091 if (defined('GRAPHVIZ_BIN_DIR') && GRAPHVIZ_BIN_DIR) {
00092 $this->dotCommand = GRAPHVIZ_BIN_DIR.'/'.$this->dotCommand;
00093 $this->neatoCommand = GRAPHVIZ_BIN_DIR.'/'.$this->neatoCommand;
00094 }
00095 }
00096
00097 function set_pid($pid)
00098 {
00099 $this->pid = $pid;
00100 }
00101
00109 function image($format = 'png') {
00110 if ($file = $this->saveParsedGraph()) {
00111 $outputfile = $file . '.' . $format;
00112 $outputfile2 = $file . '.' . 'map';
00113 $command = $this->graph['directed'] ? $this->dotCommand : $this->neatoCommand;
00114 $command .= " -T$format -o$outputfile $file";
00115
00116 @`$command`;
00117 $command = $this->dotCommand;
00118 $command.= " -Tcmap -o$outputfile2 $file";
00119 @`$command`;
00120 $fr = fopen($outputfile2,"r");
00121 $map = fread($fr,filesize($outputfile2));
00122 fclose($fr);
00123 @unlink($file);
00124
00125 switch ($format) {
00126 case 'gif':
00127 case 'jpg':
00128 case 'png':
00129 case 'svg':
00130 case 'wbmp': {
00131 header('Content-Type: image/' . $format);
00132 }
00133 break;
00134
00135 case 'pdf': {
00136 header('Content-Type: application/pdf');
00137 }
00138 break;
00139 }
00140
00141 header('Content-Length: ' . filesize($outputfile));
00142
00143 $fp = fopen($outputfile, 'rb');
00144
00145 if ($fp) {
00146 echo fread($fp, filesize($outputfile));
00147 fclose($fp);
00148 @unlink($outputfile);
00149 }
00150 @unlink($outputfile2);
00151 return $map;
00152 }
00153 }
00154
00155 function image_and_map($format = 'png') {
00156 if ($file = $this->saveParsedGraph()) {
00157 $outputfile = $file . '.' . $format;
00158 $outputfile2 = $file . '.' . 'map';
00159 if(!isset($this->graph['directed'])) $this->graph['directed']=true;
00160 $command = $this->graph['directed'] ? $this->dotCommand : $this->neatoCommand;
00161 $command .= " -T$format -o $outputfile $file";
00162 @`$command`;
00163
00164 $command = $this->dotCommand;
00165 $command.= " -Tcmap -o $outputfile2 $file";
00166 @`$command`;
00167 @unlink($file);
00168 return true;
00169 }
00170 }
00171
00172
00173 function map() {
00174 if ($file = $this->saveParsedGraph()) {
00175 $outputfile2 = $file . '.' . 'map';
00176
00177 $command = $this->dotCommand;
00178 $command.= " -Tcmap -o$outputfile2 $file";
00179 @`$command`;
00180 $fr = fopen($outputfile2,"r");
00181 $map = fread($fr,filesize($outputfile2));
00182 fclose($fr);
00183
00184
00185 @unlink($file);
00186 return $map;
00187 }
00188 }
00189
00197 function addCluster($id, $title) {
00198 $this->graph['clusters'][$id] = $title;
00199 }
00200
00209 function addNode($name, $attributes = array(), $group = 'default') {
00210 $this->graph['nodes'][$group][$name] = $attributes;
00211 }
00212
00219 function removeNode($name, $group = 'default') {
00220 if (isset($this->graph['nodes'][$group][$name])) {
00221 unset($this->graph['nodes'][$group][$name]);
00222 }
00223 }
00224
00232 function addEdge($edge, $attributes = array()) {
00233 if (is_array($edge)) {
00234 $from = key($edge);
00235 $to = $edge[$from];
00236 $id = $from . '_' . $to;
00237
00238 if (!isset($this->graph['edges'][$id])) {
00239 $this->graph['edges'][$id] = $edge;
00240 } else {
00241 $this->graph['edges'][$id] = array_merge(
00242 $this->graph['edges'][$id],
00243 $edge
00244 );
00245 }
00246
00247 if (is_array($attributes)) {
00248 if (!isset($this->graph['edgeAttributes'][$id])) {
00249 $this->graph['edgeAttributes'][$id] = $attributes;
00250 } else {
00251 $this->graph['edgeAttributes'][$id] = array_merge(
00252 $this->graph['edgeAttributes'][$id],
00253 $attributes
00254 );
00255 }
00256 }
00257 }
00258 }
00259
00266 function removeEdge($edge) {
00267 if (is_array($edge)) {
00268 $from = key($edge);
00269 $to = $edge[$from];
00270 $id = $from . '_' . $to;
00271
00272 if (isset($this->graph['edges'][$id])) {
00273 unset($this->graph['edges'][$id]);
00274 }
00275
00276 if (isset($this->graph['edgeAttributes'][$id])) {
00277 unset($this->graph['edgeAttributes'][$id]);
00278 }
00279 }
00280 }
00281
00288 function addAttributes($attributes) {
00289 if (is_array($attributes)) {
00290 $this->graph['attributes'] = array_merge(
00291 $this->graph['attributes'],
00292 $attributes
00293 );
00294 }
00295 }
00296
00303 function setAttributes($attributes) {
00304 if (is_array($attributes)) {
00305 $this->graph['attributes'] = $attributes;
00306 }
00307 }
00308
00315 function setDirected($directed) {
00316 if (is_bool($directed)) {
00317 $this->graph['directed'] = $directed;
00318 }
00319 }
00320
00327 function load($file) {
00328 if ($serialized_graph = implode('', @file($file))) {
00329 $this->graph = unserialize($serialized_graph);
00330 }
00331 }
00332
00340 function save($file = '') {
00341 $serialized_graph = serialize($this->graph);
00342
00343 if (empty($file)) {
00344 $file = tempnam('temp', 'graph_');
00345 }
00346
00347 if ($fp = @fopen($file, 'w')) {
00348 @fputs($fp, $serialized_graph);
00349 @fclose($fp);
00350
00351 return $file;
00352 }
00353
00354 return false;
00355 }
00356
00363 function parse() {
00364 $parsedGraph = "digraph G {\n";
00365
00366 if (isset($this->graph['attributes'])) {
00367 foreach ($this->graph['attributes'] as $key => $value) {
00368 $attributeList[] = $key . '="' . $value . '"';
00369 }
00370
00371 if (!empty($attributeList)) {
00372 $parsedGraph .= implode(',', $attributeList) . ";\n";
00373 }
00374 }
00375
00376 if (isset($this->graph['nodes'])) {
00377 foreach($this->graph['nodes'] as $group => $nodes) {
00378 if ($group != 'default') {
00379 $parsedGraph .= sprintf(
00380 "subgraph \"cluster_%s\" {\nlabel=\"%s\";\n",
00381
00382 $group,
00383 isset($this->graph['clusters'][$group]) ? $this->graph['clusters'][$group] : ''
00384 );
00385 }
00386
00387 foreach($nodes as $node => $attributes) {
00388 unset($attributeList);
00389
00390 foreach($attributes as $key => $value) {
00391 $attributeList[] = $key . '="' . $value . '"';
00392 }
00393
00394 if (!empty($attributeList)) {
00395 $parsedGraph .= sprintf(
00396 "\"%s\" [ %s ];\n",
00397 addslashes(stripslashes($node)),
00398 implode(',', $attributeList)
00399 );
00400 }
00401 }
00402
00403 if ($group != 'default') {
00404 $parsedGraph .= "}\n";
00405 }
00406 }
00407 }
00408
00409 if (isset($this->graph['edges'])) {
00410 foreach($this->graph['edges'] as $label => $node) {
00411 unset($attributeList);
00412
00413 $from = key($node);
00414 $to = $node[$from];
00415
00416 foreach($this->graph['edgeAttributes'][$label] as $key => $value) {
00417 $attributeList[] = $key . '="' . $value . '"';
00418 }
00419
00420 $parsedGraph .= sprintf(
00421 '"%s" -> "%s"',
00422 addslashes(stripslashes($from)),
00423 addslashes(stripslashes($to))
00424 );
00425
00426 if (!empty($attributeList)) {
00427 $parsedGraph .= sprintf(
00428 ' [ %s ]',
00429 implode(',', $attributeList)
00430 );
00431 }
00432
00433 $parsedGraph .= ";\n";
00434 }
00435 }
00436
00437 return $parsedGraph . "}\n";
00438 }
00439
00448 function saveParsedGraph($file = '') {
00449 $parsedGraph = $this->parse();
00450 if (!empty($parsedGraph)) {
00451 $file = GALAXIA_PROCESSES.'/'.$this->pid.'/graph/'.$this->pid;
00452
00453 if ($fp = @fopen($file, 'w')) {
00454 @fputs($fp, $parsedGraph, strlen($parsedGraph));
00455 @fclose($fp);
00456
00457 return $file;
00458 }
00459 }
00460
00461 return false;
00462 }
00463 }
00464 ?>