1317bdfc2SAndreas Gohr<?php 2317bdfc2SAndreas Gohr 3317bdfc2SAndreas Gohr/** 4317bdfc2SAndreas Gohr * Action component of diagrams plugin 5317bdfc2SAndreas Gohr * 659e7180eSAndreas Gohr * This handles general operations independent of the configured mode 759e7180eSAndreas Gohr * 859e7180eSAndreas Gohr * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 959e7180eSAndreas Gohr * @author Innovakom + CosmoCode <dokuwiki@cosmocode.de> 10317bdfc2SAndreas Gohr */ 11317bdfc2SAndreas Gohrclass action_plugin_diagrams_action extends DokuWiki_Action_Plugin 12317bdfc2SAndreas Gohr{ 132bec1a22SAndreas Gohr /** @var helper_plugin_diagrams */ 142bec1a22SAndreas Gohr protected $helper; 15317bdfc2SAndreas Gohr 1659e7180eSAndreas Gohr /**@inheritDoc */ 17317bdfc2SAndreas Gohr public function register(Doku_Event_Handler $controller) 18317bdfc2SAndreas Gohr { 19317bdfc2SAndreas Gohr $controller->register_hook('DOKUWIKI_STARTED', 'AFTER', $this, 'addJsinfo'); 20317bdfc2SAndreas Gohr $controller->register_hook('MEDIAMANAGER_STARTED', 'AFTER', $this, 'addJsinfo'); 21317bdfc2SAndreas Gohr $controller->register_hook('DOKUWIKI_STARTED', 'AFTER', $this, 'checkConf'); 222bec1a22SAndreas Gohr $controller->register_hook('AJAX_CALL_UNKNOWN', 'BEFORE', $this, 'handleCache'); 23a5199261SAnna Dabrowska $controller->register_hook('AJAX_CALL_UNKNOWN', 'BEFORE', $this, 'handlePNGDownload'); 242bec1a22SAndreas Gohr 252bec1a22SAndreas Gohr $this->helper = plugin_load('helper', 'diagrams'); 26317bdfc2SAndreas Gohr } 27317bdfc2SAndreas Gohr 28317bdfc2SAndreas Gohr /** 2959e7180eSAndreas Gohr * Add data to JSINFO 30317bdfc2SAndreas Gohr * 3159e7180eSAndreas Gohr * full service URL 3259e7180eSAndreas Gohr * digram mode 3359e7180eSAndreas Gohr * security token used for uploading 3459e7180eSAndreas Gohr * 3559e7180eSAndreas Gohr * @param Doku_Event $event DOKUWIKI_STARTED|MEDIAMANAGER_STARTED 36317bdfc2SAndreas Gohr */ 37317bdfc2SAndreas Gohr public function addJsinfo(Doku_Event $event) 38317bdfc2SAndreas Gohr { 39317bdfc2SAndreas Gohr global $JSINFO; 40317bdfc2SAndreas Gohr $JSINFO['sectok'] = getSecurityToken(); 4159e7180eSAndreas Gohr $JSINFO['plugins']['diagrams'] = [ 4259e7180eSAndreas Gohr 'service_url' => $this->getConf('service_url'), 4359e7180eSAndreas Gohr 'mode' => $this->getConf('mode'), 4459e7180eSAndreas Gohr ]; 45317bdfc2SAndreas Gohr } 46317bdfc2SAndreas Gohr 47317bdfc2SAndreas Gohr /** 48317bdfc2SAndreas Gohr * Check if DokuWiki is properly configured to handle SVG diagrams 49317bdfc2SAndreas Gohr * 5059e7180eSAndreas Gohr * @param Doku_Event $event DOKUWIKI_STARTED 51317bdfc2SAndreas Gohr */ 52317bdfc2SAndreas Gohr public function checkConf(Doku_Event $event) 53317bdfc2SAndreas Gohr { 54317bdfc2SAndreas Gohr $mime = getMimeTypes(); 55317bdfc2SAndreas Gohr if (!array_key_exists('svg', $mime) || $mime['svg'] !== 'image/svg+xml') { 56317bdfc2SAndreas Gohr msg($this->getLang('missingConfig'), -1); 57317bdfc2SAndreas Gohr } 58317bdfc2SAndreas Gohr } 592bec1a22SAndreas Gohr 602bec1a22SAndreas Gohr /** 612bec1a22SAndreas Gohr * Save the PNG cache of a diagram 622bec1a22SAndreas Gohr * 632bec1a22SAndreas Gohr * @param Doku_Event $event AJAX_CALL_UNKNOWN 642bec1a22SAndreas Gohr */ 652bec1a22SAndreas Gohr public function handleCache(Doku_Event $event) 662bec1a22SAndreas Gohr { 672bec1a22SAndreas Gohr if ($event->data !== 'plugin_diagrams_savecache') return; 682bec1a22SAndreas Gohr $event->preventDefault(); 692bec1a22SAndreas Gohr $event->stopPropagation(); 702bec1a22SAndreas Gohr 713039104bSAndreas Gohr // to not further complicate the JavaScript and because creating the PNG is essentially free, 723039104bSAndreas Gohr // we always create the PNG but only save it if the cache is enabled 733039104bSAndreas Gohr if (!$this->getConf('pngcache')) { 743039104bSAndreas Gohr echo 'PNG cache disabled, call ignored'; 753039104bSAndreas Gohr return; 763039104bSAndreas Gohr } 773039104bSAndreas Gohr 782bec1a22SAndreas Gohr global $INPUT; 792bec1a22SAndreas Gohr 802bec1a22SAndreas Gohr $svg = $INPUT->str('svg'); // raw svg 812bec1a22SAndreas Gohr $png = $INPUT->str('png'); // data uri 822bec1a22SAndreas Gohr 832bec1a22SAndreas Gohr if (!checkSecurityToken()) { 842bec1a22SAndreas Gohr http_status(403); 852bec1a22SAndreas Gohr return; 862bec1a22SAndreas Gohr } 872bec1a22SAndreas Gohr 882bec1a22SAndreas Gohr if (!$this->helper->isDiagram($svg)) { 892bec1a22SAndreas Gohr http_status(400); 902bec1a22SAndreas Gohr return; 912bec1a22SAndreas Gohr } 922bec1a22SAndreas Gohr 932bec1a22SAndreas Gohr if (!preg_match('/^data:image\/png;base64,/', $png)) { 942bec1a22SAndreas Gohr http_status(400); 952bec1a22SAndreas Gohr return; 962bec1a22SAndreas Gohr } 972bec1a22SAndreas Gohr $png = base64_decode(explode(',', $png)[1]); 982bec1a22SAndreas Gohr 992bec1a22SAndreas Gohr if (substr($png, 1, 3) !== 'PNG') { 1002bec1a22SAndreas Gohr http_status(400); 1012bec1a22SAndreas Gohr return; 1022bec1a22SAndreas Gohr } 1032bec1a22SAndreas Gohr 1042bec1a22SAndreas Gohr $cacheName = getCacheName($svg, '.diagrams.png'); 1052bec1a22SAndreas Gohr if (io_saveFile($cacheName, $png)) { 1062bec1a22SAndreas Gohr echo 'OK'; 1072bec1a22SAndreas Gohr } else { 1082bec1a22SAndreas Gohr http_status(500); 1092bec1a22SAndreas Gohr } 1102bec1a22SAndreas Gohr } 111a5199261SAnna Dabrowska 112a5199261SAnna Dabrowska /** 113a5199261SAnna Dabrowska * PNG download available via link created in JS (only if PNG caching is enabled) 114a5199261SAnna Dabrowska * 115a5199261SAnna Dabrowska * @param Doku_Event $event 116a5199261SAnna Dabrowska * @return void 117a5199261SAnna Dabrowska */ 118a5199261SAnna Dabrowska public function handlePNGDownload(Doku_Event $event) 119a5199261SAnna Dabrowska { 120a5199261SAnna Dabrowska if ($event->data !== 'plugin_diagrams_pngdownload') return; 121a5199261SAnna Dabrowska $event->preventDefault(); 122a5199261SAnna Dabrowska $event->stopPropagation(); 123a5199261SAnna Dabrowska 124a5199261SAnna Dabrowska global $INPUT; 125a5199261SAnna Dabrowska global $conf; 126a5199261SAnna Dabrowska 127a5199261SAnna Dabrowska $cacheName = $INPUT->str('pngcache'); 128e0dfc516SAnna Dabrowska $media = cleanID($INPUT->str('media')); 129e0dfc516SAnna Dabrowska $id = cleanID($INPUT->str('id')); 130e0dfc516SAnna Dabrowska 131e0dfc516SAnna Dabrowska // check ACLs to original file or page 132e0dfc516SAnna Dabrowska if ( 133e0dfc516SAnna Dabrowska ($id && auth_quickaclcheck($id) < AUTH_READ) || 134e0dfc516SAnna Dabrowska ($media && auth_quickaclcheck($media) < AUTH_READ) 135e0dfc516SAnna Dabrowska ) { 136e0dfc516SAnna Dabrowska http_status(403); 137e0dfc516SAnna Dabrowska return; 138e0dfc516SAnna Dabrowska } 139e0dfc516SAnna Dabrowska 140e0dfc516SAnna Dabrowska // check if download target exists 141e0dfc516SAnna Dabrowska if ( 142e0dfc516SAnna Dabrowska ($id && !page_exists($id)) || 143e0dfc516SAnna Dabrowska ($media && !media_exists($media)) 144e0dfc516SAnna Dabrowska ) { 145e0dfc516SAnna Dabrowska http_status(404); 146e0dfc516SAnna Dabrowska return; 147e0dfc516SAnna Dabrowska } 148a5199261SAnna Dabrowska 149a5199261SAnna Dabrowska // serve cached PNG file 150e0dfc516SAnna Dabrowska $file = $conf['cachedir'] . $cacheName . \dokuwiki\plugin\diagrams\Diagrams::CACHE_EXT; 151a5199261SAnna Dabrowska if (file_exists($file)) { 152e0dfc516SAnna Dabrowska // correct file extension 153e0dfc516SAnna Dabrowska $download = $media ? str_replace('.svg', '.png', $media) : $id . ".png"; 154*5fbec2e8SAnna Dabrowska $download = noNS($download); 155a5199261SAnna Dabrowska header('Content-Type: image/png'); 156e0dfc516SAnna Dabrowska header("Content-Disposition: attachment; filename=$download;"); 157a5199261SAnna Dabrowska http_sendfile($file); 158a5199261SAnna Dabrowska readfile($file); 159*5fbec2e8SAnna Dabrowska } else { 160*5fbec2e8SAnna Dabrowska http_status(404); 161a5199261SAnna Dabrowska } 162a5199261SAnna Dabrowska } 163317bdfc2SAndreas Gohr} 164