Image_GraphViz
[ class tree: Image_GraphViz ] [ index: Image_GraphViz ] [ all elements ]

Source for file GraphViz.php

Documentation is available at GraphViz.php

  1. <?php
  2. //
  3. // +---------------------------------------------------------------------------+
  4. // | PEAR :: Image :: GraphViz                                                 |
  5. // +---------------------------------------------------------------------------+
  6. // | Copyright (c) 2002-2005 Sebastian Bergmann <sb@sebastian-bergmann.de> and |
  7. // +---------------------------------------------------------------------------+
  8. // | This source file is subject to version 3.00 of the PHP License,           |
  9. // | that is available at http://www.php.net/license/3_0.txt.                  |
  10. // | If you did not receive a copy of the PHP license and are unable to        |
  11. // | obtain it through the world-wide-web, please send a note to               |
  12. // | license@php.net so we can mail you a copy immediately.                    |
  13. // +---------------------------------------------------------------------------+
  14. //
  15. // $Id: GraphViz.php,v 1.23 2004/12/22 08:06:11 sebastian Exp $
  16. //
  17.  
  18. require_once 'System.php';
  19.  
  20. /**
  21.  * Interface to AT&T's GraphViz tools.
  22.  *
  23.  * The GraphViz class allows for the creation of and the work with directed
  24.  * and undirected graphs and their visualization with AT&T's GraphViz tools.
  25.  *
  26.  * <code>
  27.  * <?php
  28.  * require_once 'Image/GraphViz.php';
  29.  *
  30.  * $graph = new Image_GraphViz();
  31.  *
  32.  * $graph->addNode(
  33.  *   'Node1',
  34.  *   array(
  35.  *     'URL'   => 'http://link1',
  36.  *     'label' => 'This is a label',
  37.  *     'shape' => 'box'
  38.  *   )
  39.  * );
  40.  *
  41.  * $graph->addNode(
  42.  *   'Node2',
  43.  *   array(
  44.  *     'URL'      => 'http://link2',
  45.  *     'fontsize' => '14'
  46.  *   )
  47.  * );
  48.  *
  49.  * $graph->addNode(
  50.  *   'Node3',
  51.  *   array(
  52.  *     'URL'      => 'http://link3',
  53.  *     'fontsize' => '20'
  54.  *   )
  55.  * );
  56.  *
  57.  * $graph->addEdge(
  58.  *   array(
  59.  *     'Node1' => 'Node2'
  60.  *   ),
  61.  *   array(
  62.  *     'label' => 'Edge Label'
  63.  *   )
  64.  * );
  65.  *
  66.  * $graph->addEdge(
  67.  *   array(
  68.  *     'Node1' => 'Node2'
  69.  *   ),
  70.  *   array(
  71.  *     'color' => 'red'
  72.  *   )
  73.  * );
  74.  *
  75.  * $graph->image();
  76.  * ?>
  77.  * </code>
  78.  *
  79.  * @author    Sebastian Bergmann <sb@sebastian-bergmann.de>
  80.  * @author
  81.  * @author    Karsten Dambekalns <k.dambekalns@fishfarm.de>
  82.  * @copyright
  83.  * @license   http://www.php.net/license/3_0.txt The PHP License, Version 3.0
  84.  * @category  Image
  85.  * @package   Image_GraphViz
  86.  */
  87. class Image_GraphViz {
  88.     /**
  89.     * Path to GraphViz/dot command
  90.     *
  91.     * @var  string 
  92.     */
  93.     var $dotCommand = 'dot';
  94.  
  95.     /**
  96.     * Path to GraphViz/neato command
  97.     *
  98.     * @var  string 
  99.     */
  100.     var $neatoCommand = 'neato';
  101.  
  102.     /**
  103.     * Representation of the graph
  104.     *
  105.     * @var  array 
  106.     */
  107.     var $graph;
  108.  
  109.     /**
  110.     * Constructor.
  111.     *
  112.     * Setting the name of the Graph is useful for including multiple image maps on
  113.     * one page. If not set, the graph will be named 'G'.
  114.     *
  115.     * @param  boolean $directed Directed (TRUE) or undirected (FALSE) graph.
  116.     * @param  array   $attributes Attributes of the graph
  117.     * @param  string  $name Name of the Graph
  118.     * @access public
  119.     */
  120.     function Image_GraphViz($directed = TRUE$attributes = array()$name = NULL{
  121.         $this->setDirected($directed);
  122.         $this->setAttributes($attributes);
  123.         $this->graph['name'$name;
  124.     }
  125.  
  126.     /**
  127.     * Output image of the graph in a given format.
  128.     *
  129.     * @param  string  Format of the output image.
  130.     *                  This may be one of the formats supported by GraphViz.
  131.     * @access public
  132.     */
  133.     function image($format 'svg'{
  134.         if ($data $this->fetch($format)) {
  135.             $sendContentLengthHeader = TRUE;
  136.  
  137.             switch ($format{
  138.                 case 'gif':
  139.                 case 'png':
  140.                 case 'wbmp'{
  141.                     header('Content-Type: image/' $format);
  142.                 }
  143.                 break;
  144.  
  145.                 case 'jpg'{
  146.                     header('Content-Type: image/jpeg');
  147.                 }
  148.                 break;
  149.  
  150.                 case 'pdf'{
  151.                     header('Content-Type: application/pdf');
  152.                 }
  153.                 break;
  154.  
  155.                 case 'svg'{
  156.                     header('Content-Type: image/svg+xml');
  157.                 }
  158.                 break;
  159.  
  160.                 default: {
  161.                     $sendContentLengthHeader = FALSE;
  162.                 }
  163.             }
  164.  
  165.             if ($sendContentLengthHeader{
  166.                 header('Content-Length: ' strlen($data));
  167.             }
  168.  
  169.             echo $data;
  170.         }
  171.     }
  172.  
  173.     /**
  174.     * Return image (data) of the graph in a given format.
  175.     *
  176.     * @param  string  Format of the output image.
  177.     *                  This may be one of the formats supported by GraphViz.
  178.     * @return string  The image (data) created by GraphViz.
  179.     * @access public
  180.     * @since  1.1.0
  181.     */
  182.     function fetch($format 'svg'{
  183.         if ($file $this->saveParsedGraph()) {
  184.             $outputfile $file '.' $format;
  185.             $command  $this->graph['directed'$this->dotCommand : $this->neatoCommand;
  186.             $command .= " -T$format -o$outputfile $file";
  187.     
  188.             @`$command`;
  189.             @unlink($file);
  190.     
  191.             $fp fopen($outputfile'rb');
  192.     
  193.             if ($fp{
  194.                 $data fread($fpfilesize($outputfile));
  195.                 fclose($fp);
  196.                 @unlink($outputfile);
  197.             }
  198.     
  199.             return $data;
  200.         }
  201.     
  202.         return FALSE;
  203.     }
  204.  
  205.     /**
  206.     * Add a cluster to the graph.
  207.     *
  208.     * @param  string  ID.
  209.     * @param  array   Title.
  210.     * @param  array   Attributes of the cluster.
  211.     * @access public
  212.     */
  213.     function addCluster($id$title$attributes = array()) {
  214.         $this->graph['clusters'][$id]['title'$title;
  215.         $this->graph['clusters'][$id]['attributes'$attributes;
  216.     }
  217.  
  218.     /**
  219.     * Add a note to the graph.
  220.     *
  221.     * @param  string  Name of the node.
  222.     * @param  array   Attributes of the node.
  223.     * @param  string  Group of the node.
  224.     * @access public
  225.     */
  226.     function addNode($name$attributes = array()$group 'default'{
  227.         $this->graph['nodes'][$group][$name$attributes;
  228.     }
  229.  
  230.     /**
  231.     * Remove a node from the graph.
  232.     *
  233.     * @param  Name of the node to be removed.
  234.     * @access public
  235.     */
  236.     function removeNode($name$group 'default'{
  237.         if (isset($this->graph['nodes'][$group][$name])) {
  238.             unset($this->graph['nodes'][$group][$name]);
  239.         }
  240.     }
  241.  
  242.     /**
  243.     * Add an edge to the graph.
  244.     *
  245.     * Caveat! This cannot handle multiple identical edges. If you use non-numeric
  246.     * IDs for the nodes, this will not do (too much) harm. For numeric IDs the
  247.     * array_merge() that is used will change the keys when merging arrays, leading
  248.     * to new nodes appearing in the graph.
  249.     *
  250.     * @param  array Start and End node of the edge.
  251.     * @param  array Attributes of the edge.
  252.     * @access public
  253.     */
  254.     function addEdge($edge$attributes = array()) {
  255.         if (is_array($edge)) {
  256.             $from key($edge);
  257.             $to   $edge[$from];
  258.             $id   $from '_' $to;
  259.  
  260.             if (!isset($this->graph['edges'][$id])) {
  261.                 $this->graph['edges'][$id$edge;
  262.             else {
  263.                 $this->graph['edges'][$idarray_merge(
  264.                   $this->graph['edges'][$id],
  265.                   $edge
  266.                 );
  267.             }
  268.  
  269.             if (is_array($attributes)) {
  270.                 if (!isset($this->graph['edgeAttributes'][$id])) {
  271.                     $this->graph['edgeAttributes'][$id$attributes;
  272.                 else {
  273.                     $this->graph['edgeAttributes'][$idarray_merge(
  274.                       $this->graph['edgeAttributes'][$id],
  275.                       $attributes
  276.                     );
  277.                 }
  278.             }
  279.         }
  280.     }
  281.  
  282.     /**
  283.     * Remove an edge from the graph.
  284.     *
  285.     * @param  array Start and End node of the edge to be removed.
  286.     * @access public
  287.     */
  288.     function removeEdge($edge{
  289.         if (is_array($edge)) {
  290.               $from key($edge);
  291.               $to   $edge[$from];
  292.               $id   $from '_' $to;
  293.  
  294.             if (isset($this->graph['edges'][$id])) {
  295.                 unset($this->graph['edges'][$id]);
  296.             }
  297.  
  298.             if (isset($this->graph['edgeAttributes'][$id])) {
  299.                 unset($this->graph['edgeAttributes'][$id]);
  300.             }
  301.         }
  302.     }
  303.  
  304.     /**
  305.     * Add attributes to the graph.
  306.     *
  307.     * @param  array Attributes to be added to the graph.
  308.     * @access public
  309.     */
  310.     function addAttributes($attributes{
  311.         if (is_array($attributes)) {
  312.             $this->graph['attributes'array_merge(
  313.               $this->graph['attributes'],
  314.               $attributes
  315.             );
  316.         }
  317.     }
  318.  
  319.     /**
  320.     * Set attributes of the graph.
  321.     *
  322.     * @param  array Attributes to be set for the graph.
  323.     * @access public
  324.     */
  325.     function setAttributes($attributes{
  326.         if (is_array($attributes)) {
  327.             $this->graph['attributes'$attributes;
  328.         }
  329.     }
  330.  
  331.     /**
  332.     * Set directed/undirected flag for the graph.
  333.     *
  334.     * @param  boolean Directed (TRUE) or undirected (FALSE) graph.
  335.     * @access public
  336.     */
  337.     function setDirected($directed{
  338.         if (is_bool($directed)) {
  339.             $this->graph['directed'$directed;
  340.         }
  341.     }
  342.  
  343.     /**
  344.     * Load graph from file.
  345.     *
  346.     * @param  string  File to load graph from.
  347.     * @access public
  348.     */
  349.     function load($file{
  350.         if ($serialized_graph implode(''@file($file))) {
  351.             $this->graph = unserialize($serialized_graph);
  352.         }
  353.     }
  354.  
  355.     /**
  356.     * Save graph to file.
  357.     *
  358.     * @param  string  File to save the graph to.
  359.     * @return mixed   File the graph was saved to, FALSE on failure.
  360.     * @access public
  361.     */
  362.     function save($file ''{
  363.         $serialized_graph serialize($this->graph);
  364.  
  365.         if (empty($file)) {
  366.             $file = System::mktemp('graph_');
  367.         }
  368.  
  369.         if ($fp @fopen($file'w')) {
  370.             @fputs($fp$serialized_graph);
  371.             @fclose($fp);
  372.  
  373.             return $file;
  374.         }
  375.  
  376.         return FALSE;
  377.     }
  378.  
  379.     /**
  380.     * Parse the graph into GraphViz markup.
  381.     *
  382.     * @return string  GraphViz markup
  383.     * @access public
  384.     */
  385.     function parse({
  386.         if (isset($this->graph['name']&& is_string($this->graph['name'])) {
  387.             $parsedGraph "digraph " $this->graph['name'" {\n";
  388.         else {
  389.             $parsedGraph "digraph G {\n";
  390.         }
  391.  
  392.         if (isset($this->graph['attributes'])) {
  393.             foreach ($this->graph['attributes'as $key => $value{
  394.                 $attributeList[$key '="' $value '"';
  395.             }
  396.  
  397.             if (!empty($attributeList)) {
  398.                 $parsedGraph .= 'graph [ '.implode(','$attributeList" ];\n";
  399.             }
  400.         }
  401.  
  402.         if (isset($this->graph['nodes'])) {
  403.             foreach($this->graph['nodes'as $group => $nodes{
  404.                 if ($group != 'default'{
  405.                     $parsedGraph .= sprintf(
  406.                       "subgraph \"cluster_%s\" {\nlabel=\"%s\";\n",
  407.  
  408.                       $group,
  409.                       isset($this->graph['clusters'][$group]$this->graph['clusters'][$group]['title'''
  410.                     );
  411.  
  412.                     if (isset($this->graph['clusters'][$group]['attributes'])) {
  413.                         unset($attributeList);
  414.  
  415.                         foreach ($this->graph['clusters'][$group]['attributes'as $key => $value{
  416.                             $attributeList[$key '="' $value '"';
  417.                         }
  418.  
  419.                         if (!empty($attributeList)) {
  420.                             $parsedGraph .= implode(','$attributeList";\n";
  421.                         }
  422.                     }
  423.                 }
  424.  
  425.                 foreach($nodes as $node => $attributes{
  426.                     unset($attributeList);
  427.  
  428.                     foreach($attributes as $key => $value{
  429.                         $attributeList[$key '="' $value '"';
  430.                     }
  431.  
  432.                     if (!empty($attributeList)) {
  433.                         $parsedGraph .= sprintf(
  434.                           "\"%s\" [ %s ];\n",
  435.                           addslashes(stripslashes($node)),
  436.                           implode(','$attributeList)
  437.                         );
  438.                     }
  439.                 }
  440.  
  441.                 if ($group != 'default'{
  442.                   $parsedGraph .= "}\n";
  443.                 }
  444.             }
  445.         }
  446.  
  447.         if (isset($this->graph['edges'])) {
  448.             foreach($this->graph['edges'as $label => $node{
  449.                 unset($attributeList);
  450.  
  451.                 $from key($node);
  452.                 $to   $node[$from];
  453.  
  454.                 foreach($this->graph['edgeAttributes'][$labelas $key => $value{
  455.                     $attributeList[$key '="' $value '"';
  456.                 }
  457.  
  458.                 $parsedGraph .= sprintf(
  459.                   '"%s" -> "%s"',
  460.                   addslashes(stripslashes($from)),
  461.                   addslashes(stripslashes($to))
  462.                 );
  463.                 
  464.                 if (!empty($attributeList)) {
  465.                     $parsedGraph .= sprintf(
  466.                       ' [ %s ]',
  467.                       implode(','$attributeList)
  468.                     );
  469.                 }
  470.  
  471.                 $parsedGraph .= ";\n";
  472.             }
  473.         }
  474.  
  475.         return $parsedGraph "}\n";
  476.     }
  477.  
  478.     /**
  479.     * Save GraphViz markup to file.
  480.     *
  481.     * @param  string  File to write the GraphViz markup to.
  482.     * @return mixed   File to which the GraphViz markup was
  483.     *                  written, FALSE on failure.
  484.     * @access public
  485.     */
  486.     function saveParsedGraph($file ''{
  487.         $parsedGraph $this->parse();
  488.  
  489.         if (!empty($parsedGraph)) {
  490.             if (empty($file)) {
  491.                 $file = System::mktemp('graph_');
  492.             }
  493.  
  494.             if ($fp @fopen($file'w')) {
  495.                 @fputs($fp$parsedGraph);
  496.                 @fclose($fp);
  497.  
  498.                 return $file;
  499.             }
  500.         }
  501.  
  502.         return FALSE;
  503.     }
  504. }
  505. ?>

Documentation generated on Mon, 11 Mar 2019 14:14:17 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.