xref: /plugin/diagrams/action/action.php (revision a5199261c250645da37291dbb742beb5c2e8f840)
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        $downloadName = $INPUT->str('filename');
129
130        // serve cached PNG file
131        $file = $conf['cachedir'] . $cacheName;
132        if (file_exists($file)) {
133            header('Content-Type: image/png');
134            header("Content-Disposition: attachment; filename=$downloadName;");
135            http_sendfile($file);
136            readfile($file);
137        }
138        exit();
139    }
140}
141