xref: /plugin/imgpaste/action.php (revision 832cd16116fe537c83226c44e00a234c7389f636)
1<?php
2
3/**
4 * DokuWiki Plugin imgpaste (Action Component)
5 *
6 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
7 * @author  Andreas Gohr <gohr@cosmocode.de>
8 */
9class action_plugin_imgpaste extends DokuWiki_Action_Plugin
10{
11
12    private $tempdir = '';
13    private $tempfile = '';
14
15    /** @inheritdoc */
16    public function register(Doku_Event_Handler $controller)
17    {
18        $controller->register_hook('AJAX_CALL_UNKNOWN', 'BEFORE', $this, 'handleAjaxUpload');
19    }
20
21    /**
22     * Creates a new file from the given data URL
23     *
24     * @param Doku_Event $event AJAX_CALL_UNKNOWN
25     */
26    public function handleAjaxUpload(Doku_Event $event)
27    {
28        if ($event->data != 'plugin_imgpaste') return;
29        global $lang;
30
31        // get data
32        global $INPUT;
33        $data = $INPUT->post->str('data');
34        list($type, $data) = explode(';', $data);
35        if (!$data) $this->fail(400, $this->getLang('e_nodata'));
36
37        // process data encoding
38        $type = strtolower(substr($type, 5)); // strip 'data:' prefix
39        $data = substr($data, 7); // strip 'base64,' prefix
40        $data = base64_decode($data);
41
42        // check for supported mime type
43        $mimetypes = array_flip(getMimeTypes());
44        if (!isset($mimetypes[$type])) $this->fail(415, $lang['uploadwrong']);
45
46        // prepare file names
47        $tempname = $this->storetemp($data);
48        $filename = $this->getConf('filename');
49        $filename = str_replace(
50            [
51                '@NS@',
52                '@ID@',
53                '@USER@',
54                '@PAGE@',
55            ],
56            [
57                getNS($INPUT->post->str('id')),
58                $INPUT->post->str('id'),
59                $_SERVER['REMOTE_USER'],
60                noNS($INPUT->post->str('id')),
61            ],
62            $filename
63        );
64        $filename = strftime($filename);
65        $filename .= '.' . $mimetypes[$type];
66        $filename = cleanID($filename);
67
68        // check ACLs
69        $auth = auth_quickaclcheck($filename);
70        if ($auth < AUTH_UPLOAD) $this->fail(403, $lang['uploadfail']);
71
72        // do the actual saving
73        $result = media_save(
74            array(
75                'name' => $tempname,
76                'mime' => $type,
77                'ext' => $mimetypes[$type],
78            ),
79            $filename,
80            false,
81            $auth,
82            'copy'
83        );
84        if (is_array($result)) $this->fail(500, $result[0]);
85
86        //Still here? We had a successful upload
87        $this->clean();
88        header('Content-Type: application/json');
89        echo json_encode([
90            'message' => $lang['uploadsucc'],
91            'id' => $result,
92            'mime' => $type,
93            'ext' => $mimetypes[$type],
94            'url' => ml($result),
95        ]);
96
97        $event->preventDefault();
98        $event->stopPropagation();
99    }
100
101    /**
102     * Create a temporary file from the given data
103     *
104     * exits if an error occurs
105     *
106     * @param $data
107     * @return string
108     */
109    private function storetemp($data)
110    {
111        // store in temporary file
112        $this->tempdir = io_mktmpdir();
113        if (!$this->tempdir) $this->fail(500);
114        $this->tempfile = $this->tempdir . '/' . md5($data);
115        if (!io_saveFile($this->tempfile, $data)) $this->fail(500);
116        return $this->tempfile;
117    }
118
119    /**
120     * remove temporary file and directory
121     */
122    private function clean()
123    {
124        if ($this->tempfile && file_exists($this->tempfile)) @unlink($this->tempfile);
125        if ($this->tempdir && is_dir($this->tempdir)) @rmdir($this->tempdir);
126        $this->tempfile = '';
127        $this->tempdir = '';
128    }
129
130    /**
131     * End the execution with a HTTP error code
132     *
133     * Calls clean
134     *
135     * @param int $status HTTP status code
136     * @param string $text
137     */
138    private function fail($status, $text = '')
139    {
140        $this->clean();
141        http_status($status, $text);
142        exit;
143    }
144}
145