xref: /plugin/diagrams/action/action.php (revision 5fbec2e8ebc7d19ba8b16d80014a9287683a78c5)
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