1<?php 2 3/** 4 * Action component of diagrams plugin 5 * 6 * This handles general operations independent of the configured mode 7 * 8 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 9 * @author Innovakom + CosmoCode <dokuwiki@cosmocode.de> 10 */ 11class action_plugin_diagrams_action extends DokuWiki_Action_Plugin 12{ 13 /** @var helper_plugin_diagrams */ 14 protected $helper; 15 16 /**@inheritDoc */ 17 public function register(Doku_Event_Handler $controller) 18 { 19 $controller->register_hook('DOKUWIKI_STARTED', 'AFTER', $this, 'addJsinfo'); 20 $controller->register_hook('MEDIAMANAGER_STARTED', 'AFTER', $this, 'addJsinfo'); 21 $controller->register_hook('DOKUWIKI_STARTED', 'AFTER', $this, 'checkConf'); 22 $controller->register_hook('AJAX_CALL_UNKNOWN', 'BEFORE', $this, 'handleCache'); 23 $controller->register_hook('AJAX_CALL_UNKNOWN', 'BEFORE', $this, 'handlePNGDownload'); 24 25 $this->helper = plugin_load('helper', 'diagrams'); 26 } 27 28 /** 29 * Add data to JSINFO 30 * 31 * full service URL 32 * digram mode 33 * security token used for uploading 34 * 35 * @param Doku_Event $event DOKUWIKI_STARTED|MEDIAMANAGER_STARTED 36 */ 37 public function addJsinfo(Doku_Event $event) 38 { 39 global $JSINFO; 40 $JSINFO['sectok'] = getSecurityToken(); 41 $JSINFO['plugins']['diagrams'] = [ 42 'service_url' => $this->getConf('service_url'), 43 'mode' => $this->getConf('mode'), 44 ]; 45 } 46 47 /** 48 * Check if DokuWiki is properly configured to handle SVG diagrams 49 * 50 * @param Doku_Event $event DOKUWIKI_STARTED 51 */ 52 public function checkConf(Doku_Event $event) 53 { 54 $mime = getMimeTypes(); 55 if (!array_key_exists('svg', $mime) || $mime['svg'] !== 'image/svg+xml') { 56 msg($this->getLang('missingConfig'), -1); 57 } 58 } 59 60 /** 61 * Save the PNG cache of a diagram 62 * 63 * @param Doku_Event $event AJAX_CALL_UNKNOWN 64 */ 65 public function handleCache(Doku_Event $event) 66 { 67 if ($event->data !== 'plugin_diagrams_savecache') return; 68 $event->preventDefault(); 69 $event->stopPropagation(); 70 71 // to not further complicate the JavaScript and because creating the PNG is essentially free, 72 // we always create the PNG but only save it if the cache is enabled 73 if (!$this->getConf('pngcache')) { 74 echo 'PNG cache disabled, call ignored'; 75 return; 76 } 77 78 global $INPUT; 79 80 $svg = $INPUT->str('svg'); // raw svg 81 $png = $INPUT->str('png'); // data uri 82 83 if (!checkSecurityToken()) { 84 http_status(403); 85 return; 86 } 87 88 if (!$this->helper->isDiagram($svg)) { 89 http_status(400); 90 return; 91 } 92 93 if (!preg_match('/^data:image\/png;base64,/', $png)) { 94 http_status(400); 95 return; 96 } 97 $png = base64_decode(explode(',', $png)[1]); 98 99 if (substr($png, 1, 3) !== 'PNG') { 100 http_status(400); 101 return; 102 } 103 104 $cacheName = getCacheName($svg, '.diagrams.png'); 105 if (io_saveFile($cacheName, $png)) { 106 echo 'OK'; 107 } else { 108 http_status(500); 109 } 110 } 111 112 /** 113 * PNG download available via link created in JS (only if PNG caching is enabled) 114 * 115 * @param Doku_Event $event 116 * @return void 117 */ 118 public function handlePNGDownload(Doku_Event $event) 119 { 120 if ($event->data !== 'plugin_diagrams_pngdownload') return; 121 $event->preventDefault(); 122 $event->stopPropagation(); 123 124 global $INPUT; 125 global $conf; 126 127 $cacheName = $INPUT->str('pngcache'); 128 $media = cleanID($INPUT->str('media')); 129 $id = cleanID($INPUT->str('id')); 130 131 // check ACLs to original file or page 132 if ( 133 ($id && auth_quickaclcheck($id) < AUTH_READ) || 134 ($media && auth_quickaclcheck($media) < AUTH_READ) 135 ) { 136 http_status(403); 137 return; 138 } 139 140 // check if download target exists 141 if ( 142 ($id && !page_exists($id)) || 143 ($media && !media_exists($media)) 144 ) { 145 http_status(404); 146 return; 147 } 148 149 // serve cached PNG file 150 $file = $conf['cachedir'] . $cacheName . \dokuwiki\plugin\diagrams\Diagrams::CACHE_EXT; 151 if (file_exists($file)) { 152 // correct file extension 153 $download = $media ? str_replace('.svg', '.png', $media) : $id . ".png"; 154 $download = noNS($download); 155 header('Content-Type: image/png'); 156 header("Content-Disposition: attachment; filename=$download;"); 157 http_sendfile($file); 158 readfile($file); 159 } else { 160 http_status(404); 161 } 162 } 163} 164