Source for file GraphViz.php
Documentation is available at GraphViz.php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
* Copyright (c) 2001-2007, Dr. Volker Göbbels <vmg@arachnion.de> and
* Sebastian Bergmann <sb@sebastian-bergmann.de>. All rights reserved.
* LICENSE: This source file is subject to version 3.0 of the PHP license
* that is available through the world-wide-web at the following URI:
* http://www.php.net/license/3_0.txt. If you did not receive a copy of
* the PHP License and are unable to obtain it through the web, please
* send a note to license@php.net so we can mail you a copy immediately.
* @author Dr. Volker Göbbels <vmg@arachnion.de>
* @author Sebastian Bergmann <sb@sebastian-bergmann.de>
* @author Karsten Dambekalns <k.dambekalns@fishfarm.de>
* @author Michael Lively Jr. <mlively@ft11.net>
* @author Philippe Jausions <Philippe.Jausions@11abacus.com>
* @copyright 2001-2007 Dr. Volker Göbbels <vmg@arachnion.de> and Sebastian Bergmann <sb@sebastian-bergmann.de>
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version CVS: $Id: GraphViz.php,v 1.29 2008/02/05 19:39:35 jausions Exp $
* @link http://pear.php.net/package/Image_GraphViz
* @link http://www.graphviz.org/
* @since File available since Release 0.1.0
require_once 'System.php';
* Interface to AT&T's GraphViz tools.
* The GraphViz class allows for the creation of and to work with directed
* and undirected graphs and their visualization with AT&T's GraphViz tools.
* require_once 'Image/GraphViz.php';
* $graph = new Image_GraphViz();
* 'URL' => 'http://link1',
* 'label' => 'This is a label',
* 'URL' => 'http://link2',
* 'URL' => 'http://link3',
* 'label' => 'Edge Label'
* @author Sebastian Bergmann <sb@sebastian-bergmann.de>
* @author Dr. Volker Göbbels <vmg@arachnion.de>
* @author Karsten Dambekalns <k.dambekalns@fishfarm.de>
* @author Michael Lively Jr. <mlively@ft11.net>
* @author Philippe Jausions <Philippe.Jausions@11abacus.com>
* @copyright 2001-2007 Dr. Volker Göbbels <vmg@arachnion.de> and Sebastian Bergmann <sb@sebastian-bergmann.de>
* @license http://www.php.net/license/3_0.txt The PHP License, Version 3.0
* @version Release: 1.3.0RC3
* @link http://pear.php.net/package/Image_GraphViz
* @link http://www.graphviz.org/
* @since Class available since Release 0.1
* Base path to GraphViz commands
* Path to GraphViz/dot command
* Path to GraphViz/neato command
* Representation of the graph
var $graph = array ('edgesFrom' => array (),
* Whether to return PEAR_Error instance on failures instead of FALSE
* Setting the name of the Graph is useful for including multiple image
* maps on one page. If not set, the graph will be named 'G'.
* @param boolean $directed Directed (TRUE) or undirected (FALSE) graph.
* Note: You MUST pass a boolean, and not just
* an expression that evaluates to TRUE or
* FALSE (i.e. NULL, empty string, 0 will NOT
* @param array $attributes Attributes of the graph
* @param string $name Name of the Graph
* @param boolean $strict Whether to collapse multiple edges between
* @param boolean $returnError Set to TRUE to return PEAR_Error instances
* on failures instead of FALSE
$name = 'G', $strict = true , $returnError = false )
$this->graph['name'] = $name;
$this->graph['strict'] = (boolean) $strict;
* Outputs image of the graph in a given format
* This methods send HTTP headers
* @param string $format Format of the output image. This may be one
* of the formats supported by GraphViz.
* @param string $command "dot" or "neato"
* @return boolean TRUE on success, FALSE or PEAR_Error otherwise
function image($format = 'svg', $command = null )
if (!$file || PEAR ::isError ($file)) {
$outputfile = $file . '.' . $format;
if ($rendered !== true ) {
$sendContentLengthHeader = true;
header('Content-Type: image/' . $format);
header('Content-Type: image/tiff');
header('Content-Type: image/jpeg');
header('Content-Type: image/x-icon');
header('Content-Type: image/vnd.wap.wbmp');
header('Content-Type: application/pdf');
header('Content-Type: application/vnd.mif');
header('Content-Type: application/x-vrml');
header('Content-Type: image/svg+xml');
header('Content-Type: text/plain');
header('Content-Type: application/octet-stream');
$sendContentLengthHeader = false;
if ($sendContentLengthHeader) {
* Returns image (data) of the graph in a given format.
* @param string $format Format of the output image. This may be one
* of the formats supported by GraphViz.
* @param string $command "dot" or "neato"
* @return string The image (data) created by GraphViz, FALSE or PEAR_Error
* @since Method available since Release 1.1.0
function fetch($format = 'svg', $command = null )
if (!$file || PEAR ::isError ($file)) {
$outputfile = $file . '.' . $format;
if ($rendered !== true ) {
$fp = fopen($outputfile, 'rb');
$error = PEAR ::raiseError ('Could not read rendered file');
* Renders a given dot file into a given format.
* @param string $dotfile The absolute path of the dot file to use.
* @param string $outputfile The absolute path of the file to save to.
* @param string $format Format of the output image. This may be one
* of the formats supported by GraphViz.
* @param string $command "dot" or "neato"
* @return boolean TRUE if the file was saved, FALSE or PEAR_Error
$error = PEAR ::raiseError ('Could not find dot file');
$command = $this->graph['directed'] ? 'dot' : 'neato';
$command_orig = $command;
exec($command, $msg, $return_val);
$error = PEAR ::raiseError ($command_orig. ' command failed: '
* Adds a cluster to the graph.
* @param array $title Title.
* @param array $attributes Attributes of the cluster.
function addCluster($id, $title, $attributes = array ())
$this->graph['clusters'][$id]['title'] = $title;
$this->graph['clusters'][$id]['attributes'] = $attributes;
* Adds a note to the graph.
* @param string $name Name of the node.
* @param array $attributes Attributes of the node.
* @param string $group Group of the node.
function addNode($name, $attributes = array (), $group = 'default')
$this->graph['nodes'][$group][$name] = $attributes;
* Removes a node from the graph.
* This method doesn't remove edges associated with the node.
* @param string $name Name of the node to be removed.
* @param string $group Group of the node.
if (isset ($this->graph['nodes'][$group][$name])) {
unset ($this->graph['nodes'][$group][$name]);
* Adds an edge to the graph.
* $g->addEdge(array('node1' => 'node2'));
* $g->addEdge(array('node3' => 'node4'), $attr);
* // With port specification
* $g->addEdge(array('node5' => 'node6'), $attr, array('node6' => 'portA'));
* $g->addEdge(array('node7' => 'node8'), null, array('node7' => 'portC',
* @param array $edge Start => End node of the edge.
* @param array $attributes Attributes of the edge.
* @param array $ports Start node => port, End node => port
* @return integer an edge ID that can be used with {@link removeEdge()}
function addEdge($edge, $attributes = array (), $ports = array ())
$info['portFrom'] = $ports[$from];
$info['portTo'] = $ports[$to];
$info['attributes'] = $attributes;
if (!empty ($this->graph['strict'])) {
if (!isset ($this->graph['edgesFrom'][$from][$to][0 ])) {
$this->graph['edgesFrom'][$from][$to][0 ] = $info;
$this->graph['edgesFrom'][$from][$to][] = $info;
return count($this->graph['edgesFrom'][$from][$to]) - 1;
* Removes an edge from the graph.
* @param array $edge Start and End node of the edge to be removed.
* @param integer $id specific edge ID (only usefull when multiple edges
* exist between the same 2 nodes)
if (isset ($this->graph['edgesFrom'][$from][$to][$id])) {
unset ($this->graph['edgesFrom'][$from][$to][$id]);
if (count($this->graph['edgesFrom'][$from][$to]) == 0 ) {
unset ($this->graph['edgesFrom'][$from][$to]);
} elseif (isset ($this->graph['edgesFrom'][$from][$to])) {
unset ($this->graph['edgesFrom'][$from][$to]);
* Adds attributes to the graph.
* @param array $attributes Attributes to be added to the graph.
* Sets attributes of the graph.
* @param array $attributes Attributes to be set for the graph.
$this->graph['attributes'] = $attributes;
* Escapes an (attribute) array
* Detects if an attribute is <html>, contains double-quotes, etc...
* @param array $input input to escape
* @return array input escaped
foreach ((array) $input as $k => $v) {
* Returns a safe "ID" in DOT syntax
* @param string $input string to use as "ID"
* @param boolean $html whether to attempt detecting HTML-like content
function _escape($input, $html = false )
return ($input) ? 'true' : 'false';
if ($html && (strpos($input, '</') !== false
|| strpos($input, '/>') !== false )) {
if (preg_match('/^([a-z_][a-z_0-9]*|-?(\.[0-9]+|[0-9]+(\.[0-9]*)?))$/i',
array ('\n', '\n', '\n', '\"'), $input). '"';
* Sets directed/undirected flag for the graph.
* Note: You MUST pass a boolean, and not just an expression that evaluates
* to TRUE or FALSE (i.e. NULL, empty string, 0 will not work)
* @param boolean $directed Directed (TRUE) or undirected (FALSE) graph.
$this->graph['directed'] = $directed;
* Loads a graph from a file in Image_GraphViz format
* @param string $file File to load graph from.
// Convert old storage format to new one
$defaults = array ('edgesFrom' => array (),
if (isset ($this->graph['edges'])) {
foreach ($this->graph['edges'] as $id => $nodes) {
$attr = (isset ($this->graph['edgeAttributes'][$id]))
? $this->graph['edgeAttributes'][$id]
unset ($this->graph['edges']);
unset ($this->graph['edgeAttributes']);
* Save graph to file in Image_GraphViz format
* This saves the serialized version of the instance, not the
* @param string $file File to save the graph to.
* @return string File the graph was saved to, FALSE or PEAR_Error on
function save($file = '')
$file = System ::mktemp ('graph_');
if ($fp = @fopen($file, 'wb')) {
@fputs($fp, $serializedGraph);
$error = PEAR ::raiseError ('Could not save serialized graph instance');
* Parses the graph into GraphViz markup.
* @return string GraphViz markup
$parsedGraph = (empty ($this->graph['strict'])) ? '' : 'strict ';
$parsedGraph .= (empty ($this->graph['directed'])) ? 'graph ' : 'digraph ';
$parsedGraph .= $this->_escape($this->graph['name']). " {\n";
foreach ($attr as $key => $value) {
$parsedGraph .= $indent. $key. '='. $value. ";\n";
foreach ($this->graph['nodes'] as $group => $nodes) {
if ($group != 'default') {
$parsedGraph .= $indent. 'subgraph '. $this->_escape($group). " {\n";
if (isset ($this->graph['clusters'][$group])) {
$cluster = $this->graph['clusters'][$group];
foreach ($attr as $key => $value) {
$attr[] = $key. '='. $value;
if (strlen($cluster['title'])) {
. $this->_escape($cluster['title'], true );
$parsedGraph .= $indent. 'graph [ '. implode(',', $attr)
foreach ($nodes as $node => $attributes) {
$parsedGraph .= $indent. $this->_escape($node);
$attributeList = array ();
foreach ($this->_escapeArray($attributes) as $key => $value) {
$attributeList[] = $key. '='. $value;
if (!empty ($attributeList)) {
$parsedGraph .= ' [ '. implode(',', $attributeList). ' ]';
if ($group != 'default') {
$indent = substr($indent, 0 , -4 );
$parsedGraph .= $indent. "}\n";
if (!empty ($this->graph['directed'])) {
foreach ($this->graph['edgesFrom'] as $from => $toNodes) {
foreach ($toNodes as $to => $edges) {
foreach ($edges as $info) {
$f .= ':'. $this->_escape($info['portFrom']);
$t .= ':'. $this->_escape($info['portTo']);
$parsedGraph .= $indent. $f. $separator. $t;
if (!empty ($info['attributes'])) {
$attributeList = array ();
foreach ($this->_escapeArray($info['attributes']) as $key => $value) {
$attributeList[] = $key. '='. $value;
$parsedGraph .= ' [ '. implode(',', $attributeList). ' ]';
return $parsedGraph . "}\n";
* Saves GraphViz markup to file (in DOT language)
* @param string $file File to write the GraphViz markup to.
* @return string File to which the GraphViz markup was written, FALSE or
* or PEAR_Error on failure.
$parsedGraph = $this->parse();
if (!empty ($parsedGraph)) {
$file = System ::mktemp ('graph_');
if ($fp = @fopen($file, 'wb')) {
@fputs($fp, $parsedGraph);
$error = PEAR ::raiseError ('Could not save graph');
* c-hanging-comment-ender-p: nil
Documentation generated on Tue, 05 Feb 2008 15:00:05 -0500 by phpDocumentor 1.4.0. PEAR Logo Copyright © PHP Group 2004.
|