1<?php 2/** 3 * RRDGraph Plugin: Action Plugin 4 * 5 * @author Daniel Goß <developer@flashsystems.de> 6 * @license MIT 7 */ 8 9if (! defined ( 'DOKU_INC' )) die (); 10 11/** 12 * Structure for storing the media information passed to the media manager. 13 * This contains the path within the configured virtual namespace. 14 * 15 */ 16class rrdMediaInfo 17{ 18 /** @var string PageID of the page containing the image. */ 19 public $pageId; 20 21 /** @var string ImageID of the image on the page referenced by $pageID. */ 22 public $imageId; 23} 24 25/** 26 * Action Plugin Class for RRDGraph 27 * 28 */ 29class action_plugin_rrdgraph extends DokuWiki_Action_Plugin { 30 31 /** 32 * Checks if the necessary dependencies for this plugin are installed. 33 * @return Array Returns an array of error messages for missing dependencies. If all dependencies are installed an empty array is returned. 34 */ 35 private function &getMissingDependencies() 36 { 37 $deps = array(); 38 39 if (!function_exists("imagecreatetruecolor")) array_push($deps, $this->getLang('gd_missing')); 40 if (!function_exists("rrd_graph")) array_push($deps, $this->getLang('rrd_missing')); 41 42 return $deps; 43 } 44 45 /** 46 * Creates a rrdMediaInfo instance from a given wiki path. 47 * @param string $media Wiki path of the media file including namespace. 48 * @return Returns a rrdMediaInfo-Instance if the supplied wiki path is within the virtual media namespace. If it's outside the namespace false is returned. If it's wihin the namespace but the ImageId is invalid NULl is returned. 49 */ 50 private function &parseMediaPath($media) 51 { 52 $parts = explode(":", $media); 53 if (count($parts) < 3) return false; 54 55 $result = new rrdMediaInfo(); 56 57 //-- Check if we are within the rrdgraph virtual namespace. 58 $mediaNamespace = $this->getConf('graph_media_namespace'); 59 if (strcmp(array_shift($parts), $mediaNamespace) != 0) return false; 60 61 $result->imageId = array_pop($parts); 62 $result->pageId = implode(':', $parts); 63 64 //-- Verify the imageId 65 if (strspn($result->imageId, '0123456789abcdef') != strlen($result->imageId)) return null; 66 67 return $result; 68 } 69 70 /** 71 * Register the necessary events. 72 * @param Doku_Event_Handler $controller Event-Handler for registering the necessary events. 73 */ 74 public function register(Doku_Event_Handler $controller) { 75 //-- Performe some checks and show an error message (if an admin is loged in) to inform him that 76 // some key parts are missing. 77 // This uses the msg-Function. I don't know if this function is part of the public API. So beware! 78 foreach ($this->getMissingDependencies() as $missingDepMessage) { 79 msg($missingDepMessage, -1, '', '', MSG_ADMINS_ONLY); 80 } 81 82 //-- Register the callback hooks 83 $controller->register_hook ( 'PARSER_CACHE_USE', 'BEFORE', $this, '_handle_cache_use' ); 84 $controller->register_hook ( 'MEDIA_SENDFILE', 'BEFORE', $this, '_handle_media_sendfile' ); 85 $controller->register_hook ( 'FETCH_MEDIA_STATUS', 'BEFORE', $this, '_handle_fetch_media_status' ); 86 } 87 88 /** 89 * Event-Handler for PARSER_CACHE_USE. 90 * This handler is called BEFORE the cache is used and determins the dependencies of the page. It checks the metadata 91 * if an RRD graph is present and retrieves the dependencies of the graphs on this page from the metadata. 92 * 93 * @param Doku_Event $event The Doku_Event object 94 * @param mixed $param Value provided as fifth argument to register_hook() 95 */ 96 public function _handle_cache_use(&$event, $param) { 97 $cache = &$event->data; 98 99 if (! (isset ( $cache->page ) && isset ( $cache->mode ))) 100 return; 101 102 $dependencies = p_get_metadata ( $cache->page, 'plugin_' . $this->getPluginName () . ' dependencies' ); 103 104 if (! empty ( $dependencies )) { 105 foreach ( $dependencies as $dependency ) { 106 $cache->depends ['files'] [] = wikiFN ( $dependency ); 107 } 108 } 109 } 110 111 /** 112 * Event-Handler for MEDIA_SENDFILE. 113 * This handler ist called BEFORE media files are sent to the user. If the configured virtual media namespace 114 * is detected. The graph renderer is called and a virtual rrdgraph file ist sent. 115 * @param Doku_Event $event The Doku_Event object 116 * @param mixed $param Value provided as fifth argument to register_hook() 117 * @throws Exception 118 */ 119 public function _handle_media_sendfile(&$event, $param) { 120 global $INPUT; 121 122 $data = &$event->data; 123 $mediaPath = $this->parseMediaPath($data['media']); 124 125 if ($mediaPath !== false) { 126 127 //-- Load the rrdgraph helper. This helper contains the cache manager and other stuff used here. 128 $rrdGraphHelper = &plugin_load('helper', 'rrdgraph'); 129 if ($rrdGraphHelper === null) throw new Exception("rrdgraph helper not found."); 130 131 //-- Read some more parameters 132 $rangeNr = $INPUT->int('range', 0, true); 133 $mode = $INPUT->str('mode', helper_plugin_rrdgraph::MODE_GRAPH_EMBEDDED, true); 134 $bindingSource = $INPUT->str('bind'); 135 136 //-- Call the helper function to render and send the graph. 137 $rrdGraphHelper->sendRrdImage($mediaPath->pageId, $mediaPath->imageId, $rangeNr, $mode, $bindingSource); 138 139 //-- The graph was successfully send. Suppress any more processing 140 $event->preventDefault(); 141 } 142 } 143 144 /** 145 * Event-Handler for FETCH_MEDIA_STATUS. 146 * This handler ist called BEFORE the status of the media file is retrieved. If the configured virtual meida 147 * namespace is detected the method checks if the parameters look valid. If that's the case, the status code 148 * is set to 200 and DokuWiki calls the MEDIA_SENDFILE event hook. if the virtual namespace is not detected 149 * the method falls through and the normal media processing takes place. 150 * @param Doku_Event $event The Doku_Event object 151 * @param mixed $param Value provided as fifth argument to register_hook() 152 * @throws Exception 153 */ 154 public function _handle_fetch_media_status(&$event, $param) { 155 $data = &$event->data; 156 $mediaPath = $this->parseMediaPath($data['media']); 157 158 if ($mediaPath !== false) 159 { 160 //-- Check if the key features (GD and RRD) are installed and fail with a 500 error if they are missing. 161 if (count($this->getMissingDependencies()) == 0) { 162 if ($mediaPath === null) { 163 $data['status'] = 404; 164 $data['statusmessage'] = "Invalid graph request."; 165 } else { 166 $data['status'] = 200; 167 $data['statusmessage'] = ""; 168 } 169 } else { 170 $data['status'] = 500; 171 $data['statusmessage'] = "Could not render RRD graph. GD or rrd extension missing."; 172 } 173 } 174 } 175} 176 177