14df872e4SAndreas Gohr<?php 2832cd161SAndreas Gohr 3*8f17bdb9SAndreas Gohruse dokuwiki\Extension\ActionPlugin; 4*8f17bdb9SAndreas Gohruse dokuwiki\Extension\Event; 5*8f17bdb9SAndreas Gohruse dokuwiki\Extension\EventHandler; 6*8f17bdb9SAndreas Gohruse dokuwiki\plugin\imgpaste\Exception as PasteException; 7*8f17bdb9SAndreas Gohr 84df872e4SAndreas Gohr/** 94df872e4SAndreas Gohr * DokuWiki Plugin imgpaste (Action Component) 104df872e4SAndreas Gohr * 114df872e4SAndreas Gohr * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 124df872e4SAndreas Gohr * @author Andreas Gohr <gohr@cosmocode.de> 134df872e4SAndreas Gohr */ 14*8f17bdb9SAndreas Gohrclass action_plugin_imgpaste extends ActionPlugin 15832cd161SAndreas Gohr{ 164df872e4SAndreas Gohr 17584f4635SAndreas Gohr protected $tempdir = ''; 18584f4635SAndreas Gohr protected $tempfile = ''; 19584f4635SAndreas Gohr 20584f4635SAndreas Gohr /** 21584f4635SAndreas Gohr * Clean up on destruction 22584f4635SAndreas Gohr */ 23584f4635SAndreas Gohr public function __destruct() 24584f4635SAndreas Gohr { 25584f4635SAndreas Gohr $this->clean(); 26584f4635SAndreas Gohr } 274df872e4SAndreas Gohr 28832cd161SAndreas Gohr /** @inheritdoc */ 29*8f17bdb9SAndreas Gohr public function register(EventHandler $controller) 30832cd161SAndreas Gohr { 31832cd161SAndreas Gohr $controller->register_hook('AJAX_CALL_UNKNOWN', 'BEFORE', $this, 'handleAjaxUpload'); 324df872e4SAndreas Gohr } 334df872e4SAndreas Gohr 34*8f17bdb9SAndreas Gohr 35832cd161SAndreas Gohr /** 36832cd161SAndreas Gohr * Creates a new file from the given data URL 37832cd161SAndreas Gohr * 38*8f17bdb9SAndreas Gohr * @param Event $event AJAX_CALL_UNKNOWN 39832cd161SAndreas Gohr */ 40*8f17bdb9SAndreas Gohr public function handleAjaxUpload(Event $event) 41832cd161SAndreas Gohr { 424df872e4SAndreas Gohr if ($event->data != 'plugin_imgpaste') return; 43*8f17bdb9SAndreas Gohr $event->preventDefault(); 44*8f17bdb9SAndreas Gohr $event->stopPropagation(); 454df872e4SAndreas Gohr 464df872e4SAndreas Gohr global $INPUT; 47*8f17bdb9SAndreas Gohr try { 48*8f17bdb9SAndreas Gohr if ($INPUT->has('url')) { 49*8f17bdb9SAndreas Gohr [$data, $type] = $this->externalUrlToData($INPUT->post->str('url')); 50*8f17bdb9SAndreas Gohr } else { 51*8f17bdb9SAndreas Gohr [$data, $type] = $this->dataUrlToData($INPUT->post->str('data')); 52*8f17bdb9SAndreas Gohr } 53*8f17bdb9SAndreas Gohr $result = $this->storeImage($data, $type); 54*8f17bdb9SAndreas Gohr } catch (PasteException $e) { 55*8f17bdb9SAndreas Gohr $this->clean(); 56*8f17bdb9SAndreas Gohr http_status($e->getCode(), $e->getMessage()); 57*8f17bdb9SAndreas Gohr exit; 58*8f17bdb9SAndreas Gohr } 59*8f17bdb9SAndreas Gohr 60*8f17bdb9SAndreas Gohr header('Content-Type: application/json'); 61*8f17bdb9SAndreas Gohr echo json_encode($result); 62*8f17bdb9SAndreas Gohr } 63*8f17bdb9SAndreas Gohr 64*8f17bdb9SAndreas Gohr /** 65*8f17bdb9SAndreas Gohr * Get the binary data and mime type from a data URL 66*8f17bdb9SAndreas Gohr * 67*8f17bdb9SAndreas Gohr * @param string $dataUrl 68*8f17bdb9SAndreas Gohr * @return array [data, type] 69*8f17bdb9SAndreas Gohr * @throws PasteException 70*8f17bdb9SAndreas Gohr */ 71*8f17bdb9SAndreas Gohr protected function dataUrlToData($dataUrl) 72*8f17bdb9SAndreas Gohr { 73*8f17bdb9SAndreas Gohr list($type, $data) = explode(';', $dataUrl); 74*8f17bdb9SAndreas Gohr if (!$data) throw new PasteException($this->getLang('e_nodata'), 400); 754df872e4SAndreas Gohr 764df872e4SAndreas Gohr // process data encoding 774df872e4SAndreas Gohr $type = strtolower(substr($type, 5)); // strip 'data:' prefix 784df872e4SAndreas Gohr $data = substr($data, 7); // strip 'base64,' prefix 794df872e4SAndreas Gohr $data = base64_decode($data); 80*8f17bdb9SAndreas Gohr return [$data, $type]; 81*8f17bdb9SAndreas Gohr } 82*8f17bdb9SAndreas Gohr 83*8f17bdb9SAndreas Gohr /** 84*8f17bdb9SAndreas Gohr * Download the file from an external URL 85*8f17bdb9SAndreas Gohr * 86*8f17bdb9SAndreas Gohr * @param string $externalUrl 87*8f17bdb9SAndreas Gohr * @return array [data, type] 88*8f17bdb9SAndreas Gohr * @throws PasteException 89*8f17bdb9SAndreas Gohr */ 90*8f17bdb9SAndreas Gohr protected function externalUrlToData($externalUrl) 91*8f17bdb9SAndreas Gohr { 92*8f17bdb9SAndreas Gohr global $lang; 93*8f17bdb9SAndreas Gohr 94*8f17bdb9SAndreas Gohr // download the file 95*8f17bdb9SAndreas Gohr $http = new \dokuwiki\HTTP\DokuHTTPClient(); 96*8f17bdb9SAndreas Gohr $data = $http->get($externalUrl); 97*8f17bdb9SAndreas Gohr if (!$data) throw new PasteException($lang['uploadfail'], 500); 98*8f17bdb9SAndreas Gohr [$type] = explode(';', $http->resp_headers['content-type']); 99*8f17bdb9SAndreas Gohr return [$data, $type]; 100*8f17bdb9SAndreas Gohr } 101*8f17bdb9SAndreas Gohr 102*8f17bdb9SAndreas Gohr /** 103*8f17bdb9SAndreas Gohr * @throws PasteException 104*8f17bdb9SAndreas Gohr */ 105*8f17bdb9SAndreas Gohr protected function storeImage($data, $type) 106*8f17bdb9SAndreas Gohr { 107*8f17bdb9SAndreas Gohr global $lang; 108*8f17bdb9SAndreas Gohr global $INPUT; 1094df872e4SAndreas Gohr 1104df872e4SAndreas Gohr // check for supported mime type 1114df872e4SAndreas Gohr $mimetypes = array_flip(getMimeTypes()); 112*8f17bdb9SAndreas Gohr if (!isset($mimetypes[$type])) throw new PasteException($lang['uploadwrong'], 415); 1134df872e4SAndreas Gohr 1144df872e4SAndreas Gohr // prepare file names 1154df872e4SAndreas Gohr $tempname = $this->storetemp($data); 116584f4635SAndreas Gohr $filename = $this->createFileName($INPUT->post->str('id'), $mimetypes[$type], $_SERVER['REMOTE_USER']); 1174df872e4SAndreas Gohr 1184df872e4SAndreas Gohr // check ACLs 1194df872e4SAndreas Gohr $auth = auth_quickaclcheck($filename); 120*8f17bdb9SAndreas Gohr if ($auth < AUTH_UPLOAD) throw new PasteException($lang['uploadfail'], 403); 1214df872e4SAndreas Gohr 1224df872e4SAndreas Gohr // do the actual saving 1234df872e4SAndreas Gohr $result = media_save( 124584f4635SAndreas Gohr [ 1254df872e4SAndreas Gohr 'name' => $tempname, 1264df872e4SAndreas Gohr 'mime' => $type, 127832cd161SAndreas Gohr 'ext' => $mimetypes[$type], 128584f4635SAndreas Gohr ], 1294df872e4SAndreas Gohr $filename, 1304df872e4SAndreas Gohr false, 1314df872e4SAndreas Gohr $auth, 1324df872e4SAndreas Gohr 'copy' 1334df872e4SAndreas Gohr ); 134*8f17bdb9SAndreas Gohr if (is_array($result)) throw new PasteException($result[0], 500); 1354df872e4SAndreas Gohr 1364df872e4SAndreas Gohr //Still here? We had a successful upload 1374df872e4SAndreas Gohr $this->clean(); 138*8f17bdb9SAndreas Gohr return [ 1394df872e4SAndreas Gohr 'message' => $lang['uploadsucc'], 140832cd161SAndreas Gohr 'id' => $result, 141832cd161SAndreas Gohr 'mime' => $type, 142832cd161SAndreas Gohr 'ext' => $mimetypes[$type], 143832cd161SAndreas Gohr 'url' => ml($result), 144*8f17bdb9SAndreas Gohr ]; 1454df872e4SAndreas Gohr } 1464df872e4SAndreas Gohr 1474df872e4SAndreas Gohr /** 148584f4635SAndreas Gohr * Create the filename for the new file 149584f4635SAndreas Gohr * 150584f4635SAndreas Gohr * @param string $pageid the original page the paste event happend on 151584f4635SAndreas Gohr * @param string $ext the extension of the file 152584f4635SAndreas Gohr * @param string $user the currently logged in user 153584f4635SAndreas Gohr * @return string 154584f4635SAndreas Gohr */ 155584f4635SAndreas Gohr protected function createFileName($pageid, $ext, $user) 156584f4635SAndreas Gohr { 157*8f17bdb9SAndreas Gohr $unique = ''; 158584f4635SAndreas Gohr $filename = $this->getConf('filename'); 159584f4635SAndreas Gohr $filename = str_replace( 160584f4635SAndreas Gohr [ 161584f4635SAndreas Gohr '@NS@', 162584f4635SAndreas Gohr '@ID@', 163584f4635SAndreas Gohr '@USER@', 164584f4635SAndreas Gohr '@PAGE@', 165584f4635SAndreas Gohr ], 166584f4635SAndreas Gohr [ 167584f4635SAndreas Gohr getNS($pageid), 168584f4635SAndreas Gohr $pageid, 169584f4635SAndreas Gohr $user, 170584f4635SAndreas Gohr noNS($pageid), 171584f4635SAndreas Gohr ], 172584f4635SAndreas Gohr $filename 173584f4635SAndreas Gohr ); 174584f4635SAndreas Gohr $filename = strftime($filename); 175*8f17bdb9SAndreas Gohr $filename = cleanID($filename); 176*8f17bdb9SAndreas Gohr while (media_exists($filename . $unique . '.' . $ext)) { 177*8f17bdb9SAndreas Gohr $unique = (int)$unique + 1; 178*8f17bdb9SAndreas Gohr } 179*8f17bdb9SAndreas Gohr return $filename . $unique . '.' . $ext; 180584f4635SAndreas Gohr } 181584f4635SAndreas Gohr 182584f4635SAndreas Gohr /** 1834df872e4SAndreas Gohr * Create a temporary file from the given data 1844df872e4SAndreas Gohr * 1854df872e4SAndreas Gohr * exits if an error occurs 1864df872e4SAndreas Gohr * 1874df872e4SAndreas Gohr * @param $data 1884df872e4SAndreas Gohr * @return string 1894df872e4SAndreas Gohr */ 190584f4635SAndreas Gohr protected function storetemp($data) 191832cd161SAndreas Gohr { 1924df872e4SAndreas Gohr // store in temporary file 1934df872e4SAndreas Gohr $this->tempdir = io_mktmpdir(); 194*8f17bdb9SAndreas Gohr if (!$this->tempdir) throw new PasteException('', 500); 1954df872e4SAndreas Gohr $this->tempfile = $this->tempdir . '/' . md5($data); 196*8f17bdb9SAndreas Gohr if (!io_saveFile($this->tempfile, $data)) throw new PasteException('', 500); 1974df872e4SAndreas Gohr return $this->tempfile; 1984df872e4SAndreas Gohr } 1994df872e4SAndreas Gohr 2004df872e4SAndreas Gohr /** 2014df872e4SAndreas Gohr * remove temporary file and directory 2024df872e4SAndreas Gohr */ 203584f4635SAndreas Gohr protected function clean() 204832cd161SAndreas Gohr { 2054df872e4SAndreas Gohr if ($this->tempfile && file_exists($this->tempfile)) @unlink($this->tempfile); 2064df872e4SAndreas Gohr if ($this->tempdir && is_dir($this->tempdir)) @rmdir($this->tempdir); 2074df872e4SAndreas Gohr $this->tempfile = ''; 2084df872e4SAndreas Gohr $this->tempdir = ''; 2094df872e4SAndreas Gohr } 2104df872e4SAndreas Gohr 2114df872e4SAndreas Gohr} 212