1903f28d7SAndreas Gohr<?php 2903f28d7SAndreas Gohr/** 3903f28d7SAndreas Gohr * graphviz-Plugin: Parses graphviz-blocks 4903f28d7SAndreas Gohr * 5903f28d7SAndreas Gohr * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 6903f28d7SAndreas Gohr * @author Carl-Christian Salvesen <calle@ioslo.net> 7517bd836SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org> 8903f28d7SAndreas Gohr */ 9903f28d7SAndreas Gohr 10fb9a529dSAndreas Gohr 11903f28d7SAndreas Gohrif(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/'); 12903f28d7SAndreas Gohrif(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/'); 13903f28d7SAndreas Gohrrequire_once(DOKU_PLUGIN.'syntax.php'); 14903f28d7SAndreas Gohr 15903f28d7SAndreas Gohrclass syntax_plugin_graphviz extends DokuWiki_Syntax_Plugin { 16903f28d7SAndreas Gohr 17517bd836SAndreas Gohr /** 18517bd836SAndreas Gohr * What about paragraphs? 19517bd836SAndreas Gohr */ 20517bd836SAndreas Gohr function getPType(){ 21517bd836SAndreas Gohr return 'normal'; 22903f28d7SAndreas Gohr } 23903f28d7SAndreas Gohr 24903f28d7SAndreas Gohr /** 25903f28d7SAndreas Gohr * What kind of syntax are we? 26903f28d7SAndreas Gohr */ 27903f28d7SAndreas Gohr function getType(){ 28517bd836SAndreas Gohr return 'substition'; 29903f28d7SAndreas Gohr } 30903f28d7SAndreas Gohr 31903f28d7SAndreas Gohr /** 32903f28d7SAndreas Gohr * Where to sort in? 33903f28d7SAndreas Gohr */ 34903f28d7SAndreas Gohr function getSort(){ 35fb9a529dSAndreas Gohr return 200; 36903f28d7SAndreas Gohr } 37903f28d7SAndreas Gohr 38903f28d7SAndreas Gohr /** 39903f28d7SAndreas Gohr * Connect pattern to lexer 40903f28d7SAndreas Gohr */ 41903f28d7SAndreas Gohr function connectTo($mode) { 42517bd836SAndreas Gohr $this->Lexer->addSpecialPattern('<graphviz.*?>\n.*?\n</graphviz>',$mode,'plugin_graphviz'); 43903f28d7SAndreas Gohr } 44903f28d7SAndreas Gohr 45903f28d7SAndreas Gohr /** 46903f28d7SAndreas Gohr * Handle the match 47903f28d7SAndreas Gohr */ 48517bd836SAndreas Gohr function handle($match, $state, $pos, &$handler) { 49517bd836SAndreas Gohr $info = $this->getInfo(); 50903f28d7SAndreas Gohr 5167682e69SAndreas Gohr // prepare default data 52517bd836SAndreas Gohr $return = array( 53517bd836SAndreas Gohr 'width' => 0, 54517bd836SAndreas Gohr 'height' => 0, 55517bd836SAndreas Gohr 'layout' => 'dot', 56517bd836SAndreas Gohr 'align' => '', 57517bd836SAndreas Gohr 'version' => $info['date'], //force rebuild of images on update 58517bd836SAndreas Gohr ); 59903f28d7SAndreas Gohr 60517bd836SAndreas Gohr // prepare input 61517bd836SAndreas Gohr $lines = explode("\n",$match); 62517bd836SAndreas Gohr $conf = array_shift($lines); 63517bd836SAndreas Gohr array_pop($lines); 64517bd836SAndreas Gohr 65517bd836SAndreas Gohr // match config options 66517bd836SAndreas Gohr if(preg_match('/\b(left|center|right)\b/i',$conf,$match)) $return['align'] = $match[1]; 67517bd836SAndreas Gohr if(preg_match('/\b(\d+)x(\d+)\b/',$conf,$match)){ 68517bd836SAndreas Gohr $return['width'] = $match[1]; 69517bd836SAndreas Gohr $return['height'] = $match[2]; 70903f28d7SAndreas Gohr } 71517bd836SAndreas Gohr if(preg_match('/\b(dot|neato|twopi|circo|fdp)\b/i',$conf,$match)){ 72517bd836SAndreas Gohr $return['layout'] = strtolower($match[1]); 73903f28d7SAndreas Gohr } 74517bd836SAndreas Gohr if(preg_match('/\bwidth=([0-9]+)\b/i', $conf,$match)) $return['width'] = $match[1]; 75517bd836SAndreas Gohr if(preg_match('/\bheight=([0-9]+)\b/i', $conf,$match)) $return['height'] = $match[1]; 76517bd836SAndreas Gohr 77fb9a529dSAndreas Gohr 78fb9a529dSAndreas Gohr $input = join("\n",$lines); 79fb9a529dSAndreas Gohr $return['md5'] = md5($input); // we only pass a hash around 80fb9a529dSAndreas Gohr 81fb9a529dSAndreas Gohr // store input for later use 82fb9a529dSAndreas Gohr io_saveFile($this->_cachename($return,'txt'),$input); 83517bd836SAndreas Gohr 84517bd836SAndreas Gohr return $return; 85517bd836SAndreas Gohr } 86517bd836SAndreas Gohr 87903f28d7SAndreas Gohr /** 88fb9a529dSAndreas Gohr * Cache file is based on parameters that influence the result image 89fb9a529dSAndreas Gohr */ 90fb9a529dSAndreas Gohr function _cachename($data,$ext){ 91fb9a529dSAndreas Gohr unset($data['width']); 92fb9a529dSAndreas Gohr unset($data['height']); 93fb9a529dSAndreas Gohr unset($data['align']); 94fb9a529dSAndreas Gohr return getcachename(join('x',array_values($data)),'.graphviz.'.$ext); 95fb9a529dSAndreas Gohr } 96fb9a529dSAndreas Gohr 97fb9a529dSAndreas Gohr /** 98903f28d7SAndreas Gohr * Create output 99903f28d7SAndreas Gohr */ 100517bd836SAndreas Gohr function render($format, &$R, $data) { 101eb42ed8aSAndreas Gohr if($format == 'xhtml'){ 102fb9a529dSAndreas Gohr $img = DOKU_BASE.'lib/plugins/graphviz/img.php?'.buildURLparams($data); 103517bd836SAndreas Gohr $R->doc .= '<img src="'.$img.'" class="media'.$data['align'].'" alt=""'; 104517bd836SAndreas Gohr if($data['width']) $R->doc .= ' width="'.$data['width'].'"'; 105517bd836SAndreas Gohr if($data['height']) $R->doc .= ' height="'.$data['height'].'"'; 106*cea668ddSAndreas Gohr if($data['align'] == 'right') $R->doc .= ' align="right"'; 107*cea668ddSAndreas Gohr if($data['align'] == 'left') $R->doc .= ' align="left"'; 108517bd836SAndreas Gohr $R->doc .= '/>'; 109eb42ed8aSAndreas Gohr return true; 110eb42ed8aSAndreas Gohr }elseif($format == 'odt'){ 111eb42ed8aSAndreas Gohr $src = $this->_imgfile($data); 112eb42ed8aSAndreas Gohr $R->_odtAddImage($src,$data['width'],$data['height'],$data['align']); 113eb42ed8aSAndreas Gohr return true; 114eb42ed8aSAndreas Gohr } 115eb42ed8aSAndreas Gohr return false; 116517bd836SAndreas Gohr } 117517bd836SAndreas Gohr 11867682e69SAndreas Gohr /** 119fb9a529dSAndreas Gohr * Return path to the rendered image on our local system 1209d954370SAndreas Gohr */ 1219d954370SAndreas Gohr function _imgfile($data){ 122fb9a529dSAndreas Gohr $cache = $this->_cachename($data,'png'); 1239d954370SAndreas Gohr 1249d954370SAndreas Gohr // create the file if needed 1259d954370SAndreas Gohr if(!file_exists($cache)){ 126fb9a529dSAndreas Gohr $in = $this->_cachename($data,'txt'); 127fb9a529dSAndreas Gohr if($this->getConf('path')){ 128fb9a529dSAndreas Gohr $ok = $this->_run($data,$in,$cache); 129fb9a529dSAndreas Gohr }else{ 130fb9a529dSAndreas Gohr $ok = $this->_remote($data,$in,$cache); 131fb9a529dSAndreas Gohr } 132fb9a529dSAndreas Gohr if(!$ok) return false; 1339d954370SAndreas Gohr clearstatcache(); 1349d954370SAndreas Gohr } 1359d954370SAndreas Gohr 1369d954370SAndreas Gohr // resized version 137fb9a529dSAndreas Gohr if($data['width']){ 138fb9a529dSAndreas Gohr $cache = media_resize_image($cache,'png',$data['width'],$data['height']); 139fb9a529dSAndreas Gohr } 140fb9a529dSAndreas Gohr 141fb9a529dSAndreas Gohr // something went wrong, we're missing the file 142fb9a529dSAndreas Gohr if(!file_exists($cache)) return false; 1439d954370SAndreas Gohr 1449d954370SAndreas Gohr return $cache; 1459d954370SAndreas Gohr } 1469d954370SAndreas Gohr 1479d954370SAndreas Gohr /** 148fb9a529dSAndreas Gohr * Render the output remotely at google 149fb9a529dSAndreas Gohr */ 150fb9a529dSAndreas Gohr function _remote($data,$in,$out){ 151fb9a529dSAndreas Gohr if(!file_exists($in)){ 152fb9a529dSAndreas Gohr if($conf['debug']){ 153fb9a529dSAndreas Gohr dbglog($in,'no such graphviz input file'); 154fb9a529dSAndreas Gohr } 155fb9a529dSAndreas Gohr return false; 156fb9a529dSAndreas Gohr } 157fb9a529dSAndreas Gohr 158fb9a529dSAndreas Gohr $http = new DokuHTTPClient(); 159fb9a529dSAndreas Gohr $http->timeout=30; 160fb9a529dSAndreas Gohr 161fb9a529dSAndreas Gohr $pass = array(); 162fb9a529dSAndreas Gohr $pass['cht'] = 'gv:'.$data['layout']; 163fb9a529dSAndreas Gohr $pass['chl'] = io_readFile($in); 164fb9a529dSAndreas Gohr 165fb9a529dSAndreas Gohr $img = $http->post('http://chart.apis.google.com/chart',$pass,'&'); 166fb9a529dSAndreas Gohr if(!$img) return false; 167fb9a529dSAndreas Gohr 168fb9a529dSAndreas Gohr return io_saveFile($out,$img); 169fb9a529dSAndreas Gohr } 170fb9a529dSAndreas Gohr 171fb9a529dSAndreas Gohr /** 172517bd836SAndreas Gohr * Run the graphviz program 173517bd836SAndreas Gohr */ 174fb9a529dSAndreas Gohr function _run($data,$in,$out) { 175903f28d7SAndreas Gohr global $conf; 176903f28d7SAndreas Gohr 177fb9a529dSAndreas Gohr if(!file_exists($in)){ 178fb9a529dSAndreas Gohr if($conf['debug']){ 179fb9a529dSAndreas Gohr dbglog($in,'no such graphviz input file'); 180fb9a529dSAndreas Gohr } 181fb9a529dSAndreas Gohr return false; 182fb9a529dSAndreas Gohr } 183903f28d7SAndreas Gohr 184517bd836SAndreas Gohr $cmd = $this->getConf('path'); 185517bd836SAndreas Gohr $cmd .= ' -Tpng'; 186517bd836SAndreas Gohr $cmd .= ' -K'.$data['layout']; 187fb9a529dSAndreas Gohr $cmd .= ' -o'.escapeshellarg($out); //output 188fb9a529dSAndreas Gohr $cmd .= ' '.escapeshellarg($in); //input 189903f28d7SAndreas Gohr 190517bd836SAndreas Gohr exec($cmd, $output, $error); 191903f28d7SAndreas Gohr 192517bd836SAndreas Gohr if ($error != 0){ 193517bd836SAndreas Gohr if($conf['debug']){ 194517bd836SAndreas Gohr dbglog(join("\n",$output),'graphviz command failed: '.$cmd); 195903f28d7SAndreas Gohr } 196903f28d7SAndreas Gohr return false; 197903f28d7SAndreas Gohr } 198517bd836SAndreas Gohr return true; 199903f28d7SAndreas Gohr } 200903f28d7SAndreas Gohr 201903f28d7SAndreas Gohr} 202903f28d7SAndreas Gohr 203517bd836SAndreas Gohr 204517bd836SAndreas Gohr 205