xref: /dokuwiki/inc/media.php (revision 24870174d2ee45460ba6bcfe5f5a0ae94715efd7)
13df72098SAndreas Gohr<?php
23df72098SAndreas Gohr/**
33df72098SAndreas Gohr * All output and handler function needed for the media management popup
43df72098SAndreas Gohr *
53df72098SAndreas Gohr * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
63df72098SAndreas Gohr * @author     Andreas Gohr <andi@splitbrain.org>
73df72098SAndreas Gohr */
8*24870174SAndreas Gohruse dokuwiki\Ui\MediaRevisions;
9*24870174SAndreas Gohruse dokuwiki\Cache\CacheImageMod;
10*24870174SAndreas Gohruse splitbrain\slika\Exception;
11*24870174SAndreas Gohruse dokuwiki\PassHash;
120c3a5702SAndreas Gohruse dokuwiki\ChangeLog\MediaChangeLog;
13b021f0b4SAndreas Gohruse dokuwiki\Extension\Event;
14b021f0b4SAndreas Gohruse dokuwiki\Form\Form;
155a8d6e48SMichael Großeuse dokuwiki\HTTP\DokuHTTPClient;
1679a2d784SGerrit Uitslaguse dokuwiki\Logger;
17704a815fSMichael Großeuse dokuwiki\Subscriptions\MediaSubscriptionSender;
1879a2d784SGerrit Uitslaguse dokuwiki\Ui\Media\DisplayRow;
1979a2d784SGerrit Uitslaguse dokuwiki\Ui\Media\DisplayTile;
2079a2d784SGerrit Uitslaguse dokuwiki\Ui\MediaDiff;
2179a2d784SGerrit Uitslaguse dokuwiki\Utf8\PhpString;
222d85e841SAndreas Gohruse dokuwiki\Utf8\Sort;
2379a2d784SGerrit Uitslaguse splitbrain\slika\Slika;
240c3a5702SAndreas Gohr
253df72098SAndreas Gohr/**
263df72098SAndreas Gohr * Lists pages which currently use a media file selected for deletion
273df72098SAndreas Gohr *
283df72098SAndreas Gohr * References uses the same visual as search results and share
293df72098SAndreas Gohr * their CSS tags except pagenames won't be links.
303df72098SAndreas Gohr *
313df72098SAndreas Gohr * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
3242ea7f44SGerrit Uitslag *
3342ea7f44SGerrit Uitslag * @param array $data
3442ea7f44SGerrit Uitslag * @param string $id
353df72098SAndreas Gohr */
363df72098SAndreas Gohrfunction media_filesinuse($data,$id){
373df72098SAndreas Gohr    global $lang;
383df72098SAndreas Gohr    echo '<h1>'.$lang['reference'].' <code>'.hsc(noNS($id)).'</code></h1>';
393df72098SAndreas Gohr    echo '<p>'.hsc($lang['ref_inuse']).'</p>';
403df72098SAndreas Gohr
413df72098SAndreas Gohr    $hidden=0; //count of hits without read permission
423df72098SAndreas Gohr    foreach($data as $row){
43a05e297aSAndreas Gohr        if(auth_quickaclcheck($row) >= AUTH_READ && isVisiblePage($row)){
443df72098SAndreas Gohr            echo '<div class="search_result">';
45a05e297aSAndreas Gohr            echo '<span class="mediaref_ref">'.hsc($row).'</span>';
463df72098SAndreas Gohr            echo '</div>';
473df72098SAndreas Gohr        }else
483df72098SAndreas Gohr            $hidden++;
493df72098SAndreas Gohr    }
503df72098SAndreas Gohr    if ($hidden){
513df72098SAndreas Gohr        print '<div class="mediaref_hidden">'.$lang['ref_hidden'].'</div>';
523df72098SAndreas Gohr    }
533df72098SAndreas Gohr}
543df72098SAndreas Gohr
553df72098SAndreas Gohr/**
563df72098SAndreas Gohr * Handles the saving of image meta data
573df72098SAndreas Gohr *
583df72098SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org>
59cf832786SKate Arzamastseva * @author Kate Arzamastseva <pshns@ukr.net>
60e0c26282SGerrit Uitslag *
61e0c26282SGerrit Uitslag * @param string $id media id
62e0c26282SGerrit Uitslag * @param int $auth permission level
63e0c26282SGerrit Uitslag * @param array $data
6442ea7f44SGerrit Uitslag * @return false|string
653df72098SAndreas Gohr */
663df72098SAndreas Gohrfunction media_metasave($id,$auth,$data){
673df72098SAndreas Gohr    if($auth < AUTH_UPLOAD) return false;
68f2ea8432SAndreas Gohr    if(!checkSecurityToken()) return false;
693df72098SAndreas Gohr    global $lang;
700b308644SOtto Vainio    global $conf;
713df72098SAndreas Gohr    $src = mediaFN($id);
723df72098SAndreas Gohr
733df72098SAndreas Gohr    $meta = new JpegMeta($src);
743df72098SAndreas Gohr    $meta->_parseAll();
753df72098SAndreas Gohr
763df72098SAndreas Gohr    foreach($data as $key => $val){
773df72098SAndreas Gohr        $val=trim($val);
783df72098SAndreas Gohr        if(empty($val)){
793df72098SAndreas Gohr            $meta->deleteField($key);
803df72098SAndreas Gohr        }else{
813df72098SAndreas Gohr            $meta->setField($key,$val);
823df72098SAndreas Gohr        }
833df72098SAndreas Gohr    }
843df72098SAndreas Gohr
85cf832786SKate Arzamastseva    $old = @filemtime($src);
8679e79377SAndreas Gohr    if(!file_exists(mediaFN($id, $old)) && file_exists($src)) {
87cf832786SKate Arzamastseva        // add old revision to the attic
88cf832786SKate Arzamastseva        media_saveOldRevision($id);
89cf832786SKate Arzamastseva    }
90ac3ed4afSGerrit Uitslag    $filesize_old = filesize($src);
913df72098SAndreas Gohr    if($meta->save()){
920b308644SOtto Vainio        if($conf['fperm']) chmod($src, $conf['fperm']);
93ac3ed4afSGerrit Uitslag        @clearstatcache(true, $src);
94cf832786SKate Arzamastseva        $new = @filemtime($src);
95ac3ed4afSGerrit Uitslag        $filesize_new = filesize($src);
96ac3ed4afSGerrit Uitslag        $sizechange = $filesize_new - $filesize_old;
97ac3ed4afSGerrit Uitslag
98cf832786SKate Arzamastseva        // add a log entry to the media changelog
99ac3ed4afSGerrit Uitslag        addMediaLogEntry($new, $id, DOKU_CHANGE_TYPE_EDIT, $lang['media_meta_edited'], '', null, $sizechange);
100cf832786SKate Arzamastseva
1013df72098SAndreas Gohr        msg($lang['metasaveok'],1);
1023df72098SAndreas Gohr        return $id;
1033df72098SAndreas Gohr    }else{
1043df72098SAndreas Gohr        msg($lang['metasaveerr'],-1);
1053df72098SAndreas Gohr        return false;
1063df72098SAndreas Gohr    }
1073df72098SAndreas Gohr}
1083df72098SAndreas Gohr
1093df72098SAndreas Gohr/**
110d54f7963SKlap-in * check if a media is external source
111d54f7963SKlap-in *
112d54f7963SKlap-in * @author Gerrit Uitslag <klapinklapin@gmail.com>
11342ea7f44SGerrit Uitslag *
114d54f7963SKlap-in * @param string $id the media ID or URL
115d54f7963SKlap-in * @return bool
116d54f7963SKlap-in */
117d54f7963SKlap-infunction media_isexternal($id){
118fe578fe9SElan Ruusamäe    if (preg_match('#^(?:https?|ftp)://#i', $id)) return true;
119d54f7963SKlap-in    return false;
120d54f7963SKlap-in}
121d54f7963SKlap-in
122d54f7963SKlap-in/**
123add8678fSAndreas Gohr * Check if a media item is public (eg, external URL or readable by @ALL)
124add8678fSAndreas Gohr *
125add8678fSAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org>
12642ea7f44SGerrit Uitslag *
127add8678fSAndreas Gohr * @param string $id  the media ID or URL
128add8678fSAndreas Gohr * @return bool
129add8678fSAndreas Gohr */
130add8678fSAndreas Gohrfunction media_ispublic($id){
131d54f7963SKlap-in    if(media_isexternal($id)) return true;
132add8678fSAndreas Gohr    $id = cleanID($id);
133*24870174SAndreas Gohr    if(auth_aclcheck(getNS($id).':*', '', []) >= AUTH_READ) return true;
134add8678fSAndreas Gohr    return false;
135add8678fSAndreas Gohr}
136add8678fSAndreas Gohr
137add8678fSAndreas Gohr/**
1383df72098SAndreas Gohr * Display the form to edit image meta data
1393df72098SAndreas Gohr *
1403df72098SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org>
141d9162c6cSKate Arzamastseva * @author Kate Arzamastseva <pshns@ukr.net>
142e0c26282SGerrit Uitslag *
143e0c26282SGerrit Uitslag * @param string $id media id
144e0c26282SGerrit Uitslag * @param int $auth permission level
145e0c26282SGerrit Uitslag * @return bool
1463df72098SAndreas Gohr */
14730fd72fbSKate Arzamastsevafunction media_metaform($id, $auth) {
148ebc28e69SAndreas Gohr    global $lang;
1493df72098SAndreas Gohr
15088a71175SKate Arzamastseva    if ($auth < AUTH_UPLOAD) {
151b960c74fSSatoshi Sahara        echo '<div class="nothing">'.$lang['media_perm_upload'].'</div>'.DOKU_LF;
15288a71175SKate Arzamastseva        return false;
15388a71175SKate Arzamastseva    }
15488a71175SKate Arzamastseva
1553df72098SAndreas Gohr    // load the field descriptions
1563df72098SAndreas Gohr    static $fields = null;
157b960c74fSSatoshi Sahara    if ($fields === null) {
1583e98e685SKate Arzamastseva        $config_files = getConfigFiles('mediameta');
1593e98e685SKate Arzamastseva        foreach ($config_files as $config_file) {
16079e79377SAndreas Gohr            if (file_exists($config_file)) include($config_file);
1613df72098SAndreas Gohr        }
1623df72098SAndreas Gohr    }
1633df72098SAndreas Gohr
1643df72098SAndreas Gohr    $src = mediaFN($id);
1653df72098SAndreas Gohr
1663df72098SAndreas Gohr    // output
167b960c74fSSatoshi Sahara    $form = new Form([
168b960c74fSSatoshi Sahara            'action' => media_managerURL(['tab_details' => 'view'], '&'),
169b960c74fSSatoshi Sahara            'class' => 'meta'
170b960c74fSSatoshi Sahara    ]);
171b960c74fSSatoshi Sahara    $form->addTagOpen('div')->addClass('no');
172b960c74fSSatoshi Sahara    $form->setHiddenField('img', $id);
173b960c74fSSatoshi Sahara    $form->setHiddenField('mediado', 'save');
1743df72098SAndreas Gohr    foreach ($fields as $key => $field) {
1753df72098SAndreas Gohr        // get current value
1763e98e685SKate Arzamastseva        if (empty($field[0])) continue;
177*24870174SAndreas Gohr        $tags = [$field[0]];
1783df72098SAndreas Gohr        if (is_array($field[3])) $tags = array_merge($tags, $field[3]);
1793df72098SAndreas Gohr        $value = tpl_img_getTag($tags, '', $src);
180ca6a0701SAndreas Gohr        $value = cleanText($value);
1813df72098SAndreas Gohr
1823df72098SAndreas Gohr        // prepare attributes
183*24870174SAndreas Gohr        $p = [
184b960c74fSSatoshi Sahara            'class' => 'edit',
185b960c74fSSatoshi Sahara            'id'    => 'meta__'.$key,
186*24870174SAndreas Gohr            'name'  => 'meta['.$field[0].']'
187*24870174SAndreas Gohr        ];
1883df72098SAndreas Gohr
189b960c74fSSatoshi Sahara        $form->addTagOpen('div')->addClass('row');
1903df72098SAndreas Gohr        if ($field[2] == 'text') {
191bde2a644SSatoshi Sahara            $form->addTextInput(
19264159a61SAndreas Gohr                $p['name'],
19379a2d784SGerrit Uitslag                ($lang[$field[1]] ?: $field[1] . ':')
194b960c74fSSatoshi Sahara            )->id($p['id'])->addClass($p['class'])->val($value);
1953df72098SAndreas Gohr        } else {
196b960c74fSSatoshi Sahara            $form->addTextarea($p['name'], $lang[$field[1]])->id($p['id'])
197b960c74fSSatoshi Sahara                ->val(formText($value))
198b960c74fSSatoshi Sahara                ->addClass($p['class'])
199b960c74fSSatoshi Sahara                ->attr('rows', '6')->attr('cols', '50');
2003df72098SAndreas Gohr        }
201b960c74fSSatoshi Sahara        $form->addTagClose('div');
2023df72098SAndreas Gohr    }
203b960c74fSSatoshi Sahara    $form->addTagOpen('div')->addClass('buttons');
204b960c74fSSatoshi Sahara    $form->addButton('mediado[save]', $lang['btn_save'])->attr('type', 'submit')
205b960c74fSSatoshi Sahara        ->attrs(['accesskey' => 's']);
206b960c74fSSatoshi Sahara    $form->addTagClose('div');
207ebc28e69SAndreas Gohr
208b960c74fSSatoshi Sahara    $form->addTagClose('div');
209b960c74fSSatoshi Sahara    echo $form->toHTML();
210ebc28e69SAndreas Gohr    return true;
2113df72098SAndreas Gohr}
2123df72098SAndreas Gohr
213666cdec5SMichael Klier/**
21487229c84SAdrian Lang * Convenience function to check if a media file is still in use
215666cdec5SMichael Klier *
216666cdec5SMichael Klier * @author Michael Klier <chi@chimeric.de>
217e0c26282SGerrit Uitslag *
218e0c26282SGerrit Uitslag * @param string $id media id
219e0c26282SGerrit Uitslag * @return array|bool
220666cdec5SMichael Klier */
221666cdec5SMichael Klierfunction media_inuse($id) {
222666cdec5SMichael Klier    global $conf;
223ebc28e69SAndreas Gohr
224666cdec5SMichael Klier    if($conf['refcheck']){
225ffec1009SMichael Hamann        $mediareferences = ft_mediause($id,true);
226*24870174SAndreas Gohr        if($mediareferences === []) {
2276dae2464SAndreas Gohr            return false;
228666cdec5SMichael Klier        } else {
229666cdec5SMichael Klier            return $mediareferences;
230666cdec5SMichael Klier        }
231666cdec5SMichael Klier    } else {
232666cdec5SMichael Klier        return false;
233666cdec5SMichael Klier    }
234666cdec5SMichael Klier}
235a05e297aSAndreas Gohr
2363df72098SAndreas Gohr/**
2373df72098SAndreas Gohr * Handles media file deletions
2383df72098SAndreas Gohr *
2393df72098SAndreas Gohr * If configured, checks for media references before deletion
2403df72098SAndreas Gohr *
2413df72098SAndreas Gohr * @author             Andreas Gohr <andi@splitbrain.org>
24242ea7f44SGerrit Uitslag *
243ebc28e69SAndreas Gohr * @param string $id media id
24422db8df7SAndreas Gohr * @param int $auth no longer used
24587229c84SAdrian Lang * @return int One of: 0,
24663703ba5SAndreas Gohr *                     DOKU_MEDIA_DELETED,
24763703ba5SAndreas Gohr *                     DOKU_MEDIA_DELETED | DOKU_MEDIA_EMPTY_NS,
24863703ba5SAndreas Gohr *                     DOKU_MEDIA_NOT_AUTH,
24963703ba5SAndreas Gohr *                     DOKU_MEDIA_INUSE
2503df72098SAndreas Gohr */
2513df72098SAndreas Gohrfunction media_delete($id,$auth){
2526183fb05SKate Arzamastseva    global $lang;
253ff04e8b7SAndreas Gohr    $auth = auth_quickaclcheck(ltrim(getNS($id).':*', ':'));
25487229c84SAdrian Lang    if($auth < AUTH_DELETE) return DOKU_MEDIA_NOT_AUTH;
25587229c84SAdrian Lang    if(media_inuse($id)) return DOKU_MEDIA_INUSE;
2563df72098SAndreas Gohr
2573df72098SAndreas Gohr    $file = mediaFN($id);
2584a961e72SMichal Kolodziejski
2594a961e72SMichal Kolodziejski    // trigger an event - MEDIA_DELETE_FILE
260*24870174SAndreas Gohr    $data = [];
261666cdec5SMichael Klier    $data['id']   = $id;
26279a2d784SGerrit Uitslag    $data['name'] = PhpString::basename($file);
2634a961e72SMichal Kolodziejski    $data['path'] = $file;
26479e79377SAndreas Gohr    $data['size'] = (file_exists($file)) ? filesize($file) : 0;
265666cdec5SMichael Klier
266666cdec5SMichael Klier    $data['unl'] = false;
267666cdec5SMichael Klier    $data['del'] = false;
268e1d9dcc8SAndreas Gohr    $evt = new Event('MEDIA_DELETE_FILE',$data);
2694a961e72SMichal Kolodziejski    if ($evt->advise_before()) {
2706183fb05SKate Arzamastseva        $old = @filemtime($file);
27179e79377SAndreas Gohr        if(!file_exists(mediaFN($id, $old)) && file_exists($file)) {
2726183fb05SKate Arzamastseva            // add old revision to the attic
2736183fb05SKate Arzamastseva            media_saveOldRevision($id);
2746183fb05SKate Arzamastseva        }
2756183fb05SKate Arzamastseva
276666cdec5SMichael Klier        $data['unl'] = @unlink($file);
277666cdec5SMichael Klier        if($data['unl']) {
278ac3ed4afSGerrit Uitslag            $sizechange = 0 - $data['size'];
279ac3ed4afSGerrit Uitslag            addMediaLogEntry(time(), $id, DOKU_CHANGE_TYPE_DELETE, $lang['deleted'], '', null, $sizechange);
280ac3ed4afSGerrit Uitslag
281666cdec5SMichael Klier            $data['del'] = io_sweepNS($id, 'mediadir');
2823df72098SAndreas Gohr        }
2834a961e72SMichal Kolodziejski    }
2844a961e72SMichal Kolodziejski    $evt->advise_after();
2854a961e72SMichal Kolodziejski    unset($evt);
2864a961e72SMichal Kolodziejski
287666cdec5SMichael Klier    if($data['unl'] && $data['del']){
28887229c84SAdrian Lang        return DOKU_MEDIA_DELETED | DOKU_MEDIA_EMPTY_NS;
2893df72098SAndreas Gohr    }
2903df72098SAndreas Gohr
29187229c84SAdrian Lang    return $data['unl'] ? DOKU_MEDIA_DELETED : 0;
2923df72098SAndreas Gohr}
2933df72098SAndreas Gohr
2943df72098SAndreas Gohr/**
2952d6cc64fSKate Arzamastseva * Handle file uploads via XMLHttpRequest
2962d6cc64fSKate Arzamastseva *
297ebc28e69SAndreas Gohr * @param string $ns   target namespace
298ebc28e69SAndreas Gohr * @param int    $auth current auth check result
29942ea7f44SGerrit Uitslag * @return false|string false on error, id of the new file on success
3002d6cc64fSKate Arzamastseva */
3012d6cc64fSKate Arzamastsevafunction media_upload_xhr($ns,$auth){
302da45d883SKate Arzamastseva    if(!checkSecurityToken()) return false;
3038108113cSTom N Harris    global $INPUT;
304da45d883SKate Arzamastseva
3058108113cSTom N Harris    $id = $INPUT->get->str('qqfile');
306*24870174SAndreas Gohr    [$ext, $mime] = mimetype($id);
3072d6cc64fSKate Arzamastseva    $input = fopen("php://input", "r");
3082d6cc64fSKate Arzamastseva    if (!($tmp = io_mktmpdir())) return false;
30962231793SKate Arzamastseva    $path = $tmp.'/'.md5($id);
3102d6cc64fSKate Arzamastseva    $target = fopen($path, "w");
311063fb5b5SAndreas Gohr    $realSize = stream_copy_to_stream($input, $target);
3122d6cc64fSKate Arzamastseva    fclose($target);
313063fb5b5SAndreas Gohr    fclose($input);
3142b9be456SAndreas Gohr    if ($INPUT->server->has('CONTENT_LENGTH') && ($realSize != $INPUT->server->int('CONTENT_LENGTH'))) {
315063fb5b5SAndreas Gohr        unlink($path);
316063fb5b5SAndreas Gohr        return false;
317063fb5b5SAndreas Gohr    }
318063fb5b5SAndreas Gohr
3192d6cc64fSKate Arzamastseva    $res = media_save(
320*24870174SAndreas Gohr        ['name' => $path, 'mime' => $mime, 'ext'  => $ext],
3212d6cc64fSKate Arzamastseva        $ns.':'.$id,
32279a2d784SGerrit Uitslag        ($INPUT->get->str('ow') == 'true'),
3232d6cc64fSKate Arzamastseva        $auth,
3242d6cc64fSKate Arzamastseva        'copy'
3252d6cc64fSKate Arzamastseva    );
3262d6cc64fSKate Arzamastseva    unlink($path);
327900a9e9eSGerrit Uitslag    if ($tmp) io_rmdir($tmp, true);
3282d6cc64fSKate Arzamastseva    if (is_array($res)) {
3292d6cc64fSKate Arzamastseva        msg($res[0], $res[1]);
3302d6cc64fSKate Arzamastseva        return false;
3312d6cc64fSKate Arzamastseva    }
3322d6cc64fSKate Arzamastseva    return $res;
3332d6cc64fSKate Arzamastseva}
3342d6cc64fSKate Arzamastseva
3352d6cc64fSKate Arzamastseva/**
3363df72098SAndreas Gohr * Handles media file uploads
3373df72098SAndreas Gohr *
3383df72098SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org>
33911d9dfa5SMichael Klier * @author Michael Klier <chi@chimeric.de>
34042ea7f44SGerrit Uitslag *
341ebc28e69SAndreas Gohr * @param string     $ns    target namespace
342ebc28e69SAndreas Gohr * @param int        $auth  current auth check result
343ebc28e69SAndreas Gohr * @param bool|array $file  $_FILES member, $_FILES['upload'] if false
34442ea7f44SGerrit Uitslag * @return false|string false on error, id of the new file on success
3453df72098SAndreas Gohr */
3462d6cc64fSKate Arzamastsevafunction media_upload($ns,$auth,$file=false){
347f2ea8432SAndreas Gohr    if(!checkSecurityToken()) return false;
3483df72098SAndreas Gohr    global $lang;
3498108113cSTom N Harris    global $INPUT;
3503df72098SAndreas Gohr
35144409c3dSAndreas Gohr    // get file and id
3528108113cSTom N Harris    $id   = $INPUT->post->str('mediaid');
3532d6cc64fSKate Arzamastseva    if (!$file) $file = $_FILES['upload'];
3543df72098SAndreas Gohr    if(empty($id)) $id = $file['name'];
35544409c3dSAndreas Gohr
35699766eefSAndreas Gohr    // check for errors (messages are done in lib/exe/mediamanager.php)
35799766eefSAndreas Gohr    if($file['error']) return false;
3589676dc23SAndreas Gohr
35944409c3dSAndreas Gohr    // check extensions
360*24870174SAndreas Gohr    [$fext, $fmime] = mimetype($file['name']);
361*24870174SAndreas Gohr    [$iext, $imime] = mimetype($id);
36244409c3dSAndreas Gohr    if($fext && !$iext){
3638cb1eb01SAndreas Gohr        // no extension specified in id - read original one
36444409c3dSAndreas Gohr        $id   .= '.'.$fext;
3658cb1eb01SAndreas Gohr        $imime = $fmime;
36644409c3dSAndreas Gohr    }elseif($fext && $fext != $iext){
36744409c3dSAndreas Gohr        // extension was changed, print warning
36844409c3dSAndreas Gohr        msg(sprintf($lang['mediaextchange'],$fext,$iext));
36944409c3dSAndreas Gohr    }
37044409c3dSAndreas Gohr
371*24870174SAndreas Gohr    $res = media_save(
372*24870174SAndreas Gohr        [
373*24870174SAndreas Gohr            'name' => $file['tmp_name'],
374ffb291f2SAdrian Lang            'mime' => $imime,
375*24870174SAndreas Gohr            'ext' => $iext
376*24870174SAndreas Gohr        ],
377*24870174SAndreas Gohr        $ns . ':' . $id,
378*24870174SAndreas Gohr        $INPUT->post->bool('ow'),
379*24870174SAndreas Gohr        $auth,
380*24870174SAndreas Gohr        'copy_uploaded_file'
381*24870174SAndreas Gohr    );
382ffb291f2SAdrian Lang    if (is_array($res)) {
383ffb291f2SAdrian Lang        msg($res[0], $res[1]);
384ffb291f2SAdrian Lang        return false;
385ffb291f2SAdrian Lang    }
386ffb291f2SAdrian Lang    return $res;
387ffb291f2SAdrian Lang}
388ffb291f2SAdrian Lang
389ffb291f2SAdrian Lang/**
39071f17ac4SAndreas Gohr * An alternative to move_uploaded_file that copies
39171f17ac4SAndreas Gohr *
39271f17ac4SAndreas Gohr * Using copy, makes sure any setgid bits on the media directory are honored
39371f17ac4SAndreas Gohr *
39471f17ac4SAndreas Gohr * @see   move_uploaded_file()
39542ea7f44SGerrit Uitslag *
39671f17ac4SAndreas Gohr * @param string $from
39771f17ac4SAndreas Gohr * @param string $to
39871f17ac4SAndreas Gohr * @return bool
39971f17ac4SAndreas Gohr */
40071f17ac4SAndreas Gohrfunction copy_uploaded_file($from, $to){
40171f17ac4SAndreas Gohr    if(!is_uploaded_file($from)) return false;
40271f17ac4SAndreas Gohr    $ok = copy($from, $to);
40371f17ac4SAndreas Gohr    @unlink($from);
40471f17ac4SAndreas Gohr    return $ok;
40571f17ac4SAndreas Gohr}
40671f17ac4SAndreas Gohr
40771f17ac4SAndreas Gohr/**
408ffb291f2SAdrian Lang * This generates an action event and delegates to _media_upload_action().
409ffb291f2SAdrian Lang * Action plugins are allowed to pre/postprocess the uploaded file.
410ffb291f2SAdrian Lang * (The triggered event is preventable.)
411ffb291f2SAdrian Lang *
412ffb291f2SAdrian Lang * Event data:
413ffb291f2SAdrian Lang * $data[0]     fn_tmp:    the temporary file name (read from $_FILES)
414ffb291f2SAdrian Lang * $data[1]     fn:        the file name of the uploaded file
415ffb291f2SAdrian Lang * $data[2]     id:        the future directory id of the uploaded file
416ffb291f2SAdrian Lang * $data[3]     imime:     the mimetype of the uploaded file
417ffb291f2SAdrian Lang * $data[4]     overwrite: if an existing file is going to be overwritten
41852a281e8SGerrit Uitslag * $data[5]     move:      name of function that performs move/copy/..
419ffb291f2SAdrian Lang *
420ffb291f2SAdrian Lang * @triggers MEDIA_UPLOAD_FINISH
42142ea7f44SGerrit Uitslag *
422e0c26282SGerrit Uitslag * @param array  $file
42352a281e8SGerrit Uitslag * @param string $id   media id
42442ea7f44SGerrit Uitslag * @param bool   $ow   overwrite?
425e0c26282SGerrit Uitslag * @param int    $auth permission level
42652a281e8SGerrit Uitslag * @param string $move name of functions that performs move/copy/..
42742ea7f44SGerrit Uitslag * @return false|array|string
428e0c26282SGerrit Uitslag */
429ffb291f2SAdrian Langfunction media_save($file, $id, $ow, $auth, $move) {
430ffb291f2SAdrian Lang    if($auth < AUTH_UPLOAD) {
431*24870174SAndreas Gohr        return ["You don't have permissions to upload files.", -1];
432ffb291f2SAdrian Lang    }
433ffb291f2SAdrian Lang
434ffb291f2SAdrian Lang    if (!isset($file['mime']) || !isset($file['ext'])) {
435*24870174SAndreas Gohr        [$ext, $mime] = mimetype($id);
436ffb291f2SAdrian Lang        if (!isset($file['mime'])) {
437ffb291f2SAdrian Lang            $file['mime'] = $mime;
438ffb291f2SAdrian Lang        }
439ffb291f2SAdrian Lang        if (!isset($file['ext'])) {
440ffb291f2SAdrian Lang            $file['ext'] = $ext;
441ffb291f2SAdrian Lang        }
442ffb291f2SAdrian Lang    }
443ffb291f2SAdrian Lang
44492cac9a9SKate Arzamastseva    global $lang, $conf;
445ffb291f2SAdrian Lang
4463df72098SAndreas Gohr    // get filename
4473543c6deSAndreas Gohr    $id   = cleanID($id);
4483df72098SAndreas Gohr    $fn   = mediaFN($id);
4493df72098SAndreas Gohr
4503df72098SAndreas Gohr    // get filetype regexp
4513df72098SAndreas Gohr    $types = array_keys(getMimeTypes());
452bad6fc0dSAndreas Gohr    $types = array_map(
453*24870174SAndreas Gohr        static fn($q) => preg_quote($q, "/"),
454bad6fc0dSAndreas Gohr        $types
455bad6fc0dSAndreas Gohr    );
456*24870174SAndreas Gohr    $regex = implode('|',$types);
4573df72098SAndreas Gohr
4583df72098SAndreas Gohr    // because a temp file was created already
459ffb291f2SAdrian Lang    if(!preg_match('/\.('.$regex.')$/i',$fn)) {
460*24870174SAndreas Gohr        return [$lang['uploadwrong'], -1];
461ffb291f2SAdrian Lang    }
462ffb291f2SAdrian Lang
4633df72098SAndreas Gohr    //check for overwrite
46479e79377SAndreas Gohr    $overwrite = file_exists($fn);
465e5d185e1SKate Arzamastseva    $auth_ow = (($conf['mediarevisions']) ? AUTH_UPLOAD : AUTH_DELETE);
466e5d185e1SKate Arzamastseva    if($overwrite && (!$ow || $auth < $auth_ow)) {
467*24870174SAndreas Gohr        return [$lang['uploadexist'], 0];
4683df72098SAndreas Gohr    }
4698cb1eb01SAndreas Gohr    // check for valid content
470ffb291f2SAdrian Lang    $ok = media_contentcheck($file['name'], $file['mime']);
4718cb1eb01SAndreas Gohr    if($ok == -1){
472*24870174SAndreas Gohr        return [sprintf($lang['uploadbadcontent'],'.' . $file['ext']), -1];
4738cb1eb01SAndreas Gohr    }elseif($ok == -2){
474*24870174SAndreas Gohr        return [$lang['uploadspam'], -1];
47526ceae18SAndreas Gohr    }elseif($ok == -3){
476*24870174SAndreas Gohr        return [$lang['uploadxss'], -1];
4778cb1eb01SAndreas Gohr    }
4788cb1eb01SAndreas Gohr
47911d9dfa5SMichael Klier    // prepare event data
480*24870174SAndreas Gohr    $data = [];
481ffb291f2SAdrian Lang    $data[0] = $file['name'];
48211d9dfa5SMichael Klier    $data[1] = $fn;
48311d9dfa5SMichael Klier    $data[2] = $id;
484ffb291f2SAdrian Lang    $data[3] = $file['mime'];
48599c8d7f2Smichael    $data[4] = $overwrite;
486ffb291f2SAdrian Lang    $data[5] = $move;
48711d9dfa5SMichael Klier
48811d9dfa5SMichael Klier    // trigger event
489cbb44eabSAndreas Gohr    return Event::createAndTrigger('MEDIA_UPLOAD_FINISH', $data, '_media_upload_action', true);
49011d9dfa5SMichael Klier}
49111d9dfa5SMichael Klier
49211d9dfa5SMichael Klier/**
49342ea7f44SGerrit Uitslag * Callback adapter for media_upload_finish() triggered by MEDIA_UPLOAD_FINISH
49442ea7f44SGerrit Uitslag *
49511d9dfa5SMichael Klier * @author Michael Klier <chi@chimeric.de>
49642ea7f44SGerrit Uitslag *
49742ea7f44SGerrit Uitslag * @param array $data event data
49842ea7f44SGerrit Uitslag * @return false|array|string
49911d9dfa5SMichael Klier */
50011d9dfa5SMichael Klierfunction _media_upload_action($data) {
50111d9dfa5SMichael Klier    // fixme do further sanity tests of given data?
502ffb291f2SAdrian Lang    if(is_array($data) && count($data)===6) {
503ffb291f2SAdrian Lang        return media_upload_finish($data[0], $data[1], $data[2], $data[3], $data[4], $data[5]);
50411d9dfa5SMichael Klier    } else {
50511d9dfa5SMichael Klier        return false; //callback error
50611d9dfa5SMichael Klier    }
50711d9dfa5SMichael Klier}
50811d9dfa5SMichael Klier
50911d9dfa5SMichael Klier/**
51011d9dfa5SMichael Klier * Saves an uploaded media file
51111d9dfa5SMichael Klier *
51211d9dfa5SMichael Klier * @author Andreas Gohr <andi@splitbrain.org>
51311d9dfa5SMichael Klier * @author Michael Klier <chi@chimeric.de>
514cbe26ad6SKate Arzamastseva * @author Kate Arzamastseva <pshns@ukr.net>
51542ea7f44SGerrit Uitslag *
51642ea7f44SGerrit Uitslag * @param string $fn_tmp
51742ea7f44SGerrit Uitslag * @param string $fn
51842ea7f44SGerrit Uitslag * @param string $id        media id
51942ea7f44SGerrit Uitslag * @param string $imime     mime type
52042ea7f44SGerrit Uitslag * @param bool   $overwrite overwrite existing?
52142ea7f44SGerrit Uitslag * @param string $move      function name
52242ea7f44SGerrit Uitslag * @return array|string
52311d9dfa5SMichael Klier */
524ffb291f2SAdrian Langfunction media_upload_finish($fn_tmp, $fn, $id, $imime, $overwrite, $move = 'move_uploaded_file') {
52511d9dfa5SMichael Klier    global $conf;
52611d9dfa5SMichael Klier    global $lang;
5279c1bd4bcSKate Arzamastseva    global $REV;
52811d9dfa5SMichael Klier
529e4f389efSKate Arzamastseva    $old = @filemtime($fn);
53079e79377SAndreas Gohr    if(!file_exists(mediaFN($id, $old)) && file_exists($fn)) {
531e4f389efSKate Arzamastseva        // add old revision to the attic if missing
532cbe26ad6SKate Arzamastseva        media_saveOldRevision($id);
533e4f389efSKate Arzamastseva    }
534e4f389efSKate Arzamastseva
5353df72098SAndreas Gohr    // prepare directory
536cc7d0c94SBen Coburn    io_createNamespace($id, 'media');
53711d9dfa5SMichael Klier
538ac3ed4afSGerrit Uitslag    $filesize_old = file_exists($fn) ? filesize($fn) : 0;
539ac3ed4afSGerrit Uitslag
540ffb291f2SAdrian Lang    if($move($fn_tmp, $fn)) {
54123846a98SKate Arzamastseva        @clearstatcache(true,$fn);
542dad6764eSKate Arzamastseva        $new = @filemtime($fn);
54374400ea5SBen Coburn        // Set the correct permission here.
54474400ea5SBen Coburn        // Always chmod media because they may be saved with different permissions than expected from the php umask.
54574400ea5SBen Coburn        // (Should normally chmod to $conf['fperm'] only if $conf['fperm'] is set.)
54674400ea5SBen Coburn        chmod($fn, $conf['fmode']);
5473df72098SAndreas Gohr        msg($lang['uploadsucc'],1);
54883734cddSPhy        media_notify($id,$fn,$imime,$old,$new);
54999c8d7f2Smichael        // add a log entry to the media changelog
550ac3ed4afSGerrit Uitslag        $filesize_new = filesize($fn);
551ac3ed4afSGerrit Uitslag        $sizechange = $filesize_new - $filesize_old;
5529c1bd4bcSKate Arzamastseva        if($REV) {
55364159a61SAndreas Gohr            addMediaLogEntry(
55464159a61SAndreas Gohr                $new,
55564159a61SAndreas Gohr                $id,
55664159a61SAndreas Gohr                DOKU_CHANGE_TYPE_REVERT,
55764159a61SAndreas Gohr                sprintf($lang['restored'], dformat($REV)),
55864159a61SAndreas Gohr                $REV,
55964159a61SAndreas Gohr                null,
56064159a61SAndreas Gohr                $sizechange
56164159a61SAndreas Gohr            );
5629c1bd4bcSKate Arzamastseva        } elseif($overwrite) {
563ac3ed4afSGerrit Uitslag            addMediaLogEntry($new, $id, DOKU_CHANGE_TYPE_EDIT, '', '', null, $sizechange);
56499c8d7f2Smichael        } else {
565ac3ed4afSGerrit Uitslag            addMediaLogEntry($new, $id, DOKU_CHANGE_TYPE_CREATE, $lang['created'], '', null, $sizechange);
56699c8d7f2Smichael        }
5673df72098SAndreas Gohr        return $id;
5683df72098SAndreas Gohr    }else{
569*24870174SAndreas Gohr        return [$lang['uploadfail'], -1];
5703df72098SAndreas Gohr    }
5713df72098SAndreas Gohr}
5723df72098SAndreas Gohr
5738cb1eb01SAndreas Gohr/**
574cbe26ad6SKate Arzamastseva * Moves the current version of media file to the media_attic
575cbe26ad6SKate Arzamastseva * directory
576cbe26ad6SKate Arzamastseva *
577cbe26ad6SKate Arzamastseva * @author Kate Arzamastseva <pshns@ukr.net>
57842ea7f44SGerrit Uitslag *
579cbe26ad6SKate Arzamastseva * @param string $id
580cbe26ad6SKate Arzamastseva * @return int - revision date
581e4f389efSKate Arzamastseva */
582cbe26ad6SKate Arzamastsevafunction media_saveOldRevision($id) {
583dbf57c96SKate Arzamastseva    global $conf, $lang;
584dbf57c96SKate Arzamastseva
585e4f389efSKate Arzamastseva    $oldf = mediaFN($id);
58679e79377SAndreas Gohr    if (!file_exists($oldf)) return '';
587e4f389efSKate Arzamastseva    $date = filemtime($oldf);
588e5d185e1SKate Arzamastseva    if (!$conf['mediarevisions']) return $date;
589e5d185e1SKate Arzamastseva
590047bad06SGerrit Uitslag    $medialog = new MediaChangeLog($id);
591047bad06SGerrit Uitslag    if (!$medialog->getRevisionInfo($date)) {
592dbf57c96SKate Arzamastseva        // there was an external edit,
593dbf57c96SKate Arzamastseva        // there is no log entry for current version of file
594ac3ed4afSGerrit Uitslag        $sizechange = filesize($oldf);
59579e79377SAndreas Gohr        if(!file_exists(mediaMetaFN($id, '.changes'))) {
596ac3ed4afSGerrit Uitslag            addMediaLogEntry($date, $id, DOKU_CHANGE_TYPE_CREATE, $lang['created'], '', null, $sizechange);
597dbf57c96SKate Arzamastseva        } else {
598ac3ed4afSGerrit Uitslag            $oldRev = $medialog->getRevisions(-1, 1); // from changelog
599ac3ed4afSGerrit Uitslag            $oldRev = (int) (empty($oldRev) ? 0 : $oldRev[0]);
600ac3ed4afSGerrit Uitslag            $filesize_old = filesize(mediaFN($id, $oldRev));
601*24870174SAndreas Gohr            $sizechange -= $filesize_old;
602ac3ed4afSGerrit Uitslag
603ac3ed4afSGerrit Uitslag            addMediaLogEntry($date, $id, DOKU_CHANGE_TYPE_EDIT, '', '', null, $sizechange);
604dbf57c96SKate Arzamastseva        }
605dbf57c96SKate Arzamastseva    }
606dbf57c96SKate Arzamastseva
607e4f389efSKate Arzamastseva    $newf = mediaFN($id, $date);
608e4f389efSKate Arzamastseva    io_makeFileDir($newf);
609cbe26ad6SKate Arzamastseva    if (copy($oldf, $newf)) {
610e4f389efSKate Arzamastseva        // Set the correct permission here.
611e4f389efSKate Arzamastseva        // Always chmod media because they may be saved with different permissions than expected from the php umask.
612e4f389efSKate Arzamastseva        // (Should normally chmod to $conf['fperm'] only if $conf['fperm'] is set.)
613e4f389efSKate Arzamastseva        chmod($newf, $conf['fmode']);
614e4f389efSKate Arzamastseva    }
615e4f389efSKate Arzamastseva    return $date;
616e4f389efSKate Arzamastseva}
617e4f389efSKate Arzamastseva
618e4f389efSKate Arzamastseva/**
6198cb1eb01SAndreas Gohr * This function checks if the uploaded content is really what the
62026ceae18SAndreas Gohr * mimetype says it is. We also do spam checking for text types here.
6218cb1eb01SAndreas Gohr *
6228cb1eb01SAndreas Gohr * We need to do this stuff because we can not rely on the browser
6238cb1eb01SAndreas Gohr * to do this check correctly. Yes, IE is broken as usual.
6248cb1eb01SAndreas Gohr *
6258cb1eb01SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org>
62626ceae18SAndreas Gohr * @link   http://www.splitbrain.org/blog/2007-02/12-internet_explorer_facilitates_cross_site_scripting
6278cb1eb01SAndreas Gohr * @fixme  check all 26 magic IE filetypes here?
62842ea7f44SGerrit Uitslag *
62942ea7f44SGerrit Uitslag * @param string $file path to file
63042ea7f44SGerrit Uitslag * @param string $mime mimetype
63142ea7f44SGerrit Uitslag * @return int
6328cb1eb01SAndreas Gohr */
6338cb1eb01SAndreas Gohrfunction media_contentcheck($file,$mime){
63426ceae18SAndreas Gohr    global $conf;
63526ceae18SAndreas Gohr    if($conf['iexssprotect']){
63626ceae18SAndreas Gohr        $fh = @fopen($file, 'rb');
63726ceae18SAndreas Gohr        if($fh){
63826ceae18SAndreas Gohr            $bytes = fread($fh, 256);
63926ceae18SAndreas Gohr            fclose($fh);
64026ceae18SAndreas Gohr            if(preg_match('/<(script|a|img|html|body|iframe)[\s>]/i',$bytes)){
64142ea7f44SGerrit Uitslag                return -3; //XSS: possibly malicious content
64226ceae18SAndreas Gohr            }
64326ceae18SAndreas Gohr        }
64426ceae18SAndreas Gohr    }
6458cb1eb01SAndreas Gohr    if(substr($mime,0,6) == 'image/'){
6468cb1eb01SAndreas Gohr        $info = @getimagesize($file);
6478cb1eb01SAndreas Gohr        if($mime == 'image/gif' && $info[2] != 1){
64842ea7f44SGerrit Uitslag            return -1; // uploaded content did not match the file extension
6498cb1eb01SAndreas Gohr        }elseif($mime == 'image/jpeg' && $info[2] != 2){
6508cb1eb01SAndreas Gohr            return -1;
6518cb1eb01SAndreas Gohr        }elseif($mime == 'image/png' && $info[2] != 3){
6528cb1eb01SAndreas Gohr            return -1;
6538cb1eb01SAndreas Gohr        }
6548cb1eb01SAndreas Gohr        # fixme maybe check other images types as well
6558cb1eb01SAndreas Gohr    }elseif(substr($mime,0,5) == 'text/'){
6568cb1eb01SAndreas Gohr        global $TEXT;
6578cb1eb01SAndreas Gohr        $TEXT = io_readFile($file);
6588cb1eb01SAndreas Gohr        if(checkwordblock()){
65942ea7f44SGerrit Uitslag            return -2; //blocked by the spam blacklist
6608cb1eb01SAndreas Gohr        }
6618cb1eb01SAndreas Gohr    }
6628cb1eb01SAndreas Gohr    return 0;
6638cb1eb01SAndreas Gohr}
6643df72098SAndreas Gohr
6653df72098SAndreas Gohr/**
66675030359SAndreas Gohr * Send a notify mail on uploads
66775030359SAndreas Gohr *
66875030359SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org>
66942ea7f44SGerrit Uitslag *
67042ea7f44SGerrit Uitslag * @param string   $id      media id
67142ea7f44SGerrit Uitslag * @param string   $file    path to file
67242ea7f44SGerrit Uitslag * @param string   $mime    mime type
67342ea7f44SGerrit Uitslag * @param bool|int $old_rev revision timestamp or false
67475030359SAndreas Gohr */
67583734cddSPhyfunction media_notify($id,$file,$mime,$old_rev=false,$current_rev=false){
67675030359SAndreas Gohr    global $conf;
67779a2d784SGerrit Uitslag    if(empty($conf['notify'])) return; //notify enabled?
67875030359SAndreas Gohr
679704a815fSMichael Große    $subscription = new MediaSubscriptionSender();
68079a2d784SGerrit Uitslag    $subscription->sendMediaDiff($conf['notify'], 'uploadmail', $id, $old_rev, $current_rev);
68175030359SAndreas Gohr}
68275030359SAndreas Gohr
68375030359SAndreas Gohr/**
6843df72098SAndreas Gohr * List all files in a given Media namespace
68542ea7f44SGerrit Uitslag *
68621d806cdSGerrit Uitslag * @param string      $ns             namespace
68742ea7f44SGerrit Uitslag * @param null|int    $auth           permission level
68842ea7f44SGerrit Uitslag * @param string      $jump           id
68942ea7f44SGerrit Uitslag * @param bool        $fullscreenview
6908702de7fSGerrit Uitslag * @param bool|string $sort           sorting order, false skips sorting
6913df72098SAndreas Gohr */
692abc306f4SKate Arzamastsevafunction media_filelist($ns,$auth=null,$jump='',$fullscreenview=false,$sort=false){
6933df72098SAndreas Gohr    global $conf;
6943df72098SAndreas Gohr    global $lang;
6953df72098SAndreas Gohr    $ns = cleanID($ns);
6963df72098SAndreas Gohr
6973df72098SAndreas Gohr    // check auth our self if not given (needed for ajax calls)
6983df72098SAndreas Gohr    if(is_null($auth)) $auth = auth_quickaclcheck("$ns:*");
6993df72098SAndreas Gohr
700d9162c6cSKate Arzamastseva    if (!$fullscreenview) echo '<h1 id="media__ns">:'.hsc($ns).'</h1>'.NL;
7013df72098SAndreas Gohr
7023df72098SAndreas Gohr    if($auth < AUTH_READ){
7033df72098SAndreas Gohr        // FIXME: print permission warning here instead?
7043df72098SAndreas Gohr        echo '<div class="nothing">'.$lang['nothingfound'].'</div>'.NL;
70556fe6664SAndreas Gohr    }else{
70689274c0dSChristopher Smith        if (!$fullscreenview) {
70789274c0dSChristopher Smith            media_uploadform($ns, $auth);
70889274c0dSChristopher Smith            media_searchform($ns);
70989274c0dSChristopher Smith        }
7103df72098SAndreas Gohr
7113df72098SAndreas Gohr        $dir = utf8_encodeFN(str_replace(':','/',$ns));
712*24870174SAndreas Gohr        $data = [];
7134f33babfSAndreas Gohr        search($data,$conf['mediadir'],'search_mediafiles',
714*24870174SAndreas Gohr                ['showmsg'=>true, 'depth'=>1],$dir,1,$sort);
7153df72098SAndreas Gohr
7163df72098SAndreas Gohr        if(!count($data)){
7173df72098SAndreas Gohr            echo '<div class="nothing">'.$lang['nothingfound'].'</div>'.NL;
7185b9353faSKate Arzamastseva        }else {
7195b9353faSKate Arzamastseva            if ($fullscreenview) {
720554a8c9fSAdrian Lang                echo '<ul class="' . _media_get_list_type() . '">';
7215b9353faSKate Arzamastseva            }
7225b9353faSKate Arzamastseva            foreach($data as $item){
7235b9353faSKate Arzamastseva                if (!$fullscreenview) {
7244f33babfSAndreas Gohr                    //FIXME old call: media_printfile($item,$auth,$jump);
72579a2d784SGerrit Uitslag                    $display = new DisplayRow($item);
7269453716dSAndreas Gohr                    $display->scrollIntoView($jump == $item->getID());
7274f33babfSAndreas Gohr                    $display->show();
7285b9353faSKate Arzamastseva                } else {
7294f33babfSAndreas Gohr                    //FIXME old call: media_printfile_thumbs($item,$auth,$jump);
7304f33babfSAndreas Gohr                    echo '<li>';
73179a2d784SGerrit Uitslag                    $display = new DisplayTile($item);
7329453716dSAndreas Gohr                    $display->scrollIntoView($jump == $item->getID());
7334f33babfSAndreas Gohr                    $display->show();
7344f33babfSAndreas Gohr                    echo '</li>';
7355b9353faSKate Arzamastseva                }
7365b9353faSKate Arzamastseva            }
73794add303SAnika Henke            if ($fullscreenview) echo '</ul>'.NL;
7383df72098SAndreas Gohr        }
73956fe6664SAndreas Gohr    }
740d9162c6cSKate Arzamastseva}
741d9162c6cSKate Arzamastseva
742d9162c6cSKate Arzamastseva/**
743d9162c6cSKate Arzamastseva * Prints tabs for files list actions
744d9162c6cSKate Arzamastseva *
745d9162c6cSKate Arzamastseva * @author Kate Arzamastseva <pshns@ukr.net>
74695b451bcSAdrian Lang * @author Adrian Lang <mail@adrianlang.de>
74795b451bcSAdrian Lang *
748035e07f1SKate Arzamastseva * @param string $selected_tab - opened tab
749d9162c6cSKate Arzamastseva */
75095b451bcSAdrian Lang
751035e07f1SKate Arzamastsevafunction media_tabs_files($selected_tab = ''){
752d9162c6cSKate Arzamastseva    global $lang;
753*24870174SAndreas Gohr    $tabs = [];
754*24870174SAndreas Gohr    foreach([
755*24870174SAndreas Gohr                'files'  => 'mediaselect',
75695b451bcSAdrian Lang                'upload' => 'media_uploadtab',
757*24870174SAndreas Gohr                'search' => 'media_searchtab'
758*24870174SAndreas Gohr            ] as $tab => $caption) {
759*24870174SAndreas Gohr        $tabs[$tab] = [
760*24870174SAndreas Gohr            'href'    => media_managerURL(['tab_files' => $tab], '&'),
761*24870174SAndreas Gohr            'caption' => $lang[$caption]
762*24870174SAndreas Gohr        ];
76395b451bcSAdrian Lang    }
764d9162c6cSKate Arzamastseva
76595b451bcSAdrian Lang    html_tabs($tabs, $selected_tab);
766d9162c6cSKate Arzamastseva}
767d9162c6cSKate Arzamastseva
768d9162c6cSKate Arzamastseva/**
769d9162c6cSKate Arzamastseva * Prints tabs for files details actions
770d9162c6cSKate Arzamastseva *
771d9162c6cSKate Arzamastseva * @author Kate Arzamastseva <pshns@ukr.net>
772ebc28e69SAndreas Gohr * @param string $image filename of the current image
773ebc28e69SAndreas Gohr * @param string $selected_tab opened tab
774d9162c6cSKate Arzamastseva */
775035e07f1SKate Arzamastsevafunction media_tabs_details($image, $selected_tab = '') {
776e5d185e1SKate Arzamastseva    global $lang, $conf;
777d9162c6cSKate Arzamastseva
778*24870174SAndreas Gohr    $tabs = [];
779*24870174SAndreas Gohr    $tabs['view'] = [
780*24870174SAndreas Gohr        'href'    => media_managerURL(['tab_details' => 'view'], '&'),
781*24870174SAndreas Gohr        'caption' => $lang['media_viewtab']
782*24870174SAndreas Gohr    ];
783d9162c6cSKate Arzamastseva
784*24870174SAndreas Gohr    [, $mime] = mimetype($image);
78579e79377SAndreas Gohr    if ($mime == 'image/jpeg' && file_exists(mediaFN($image))) {
786*24870174SAndreas Gohr        $tabs['edit'] = [
787*24870174SAndreas Gohr            'href'    => media_managerURL(['tab_details' => 'edit'], '&'),
788*24870174SAndreas Gohr            'caption' => $lang['media_edittab']
789*24870174SAndreas Gohr        ];
790dd9ba38eSKate Arzamastseva    }
791e5d185e1SKate Arzamastseva    if ($conf['mediarevisions']) {
792*24870174SAndreas Gohr        $tabs['history'] = [
793*24870174SAndreas Gohr            'href'    => media_managerURL(['tab_details' => 'history'], '&'),
794*24870174SAndreas Gohr            'caption' => $lang['media_historytab']
795*24870174SAndreas Gohr        ];
796e5d185e1SKate Arzamastseva    }
797d9162c6cSKate Arzamastseva
79895b451bcSAdrian Lang    html_tabs($tabs, $selected_tab);
799d9162c6cSKate Arzamastseva}
800d9162c6cSKate Arzamastseva
801d9162c6cSKate Arzamastseva/**
802d9162c6cSKate Arzamastseva * Prints options for the tab that displays a list of all files
803d9162c6cSKate Arzamastseva *
804d9162c6cSKate Arzamastseva * @author Kate Arzamastseva <pshns@ukr.net>
805d9162c6cSKate Arzamastseva */
80695b451bcSAdrian Langfunction media_tab_files_options() {
8078108113cSTom N Harris    global $lang;
8088108113cSTom N Harris    global $INPUT;
809b7e5821dSAndreas Gohr    global $ID;
810b960c74fSSatoshi Sahara
811b960c74fSSatoshi Sahara    $form = new Form([
812b960c74fSSatoshi Sahara            'method' => 'get',
813b960c74fSSatoshi Sahara            'action' => wl($ID),
814b960c74fSSatoshi Sahara            'class' => 'options'
815b960c74fSSatoshi Sahara    ]);
816b960c74fSSatoshi Sahara    $form->addTagOpen('div')->addClass('no');
817b960c74fSSatoshi Sahara    $form->setHiddenField('sectok', null);
818b960c74fSSatoshi Sahara    $media_manager_params = media_managerURL([], '', false, true);
81938b2bf35SAnika Henke    foreach ($media_manager_params as $pKey => $pVal) {
820b960c74fSSatoshi Sahara        $form->setHiddenField($pKey, $pVal);
82138b2bf35SAnika Henke    }
8228108113cSTom N Harris    if ($INPUT->has('q')) {
823b960c74fSSatoshi Sahara        $form->setHiddenField('q', $INPUT->str('q'));
824554a8c9fSAdrian Lang    }
825b960c74fSSatoshi Sahara    $form->addHTML('<ul>'.NL);
826*24870174SAndreas Gohr    foreach ([
827*24870174SAndreas Gohr                 'list' => ['listType', ['thumbs', 'rows']],
828*24870174SAndreas Gohr                 'sort' => ['sortBy', ['name', 'date']]
829*24870174SAndreas Gohr             ] as $group => $content) {
830ec88e837SAndreas Gohr        $checked = "_media_get_{$group}_type";
831554a8c9fSAdrian Lang        $checked = $checked();
832d9162c6cSKate Arzamastseva
833b960c74fSSatoshi Sahara        $form->addHTML('<li class="'. $content[0] .'">');
83495b451bcSAdrian Lang        foreach ($content[1] as $option) {
835*24870174SAndreas Gohr            $attrs = [];
836554a8c9fSAdrian Lang            if ($checked == $option) {
83795b451bcSAdrian Lang                $attrs['checked'] = 'checked';
83895b451bcSAdrian Lang            }
839b960c74fSSatoshi Sahara            $radio = $form->addRadioButton(
840b960c74fSSatoshi Sahara                $group.'_dwmedia',
841b960c74fSSatoshi Sahara                $lang['media_'.$group.'_'.$option]
842b960c74fSSatoshi Sahara            )->val($option)->id($content[0].'__'.$option)->addClass($option);
843b960c74fSSatoshi Sahara            $radio->attrs($attrs);
84495b451bcSAdrian Lang        }
845b960c74fSSatoshi Sahara        $form->addHTML('</li>'.NL);
84695b451bcSAdrian Lang    }
847b960c74fSSatoshi Sahara    $form->addHTML('<li>');
848b960c74fSSatoshi Sahara    $form->addButton('', $lang['btn_apply'])->attr('type', 'submit');
849b960c74fSSatoshi Sahara    $form->addHTML('</li>'.NL);
850b960c74fSSatoshi Sahara    $form->addHTML('</ul>'.NL);
851b960c74fSSatoshi Sahara    $form->addTagClose('div');
852b960c74fSSatoshi Sahara    print $form->toHTML();
853d9162c6cSKate Arzamastseva}
854d9162c6cSKate Arzamastseva
855d9162c6cSKate Arzamastseva/**
85687deddfaSKate Arzamastseva * Returns type of sorting for the list of files in media manager
85787deddfaSKate Arzamastseva *
85887deddfaSKate Arzamastseva * @author Kate Arzamastseva <pshns@ukr.net>
85942ea7f44SGerrit Uitslag *
86087deddfaSKate Arzamastseva * @return string - sort type
86187deddfaSKate Arzamastseva */
86287deddfaSKate Arzamastsevafunction _media_get_sort_type() {
863*24870174SAndreas Gohr    return _media_get_display_param('sort', ['default' => 'name', 'date']);
86487deddfaSKate Arzamastseva}
865554a8c9fSAdrian Lang
8666ffaeda9SGerrit Uitslag/**
8676ffaeda9SGerrit Uitslag * Returns type of listing for the list of files in media manager
8686ffaeda9SGerrit Uitslag *
8696ffaeda9SGerrit Uitslag * @author Kate Arzamastseva <pshns@ukr.net>
87042ea7f44SGerrit Uitslag *
8716ffaeda9SGerrit Uitslag * @return string - list type
8726ffaeda9SGerrit Uitslag */
873554a8c9fSAdrian Langfunction _media_get_list_type() {
874*24870174SAndreas Gohr    return _media_get_display_param('list', ['default' => 'thumbs', 'rows']);
87587deddfaSKate Arzamastseva}
876554a8c9fSAdrian Lang
8776ffaeda9SGerrit Uitslag/**
8786ffaeda9SGerrit Uitslag * Get display parameters
8796ffaeda9SGerrit Uitslag *
8806ffaeda9SGerrit Uitslag * @param string $param   name of parameter
8816ffaeda9SGerrit Uitslag * @param array  $values  allowed values, where default value has index key 'default'
8826ffaeda9SGerrit Uitslag * @return string the parameter value
8836ffaeda9SGerrit Uitslag */
884554a8c9fSAdrian Langfunction _media_get_display_param($param, $values) {
8858108113cSTom N Harris    global $INPUT;
8868108113cSTom N Harris    if (in_array($INPUT->str($param), $values)) {
887554a8c9fSAdrian Lang        // FIXME: Set cookie
8888108113cSTom N Harris        return $INPUT->str($param);
889554a8c9fSAdrian Lang    } else {
8903629bc8cSAdrian Lang        $val = get_doku_pref($param, $values['default']);
8913629bc8cSAdrian Lang        if (!in_array($val, $values)) {
8923629bc8cSAdrian Lang            $val = $values['default'];
8933629bc8cSAdrian Lang        }
8943629bc8cSAdrian Lang        return $val;
895554a8c9fSAdrian Lang    }
89687deddfaSKate Arzamastseva}
89787deddfaSKate Arzamastseva
89887deddfaSKate Arzamastseva/**
899d9162c6cSKate Arzamastseva * Prints tab that displays a list of all files
900d9162c6cSKate Arzamastseva *
901d9162c6cSKate Arzamastseva * @author Kate Arzamastseva <pshns@ukr.net>
90242ea7f44SGerrit Uitslag *
90342ea7f44SGerrit Uitslag * @param string    $ns
90442ea7f44SGerrit Uitslag * @param null|int  $auth permission level
90542ea7f44SGerrit Uitslag * @param string    $jump item id
906d9162c6cSKate Arzamastseva */
907d9162c6cSKate Arzamastsevafunction media_tab_files($ns,$auth=null,$jump='') {
908d9162c6cSKate Arzamastseva    global $lang;
909d9162c6cSKate Arzamastseva    if(is_null($auth)) $auth = auth_quickaclcheck("$ns:*");
910d9162c6cSKate Arzamastseva
911d9162c6cSKate Arzamastseva    if($auth < AUTH_READ){
91288a71175SKate Arzamastseva        echo '<div class="nothing">'.$lang['media_perm_read'].'</div>'.NL;
913d9162c6cSKate Arzamastseva    }else{
91495b451bcSAdrian Lang        media_filelist($ns,$auth,$jump,true,_media_get_sort_type());
915d9162c6cSKate Arzamastseva    }
916d9162c6cSKate Arzamastseva}
917d9162c6cSKate Arzamastseva
918d9162c6cSKate Arzamastseva/**
919d9162c6cSKate Arzamastseva * Prints tab that displays uploading form
920d9162c6cSKate Arzamastseva *
921d9162c6cSKate Arzamastseva * @author Kate Arzamastseva <pshns@ukr.net>
92242ea7f44SGerrit Uitslag *
92342ea7f44SGerrit Uitslag * @param string   $ns
92442ea7f44SGerrit Uitslag * @param null|int $auth permission level
92542ea7f44SGerrit Uitslag * @param string   $jump item id
926d9162c6cSKate Arzamastseva */
927d9162c6cSKate Arzamastsevafunction media_tab_upload($ns,$auth=null,$jump='') {
928d9162c6cSKate Arzamastseva    global $lang;
929d9162c6cSKate Arzamastseva    if(is_null($auth)) $auth = auth_quickaclcheck("$ns:*");
930d9162c6cSKate Arzamastseva
93194add303SAnika Henke    echo '<div class="upload">'.NL;
93295b451bcSAdrian Lang    if ($auth >= AUTH_UPLOAD) {
93395b451bcSAdrian Lang        echo '<p>' . $lang['mediaupload'] . '</p>';
93495b451bcSAdrian Lang    }
935d9162c6cSKate Arzamastseva    media_uploadform($ns, $auth, true);
93694add303SAnika Henke    echo '</div>'.NL;
937d9162c6cSKate Arzamastseva}
938d9162c6cSKate Arzamastseva
939d9162c6cSKate Arzamastseva/**
940d9162c6cSKate Arzamastseva * Prints tab that displays search form
941d9162c6cSKate Arzamastseva *
942d9162c6cSKate Arzamastseva * @author Kate Arzamastseva <pshns@ukr.net>
94342ea7f44SGerrit Uitslag *
94442ea7f44SGerrit Uitslag * @param string $ns
94542ea7f44SGerrit Uitslag * @param null|int $auth permission level
946d9162c6cSKate Arzamastseva */
947d9162c6cSKate Arzamastsevafunction media_tab_search($ns,$auth=null) {
9488108113cSTom N Harris    global $INPUT;
949d9162c6cSKate Arzamastseva
9508108113cSTom N Harris    $do = $INPUT->str('mediado');
9518108113cSTom N Harris    $query = $INPUT->str('q');
95294add303SAnika Henke    echo '<div class="search">'.NL;
953d9162c6cSKate Arzamastseva
954d9162c6cSKate Arzamastseva    media_searchform($ns, $query, true);
9552dba8df4SAdrian Lang    if ($do == 'searchlist' || $query) {
95695b451bcSAdrian Lang        media_searchlist($query,$ns,$auth,true,_media_get_sort_type());
95795b451bcSAdrian Lang    }
95894add303SAnika Henke    echo '</div>'.NL;
959d9162c6cSKate Arzamastseva}
960d9162c6cSKate Arzamastseva
961d9162c6cSKate Arzamastseva/**
962d9162c6cSKate Arzamastseva * Prints tab that displays mediafile details
963d9162c6cSKate Arzamastseva *
964d9162c6cSKate Arzamastseva * @author Kate Arzamastseva <pshns@ukr.net>
965e0c26282SGerrit Uitslag *
966e0c26282SGerrit Uitslag * @param string     $image media id
967e0c26282SGerrit Uitslag * @param string     $ns
968e0c26282SGerrit Uitslag * @param null|int   $auth  permission level
96942ea7f44SGerrit Uitslag * @param string|int $rev   revision timestamp or empty string
970d9162c6cSKate Arzamastseva */
971e0c26282SGerrit Uitslagfunction media_tab_view($image, $ns, $auth=null, $rev='') {
972ebc28e69SAndreas Gohr    global $lang;
973d9162c6cSKate Arzamastseva    if(is_null($auth)) $auth = auth_quickaclcheck("$ns:*");
974d9162c6cSKate Arzamastseva
975e136d6ccSKate Arzamastseva    if ($image && $auth >= AUTH_READ) {
976dd9ba38eSKate Arzamastseva        $meta = new JpegMeta(mediaFN($image, $rev));
977dd9ba38eSKate Arzamastseva        media_preview($image, $auth, $rev, $meta);
978e136d6ccSKate Arzamastseva        media_preview_buttons($image, $auth, $rev);
979dd9ba38eSKate Arzamastseva        media_details($image, $auth, $rev, $meta);
980e136d6ccSKate Arzamastseva
981e136d6ccSKate Arzamastseva    } else {
98294add303SAnika Henke        echo '<div class="nothing">'.$lang['media_perm_read'].'</div>'.NL;
983e136d6ccSKate Arzamastseva    }
984d9162c6cSKate Arzamastseva}
985d9162c6cSKate Arzamastseva
986d9162c6cSKate Arzamastseva/**
987d9162c6cSKate Arzamastseva * Prints tab that displays form for editing mediafile metadata
988d9162c6cSKate Arzamastseva *
989d9162c6cSKate Arzamastseva * @author Kate Arzamastseva <pshns@ukr.net>
990e0c26282SGerrit Uitslag *
991e0c26282SGerrit Uitslag * @param string     $image media id
992e0c26282SGerrit Uitslag * @param string     $ns
993e0c26282SGerrit Uitslag * @param null|int   $auth permission level
994d9162c6cSKate Arzamastseva */
995d9162c6cSKate Arzamastsevafunction media_tab_edit($image, $ns, $auth=null) {
996d9162c6cSKate Arzamastseva    if(is_null($auth)) $auth = auth_quickaclcheck("$ns:*");
997d9162c6cSKate Arzamastseva
9981eeeced2SKate Arzamastseva    if ($image) {
999*24870174SAndreas Gohr        [, $mime] = mimetype($image);
100030fd72fbSKate Arzamastseva        if ($mime == 'image/jpeg') media_metaform($image,$auth);
10011eeeced2SKate Arzamastseva    }
1002d9162c6cSKate Arzamastseva}
1003d9162c6cSKate Arzamastseva
1004d9162c6cSKate Arzamastseva/**
1005d9162c6cSKate Arzamastseva * Prints tab that displays mediafile revisions
1006d9162c6cSKate Arzamastseva *
1007d9162c6cSKate Arzamastseva * @author Kate Arzamastseva <pshns@ukr.net>
1008e0c26282SGerrit Uitslag *
1009e0c26282SGerrit Uitslag * @param string     $image media id
1010e0c26282SGerrit Uitslag * @param string     $ns
1011e0c26282SGerrit Uitslag * @param null|int   $auth permission level
1012d9162c6cSKate Arzamastseva */
1013d9162c6cSKate Arzamastsevafunction media_tab_history($image, $ns, $auth=null) {
1014d9162c6cSKate Arzamastseva    global $lang;
10158108113cSTom N Harris    global $INPUT;
10168108113cSTom N Harris
1017d9162c6cSKate Arzamastseva    if(is_null($auth)) $auth = auth_quickaclcheck("$ns:*");
10188108113cSTom N Harris    $do = $INPUT->str('mediado');
1019d9162c6cSKate Arzamastseva
10202e55802cSKate Arzamastseva    if ($auth >= AUTH_READ && $image) {
10212e55802cSKate Arzamastseva        if ($do == 'diff'){
1022*24870174SAndreas Gohr            (new MediaDiff($image))->show(); //media_diff($image, $ns, $auth);
10232e55802cSKate Arzamastseva        } else {
1024a46cc3dcSAndreas Gohr            $first = $INPUT->int('first',-1);
1025*24870174SAndreas Gohr            (new MediaRevisions($image))->show($first);
10262e55802cSKate Arzamastseva        }
102788a71175SKate Arzamastseva    } else {
102888a71175SKate Arzamastseva        echo '<div class="nothing">'.$lang['media_perm_read'].'</div>'.NL;
10292e55802cSKate Arzamastseva    }
10303df72098SAndreas Gohr}
10313df72098SAndreas Gohr
10323df72098SAndreas Gohr/**
10331eeeced2SKate Arzamastseva * Prints mediafile details
10341eeeced2SKate Arzamastseva *
10356ffaeda9SGerrit Uitslag * @param string         $image media id
1036e0c26282SGerrit Uitslag * @param int            $auth permission level
103759bc3b48SGerrit Uitslag * @param int|string     $rev revision timestamp or empty string
10386ffaeda9SGerrit Uitslag * @param JpegMeta|bool  $meta
103942ea7f44SGerrit Uitslag *
10401eeeced2SKate Arzamastseva * @author Kate Arzamastseva <pshns@ukr.net>
10411eeeced2SKate Arzamastseva */
104259bc3b48SGerrit Uitslagfunction media_preview($image, $auth, $rev = '', $meta = false) {
1043e136d6ccSKate Arzamastseva
1044e136d6ccSKate Arzamastseva    $size = media_image_preview_size($image, $rev, $meta);
1045e136d6ccSKate Arzamastseva
1046e136d6ccSKate Arzamastseva    if ($size) {
104759f3611bSAnika Henke        global $lang;
104894add303SAnika Henke        echo '<div class="image">';
104994add303SAnika Henke
1050*24870174SAndreas Gohr        $more = [];
1051e136d6ccSKate Arzamastseva        if ($rev) {
10525b9353faSKate Arzamastseva            $more['rev'] = $rev;
1053e136d6ccSKate Arzamastseva        } else {
1054e136d6ccSKate Arzamastseva            $t = @filemtime(mediaFN($image));
10555b9353faSKate Arzamastseva            $more['t'] = $t;
105688a71175SKate Arzamastseva        }
105723786fd7SKate Arzamastseva
10585b9353faSKate Arzamastseva        $more['w'] = $size[0];
10595b9353faSKate Arzamastseva        $more['h'] = $size[1];
1060e136d6ccSKate Arzamastseva        $src = ml($image, $more);
106159f3611bSAnika Henke
106259f3611bSAnika Henke        echo '<a href="'.$src.'" target="_blank" title="'.$lang['mediaview'].'">';
106395b451bcSAdrian Lang        echo '<img src="'.$src.'" alt="" style="max-width: '.$size[0].'px;" />';
106459f3611bSAnika Henke        echo '</a>';
1065e136d6ccSKate Arzamastseva
1066871895a7SSatoshi Sahara        echo '</div>';
106794add303SAnika Henke    }
1068e136d6ccSKate Arzamastseva}
1069e136d6ccSKate Arzamastseva
1070e136d6ccSKate Arzamastseva/**
1071e136d6ccSKate Arzamastseva * Prints mediafile action buttons
1072e136d6ccSKate Arzamastseva *
1073e136d6ccSKate Arzamastseva * @author Kate Arzamastseva <pshns@ukr.net>
1074e0c26282SGerrit Uitslag *
1075e0c26282SGerrit Uitslag * @param string     $image media id
1076e0c26282SGerrit Uitslag * @param int        $auth  permission level
1077871895a7SSatoshi Sahara * @param int|string $rev   revision timestamp, or empty string
1078e136d6ccSKate Arzamastseva */
1079e0c26282SGerrit Uitslagfunction media_preview_buttons($image, $auth, $rev = '') {
1080e5d185e1SKate Arzamastseva    global $lang, $conf;
1081e136d6ccSKate Arzamastseva
1082871895a7SSatoshi Sahara    echo '<ul class="actions">';
10831eeeced2SKate Arzamastseva
108479e79377SAndreas Gohr    if ($auth >= AUTH_DELETE && !$rev && file_exists(mediaFN($image))) {
1085e136d6ccSKate Arzamastseva
1086e136d6ccSKate Arzamastseva        // delete button
1087b960c74fSSatoshi Sahara        $form = new Form([
1088b960c74fSSatoshi Sahara            'id' => 'mediamanager__btn_delete',
1089b960c74fSSatoshi Sahara            'action' => media_managerURL(['delete' => $image], '&'),
1090b960c74fSSatoshi Sahara        ]);
1091b960c74fSSatoshi Sahara        $form->addTagOpen('div')->addClass('no');
1092b960c74fSSatoshi Sahara        $form->addButton('', $lang['btn_delete'])->attr('type', 'submit');
1093b960c74fSSatoshi Sahara        $form->addTagClose('div');
109495b451bcSAdrian Lang        echo '<li>';
1095b960c74fSSatoshi Sahara        echo $form->toHTML();
1096871895a7SSatoshi Sahara        echo '</li>';
1097e5d185e1SKate Arzamastseva    }
1098e5d185e1SKate Arzamastseva
1099e5d185e1SKate Arzamastseva    $auth_ow = (($conf['mediarevisions']) ? AUTH_UPLOAD : AUTH_DELETE);
1100e5d185e1SKate Arzamastseva    if ($auth >= $auth_ow && !$rev) {
1101e5d185e1SKate Arzamastseva
1102e136d6ccSKate Arzamastseva        // upload new version button
1103b960c74fSSatoshi Sahara        $form = new Form([
1104b960c74fSSatoshi Sahara            'id' => 'mediamanager__btn_update',
1105b960c74fSSatoshi Sahara            'action' => media_managerURL(['image' => $image, 'mediado' => 'update'], '&'),
1106b960c74fSSatoshi Sahara        ]);
1107b960c74fSSatoshi Sahara        $form->addTagOpen('div')->addClass('no');
1108b960c74fSSatoshi Sahara        $form->addButton('', $lang['media_update'])->attr('type', 'submit');
1109b960c74fSSatoshi Sahara        $form->addTagClose('div');
111095b451bcSAdrian Lang        echo '<li>';
1111b960c74fSSatoshi Sahara        echo $form->toHTML();
1112871895a7SSatoshi Sahara        echo '</li>';
111370c3cc9aSKate Arzamastseva    }
1114e136d6ccSKate Arzamastseva
111579e79377SAndreas Gohr    if ($auth >= AUTH_UPLOAD && $rev && $conf['mediarevisions'] && file_exists(mediaFN($image, $rev))) {
1116e136d6ccSKate Arzamastseva
1117e136d6ccSKate Arzamastseva        // restore button
1118b960c74fSSatoshi Sahara        $form = new Form([
1119b960c74fSSatoshi Sahara            'id' => 'mediamanager__btn_restore',
1120b960c74fSSatoshi Sahara            'action'=>media_managerURL(['image' => $image], '&'),
1121b960c74fSSatoshi Sahara        ]);
1122b960c74fSSatoshi Sahara        $form->addTagOpen('div')->addClass('no');
1123b960c74fSSatoshi Sahara        $form->setHiddenField('mediado', 'restore');
1124b960c74fSSatoshi Sahara        $form->setHiddenField('rev', $rev);
1125b960c74fSSatoshi Sahara        $form->addButton('', $lang['media_restore'])->attr('type', 'submit');
1126b960c74fSSatoshi Sahara        $form->addTagClose('div');
112795b451bcSAdrian Lang        echo '<li>';
1128b960c74fSSatoshi Sahara        echo $form->toHTML();
1129871895a7SSatoshi Sahara        echo '</li>';
11309c1bd4bcSKate Arzamastseva    }
1131e136d6ccSKate Arzamastseva
1132871895a7SSatoshi Sahara    echo '</ul>';
11332e55802cSKate Arzamastseva}
11342e55802cSKate Arzamastseva
11352e55802cSKate Arzamastseva/**
1136fa8e5c77SKate Arzamastseva * Returns image width and height for mediamanager preview panel
1137fa8e5c77SKate Arzamastseva *
1138fa8e5c77SKate Arzamastseva * @author Kate Arzamastseva <pshns@ukr.net>
1139fa8e5c77SKate Arzamastseva * @param string         $image
1140e0c26282SGerrit Uitslag * @param int|string     $rev
114159bc3b48SGerrit Uitslag * @param JpegMeta|bool  $meta
1142ebc28e69SAndreas Gohr * @param int            $size
1143871895a7SSatoshi Sahara * @return array
1144fa8e5c77SKate Arzamastseva */
1145871895a7SSatoshi Saharafunction media_image_preview_size($image, $rev, $meta = false, $size = 500) {
1146871895a7SSatoshi Sahara    if (!preg_match("/\.(jpe?g|gif|png)$/", $image)
1147871895a7SSatoshi Sahara      || !file_exists($filename = mediaFN($image, $rev))
1148*24870174SAndreas Gohr    ) return [];
1149fa8e5c77SKate Arzamastseva
1150871895a7SSatoshi Sahara    $info = getimagesize($filename);
1151*24870174SAndreas Gohr    $w = $info[0];
1152*24870174SAndreas Gohr    $h = $info[1];
1153fa8e5c77SKate Arzamastseva
1154fa8e5c77SKate Arzamastseva    if ($meta && ($w > $size || $h > $size)) {
1155fa8e5c77SKate Arzamastseva        $ratio = $meta->getResizeRatio($size, $size);
1156fa8e5c77SKate Arzamastseva        $w = floor($w * $ratio);
1157fa8e5c77SKate Arzamastseva        $h = floor($h * $ratio);
1158fa8e5c77SKate Arzamastseva    }
1159*24870174SAndreas Gohr    return [$w, $h];
1160fa8e5c77SKate Arzamastseva}
1161fa8e5c77SKate Arzamastseva
1162fa8e5c77SKate Arzamastseva/**
1163fa8e5c77SKate Arzamastseva * Returns the requested EXIF/IPTC tag from the image meta
1164fa8e5c77SKate Arzamastseva *
1165fa8e5c77SKate Arzamastseva * @author Kate Arzamastseva <pshns@ukr.net>
1166e0c26282SGerrit Uitslag *
116742ea7f44SGerrit Uitslag * @param array    $tags array with tags, first existing is returned
1168fa8e5c77SKate Arzamastseva * @param JpegMeta $meta
116942ea7f44SGerrit Uitslag * @param string   $alt  alternative value
1170fa8e5c77SKate Arzamastseva * @return string
1171fa8e5c77SKate Arzamastseva */
1172871895a7SSatoshi Saharafunction media_getTag($tags, $meta = false, $alt = '') {
1173871895a7SSatoshi Sahara    if (!$meta) return $alt;
1174fa8e5c77SKate Arzamastseva    $info = $meta->getField($tags);
1175871895a7SSatoshi Sahara    if (!$info) return $alt;
1176fa8e5c77SKate Arzamastseva    return $info;
1177fa8e5c77SKate Arzamastseva}
1178fa8e5c77SKate Arzamastseva
1179fa8e5c77SKate Arzamastseva/**
1180e136d6ccSKate Arzamastseva * Returns mediafile tags
11812e55802cSKate Arzamastseva *
11822e55802cSKate Arzamastseva * @author Kate Arzamastseva <pshns@ukr.net>
1183e0c26282SGerrit Uitslag *
1184e136d6ccSKate Arzamastseva * @param JpegMeta $meta
118542ea7f44SGerrit Uitslag * @return array list of tags of the mediafile
11862e55802cSKate Arzamastseva */
1187e136d6ccSKate Arzamastsevafunction media_file_tags($meta) {
1188532850edSKate Arzamastseva    // load the field descriptions
11893e98e685SKate Arzamastseva    static $fields = null;
11903e98e685SKate Arzamastseva    if (is_null($fields)) {
11913e98e685SKate Arzamastseva        $config_files = getConfigFiles('mediameta');
11923e98e685SKate Arzamastseva        foreach ($config_files as $config_file) {
119379e79377SAndreas Gohr            if (file_exists($config_file)) include($config_file);
1194532850edSKate Arzamastseva        }
1195532850edSKate Arzamastseva    }
11961eeeced2SKate Arzamastseva
1197*24870174SAndreas Gohr    $tags = [];
1198dd9ba38eSKate Arzamastseva
1199*24870174SAndreas Gohr    foreach ($fields as $tag) {
1200*24870174SAndreas Gohr        $t = [];
1201*24870174SAndreas Gohr        if (!empty($tag[0])) $t = [$tag[0]];
12020e80bb5eSChristopher Smith        if (isset($tag[3]) && is_array($tag[3])) $t = array_merge($t,$tag[3]);
1203e136d6ccSKate Arzamastseva        $value = media_getTag($t, $meta);
1204*24870174SAndreas Gohr        $tags[] = ['tag' => $tag, 'value' => $value];
1205e136d6ccSKate Arzamastseva    }
1206e136d6ccSKate Arzamastseva
1207e136d6ccSKate Arzamastseva    return $tags;
1208e136d6ccSKate Arzamastseva}
1209e136d6ccSKate Arzamastseva
1210e136d6ccSKate Arzamastseva/**
1211e136d6ccSKate Arzamastseva * Prints mediafile tags
1212e136d6ccSKate Arzamastseva *
1213e136d6ccSKate Arzamastseva * @author Kate Arzamastseva <pshns@ukr.net>
121442ea7f44SGerrit Uitslag *
1215e0c26282SGerrit Uitslag * @param string        $image image id
1216e0c26282SGerrit Uitslag * @param int           $auth  permission level
1217e0c26282SGerrit Uitslag * @param string|int    $rev   revision timestamp, or empty string
1218e0c26282SGerrit Uitslag * @param bool|JpegMeta $meta  image object, or create one if false
1219e0c26282SGerrit Uitslag */
1220e0c26282SGerrit Uitslagfunction media_details($image, $auth, $rev='', $meta=false) {
1221e136d6ccSKate Arzamastseva    global $lang;
1222e136d6ccSKate Arzamastseva
1223e136d6ccSKate Arzamastseva    if (!$meta) $meta = new JpegMeta(mediaFN($image, $rev));
1224e136d6ccSKate Arzamastseva    $tags = media_file_tags($meta);
1225e136d6ccSKate Arzamastseva
122694add303SAnika Henke    echo '<dl>'.NL;
1227e136d6ccSKate Arzamastseva    foreach($tags as $tag){
1228e136d6ccSKate Arzamastseva        if ($tag['value']) {
1229e136d6ccSKate Arzamastseva            $value = cleanText($tag['value']);
1230fde860beSGerrit Uitslag            echo '<dt>'.$lang[$tag['tag'][1]].'</dt><dd>';
1231e136d6ccSKate Arzamastseva            if ($tag['tag'][2] == 'date') echo dformat($value);
12323e98e685SKate Arzamastseva            else echo hsc($value);
123394add303SAnika Henke            echo '</dd>'.NL;
12341eeeced2SKate Arzamastseva        }
1235e136d6ccSKate Arzamastseva    }
123694add303SAnika Henke    echo '</dl>'.NL;
123722e68399Sflammy    echo '<dl>'.NL;
123822e68399Sflammy    echo '<dt>'.$lang['reference'].':</dt>';
123922e68399Sflammy    $media_usage = ft_mediause($image,true);
1240*24870174SAndreas Gohr    if($media_usage !== []){
124122e68399Sflammy        foreach($media_usage as $path){
124222e68399Sflammy            echo '<dd>'.html_wikilink($path).'</dd>';
124322e68399Sflammy        }
124422e68399Sflammy    }else{
124522e68399Sflammy        echo '<dd>'.$lang['nothingfound'].'</dd>';
124622e68399Sflammy    }
124722e68399Sflammy    echo '</dl>'.NL;
124822e68399Sflammy
12491eeeced2SKate Arzamastseva}
12502e55802cSKate Arzamastseva
12512e55802cSKate Arzamastseva/**
12522e55802cSKate Arzamastseva * Shows difference between two revisions of file
12532e55802cSKate Arzamastseva *
12542e55802cSKate Arzamastseva * @author Kate Arzamastseva <pshns@ukr.net>
125542ea7f44SGerrit Uitslag *
1256e0c26282SGerrit Uitslag * @param string $image  image id
1257e0c26282SGerrit Uitslag * @param string $ns
1258e0c26282SGerrit Uitslag * @param int $auth permission level
1259e0c26282SGerrit Uitslag * @param bool $fromajax
126079a2d784SGerrit Uitslag *
1261297071beSSatoshi Sahara * @deprecated 2020-12-31
1262e0c26282SGerrit Uitslag */
1263b4b31bacSKate Arzamastsevafunction media_diff($image, $ns, $auth, $fromajax = false) {
126479a2d784SGerrit Uitslag    dbg_deprecated('see '. MediaDiff::class .'::show()');
126559e81a43SKate Arzamastseva}
126659e81a43SKate Arzamastseva
12676ffaeda9SGerrit Uitslag/**
12686ffaeda9SGerrit Uitslag * Callback for media file diff
12696ffaeda9SGerrit Uitslag *
127042ea7f44SGerrit Uitslag * @param array $data event data
127179a2d784SGerrit Uitslag *
1272297071beSSatoshi Sahara * @deprecated 2020-12-31
12736ffaeda9SGerrit Uitslag */
1274fa8e5c77SKate Arzamastsevafunction _media_file_diff($data) {
127579a2d784SGerrit Uitslag    dbg_deprecated('see '. MediaDiff::class .'::show()');
127659e81a43SKate Arzamastseva}
127759e81a43SKate Arzamastseva
127859e81a43SKate Arzamastseva/**
127959e81a43SKate Arzamastseva * Shows difference between two revisions of image
128059e81a43SKate Arzamastseva *
128159e81a43SKate Arzamastseva * @author Kate Arzamastseva <pshns@ukr.net>
1282e0c26282SGerrit Uitslag *
1283e0c26282SGerrit Uitslag * @param string $image
1284e0c26282SGerrit Uitslag * @param string|int $l_rev revision timestamp, or empty string
1285e0c26282SGerrit Uitslag * @param string|int $r_rev revision timestamp, or empty string
1286e0c26282SGerrit Uitslag * @param string $ns
1287e0c26282SGerrit Uitslag * @param int $auth permission level
1288e0c26282SGerrit Uitslag * @param bool $fromajax
1289297071beSSatoshi Sahara * @deprecated 2020-12-31
129059e81a43SKate Arzamastseva */
1291b4b31bacSKate Arzamastsevafunction media_file_diff($image, $l_rev, $r_rev, $ns, $auth, $fromajax) {
129279a2d784SGerrit Uitslag    dbg_deprecated('see '. MediaDiff::class .'::showFileDiff()');
1293e136d6ccSKate Arzamastseva}
1294e136d6ccSKate Arzamastseva
1295e136d6ccSKate Arzamastseva/**
1296e136d6ccSKate Arzamastseva * Prints two images side by side
1297fa8e5c77SKate Arzamastseva * and slider
1298e136d6ccSKate Arzamastseva *
1299e136d6ccSKate Arzamastseva * @author Kate Arzamastseva <pshns@ukr.net>
130042ea7f44SGerrit Uitslag *
130142ea7f44SGerrit Uitslag * @param string $image   image id
1302e0c26282SGerrit Uitslag * @param int    $l_rev   revision timestamp, or empty string
1303e0c26282SGerrit Uitslag * @param int    $r_rev   revision timestamp, or empty string
130442ea7f44SGerrit Uitslag * @param array  $l_size  array with width and height
130542ea7f44SGerrit Uitslag * @param array  $r_size  array with width and height
130650fc55feSKate Arzamastseva * @param string $type
1307297071beSSatoshi Sahara * @deprecated 2020-12-31
1308e136d6ccSKate Arzamastseva */
130950fc55feSKate Arzamastsevafunction media_image_diff($image, $l_rev, $r_rev, $l_size, $r_size, $type) {
131079a2d784SGerrit Uitslag    dbg_deprecated('see '. MediaDiff::class .'::showImageDiff()');
13111eeeced2SKate Arzamastseva}
13121eeeced2SKate Arzamastseva
13131eeeced2SKate Arzamastseva/**
13149c1bd4bcSKate Arzamastseva * Restores an old revision of a media file
13159c1bd4bcSKate Arzamastseva *
131642ea7f44SGerrit Uitslag * @param string $image media id
131742ea7f44SGerrit Uitslag * @param int    $rev   revision timestamp or empty string
13189c1bd4bcSKate Arzamastseva * @param int    $auth
13199c1bd4bcSKate Arzamastseva * @return string - file's id
132042ea7f44SGerrit Uitslag *
13219c1bd4bcSKate Arzamastseva * @author Kate Arzamastseva <pshns@ukr.net>
13229c1bd4bcSKate Arzamastseva */
13239c1bd4bcSKate Arzamastsevafunction media_restore($image, $rev, $auth){
1324e5d185e1SKate Arzamastseva    global $conf;
132580525638SKate Arzamastseva    if ($auth < AUTH_UPLOAD || !$conf['mediarevisions']) return false;
132692cac9a9SKate Arzamastseva    $removed = (!file_exists(mediaFN($image)) && file_exists(mediaMetaFN($image, '.changes')));
132792cac9a9SKate Arzamastseva    if (!$image || (!file_exists(mediaFN($image)) && !$removed)) return false;
13289c1bd4bcSKate Arzamastseva    if (!$rev || !file_exists(mediaFN($image, $rev))) return false;
1329*24870174SAndreas Gohr    [, $imime, ] = mimetype($image);
13309c1bd4bcSKate Arzamastseva    $res = media_upload_finish(mediaFN($image, $rev),
13319c1bd4bcSKate Arzamastseva        mediaFN($image),
13329c1bd4bcSKate Arzamastseva        $image,
13339c1bd4bcSKate Arzamastseva        $imime,
13349c1bd4bcSKate Arzamastseva        true,
13359c1bd4bcSKate Arzamastseva        'copy');
13369c1bd4bcSKate Arzamastseva    if (is_array($res)) {
13379c1bd4bcSKate Arzamastseva        msg($res[0], $res[1]);
13389c1bd4bcSKate Arzamastseva        return false;
13399c1bd4bcSKate Arzamastseva    }
13409c1bd4bcSKate Arzamastseva    return $res;
13419c1bd4bcSKate Arzamastseva}
13429c1bd4bcSKate Arzamastseva
13439c1bd4bcSKate Arzamastseva/**
1344bf1f3ac4Ssarnowski * List all files found by the search request
1345c9f56829SAndreas Gohr *
1346c9f56829SAndreas Gohr * @author Tobias Sarnowski <sarnowski@cosmocode.de>
1347c9f56829SAndreas Gohr * @author Andreas Gohr <gohr@cosmocode.de>
1348d9162c6cSKate Arzamastseva * @author Kate Arzamastseva <pshns@ukr.net>
1349c9f56829SAndreas Gohr * @triggers MEDIA_SEARCH
1350e0c26282SGerrit Uitslag *
1351e0c26282SGerrit Uitslag * @param string $query
1352e0c26282SGerrit Uitslag * @param string $ns
1353e0c26282SGerrit Uitslag * @param null|int $auth
1354e0c26282SGerrit Uitslag * @param bool $fullscreen
1355e0c26282SGerrit Uitslag * @param string $sort
1356bf1f3ac4Ssarnowski */
135700e3e394SChristopher Smithfunction media_searchlist($query,$ns,$auth=null,$fullscreen=false,$sort='natural'){
1358bf1f3ac4Ssarnowski    global $conf;
1359bf1f3ac4Ssarnowski    global $lang;
13608e69fd30SKate Arzamastseva
1361bf1f3ac4Ssarnowski    $ns = cleanID($ns);
1362*24870174SAndreas Gohr    $evdata = [
136356fe6664SAndreas Gohr        'ns'    => $ns,
1364*24870174SAndreas Gohr        'data'  => [],
136556fe6664SAndreas Gohr        'query' => $query
1366*24870174SAndreas Gohr    ];
13677ed31746SSzymon Olewniczak    if (!blank($query)) {
1368e1d9dcc8SAndreas Gohr        $evt = new Event('MEDIA_SEARCH', $evdata);
1369bf1f3ac4Ssarnowski        if ($evt->advise_before()) {
137056fe6664SAndreas Gohr            $dir = utf8_encodeFN(str_replace(':','/',$evdata['ns']));
137176472096SSzymon Olewniczak            $quoted = preg_quote($evdata['query'],'/');
137276472096SSzymon Olewniczak            //apply globbing
1373*24870174SAndreas Gohr            $quoted = str_replace(['\*', '\?'], ['.*', '.'], $quoted, $count);
137423e31e76SSzymon Olewniczak
137523e31e76SSzymon Olewniczak            //if we use globbing file name must match entirely but may be preceded by arbitrary namespace
137623e31e76SSzymon Olewniczak            if ($count > 0) $quoted = '^([^:]*:)*'.$quoted.'$';
137723e31e76SSzymon Olewniczak
137876472096SSzymon Olewniczak            $pattern = '/'.$quoted.'/i';
137956fe6664SAndreas Gohr            search($evdata['data'],
138056fe6664SAndreas Gohr                    $conf['mediadir'],
13814f33babfSAndreas Gohr                    'search_mediafiles',
1382*24870174SAndreas Gohr                    ['showmsg'=>false, 'pattern'=>$pattern],
138300e3e394SChristopher Smith                    $dir,
138400e3e394SChristopher Smith                    1,
138500e3e394SChristopher Smith                    $sort);
1386bf1f3ac4Ssarnowski        }
1387bf1f3ac4Ssarnowski        $evt->advise_after();
1388bf1f3ac4Ssarnowski        unset($evt);
138956fe6664SAndreas Gohr    }
1390bf1f3ac4Ssarnowski
1391d9162c6cSKate Arzamastseva    if (!$fullscreen) {
139256fe6664SAndreas Gohr        echo '<h1 id="media__ns">'.sprintf($lang['searchmedia_in'],hsc($ns).':*').'</h1>'.NL;
139356fe6664SAndreas Gohr        media_searchform($ns,$query);
1394d9162c6cSKate Arzamastseva    }
139556fe6664SAndreas Gohr
139656fe6664SAndreas Gohr    if(!count($evdata['data'])){
1397bf1f3ac4Ssarnowski        echo '<div class="nothing">'.$lang['nothingfound'].'</div>'.NL;
13985b9353faSKate Arzamastseva    }else {
13995b9353faSKate Arzamastseva        if ($fullscreen) {
1400554a8c9fSAdrian Lang            echo '<ul class="' . _media_get_list_type() . '">';
14015b9353faSKate Arzamastseva        }
14025b9353faSKate Arzamastseva        foreach($evdata['data'] as $item){
14034f33babfSAndreas Gohr            if (!$fullscreen) {
14044f33babfSAndreas Gohr                // FIXME old call: media_printfile($item,$item['perm'],'',true);
140579a2d784SGerrit Uitslag                $display = new DisplayRow($item);
140679b00823SAndreas Gohr                $display->relativeDisplay($ns);
14074f33babfSAndreas Gohr                $display->show();
14084f33babfSAndreas Gohr            } else {
14094f33babfSAndreas Gohr                // FIXME old call: media_printfile_thumbs($item,$item['perm'],false,true);
141079a2d784SGerrit Uitslag                $display = new DisplayTile($item);
141179b00823SAndreas Gohr                $display->relativeDisplay($ns);
14124f33babfSAndreas Gohr                echo '<li>';
14134f33babfSAndreas Gohr                $display->show();
14144f33babfSAndreas Gohr                echo '</li>';
14154f33babfSAndreas Gohr            }
1416bf1f3ac4Ssarnowski        }
141794add303SAnika Henke        if ($fullscreen) echo '</ul>'.NL;
14185b9353faSKate Arzamastseva    }
1419bf1f3ac4Ssarnowski}
1420bf1f3ac4Ssarnowski
1421bf1f3ac4Ssarnowski/**
1422c6571d58SAndreas Gohr * Display a media icon
1423c6571d58SAndreas Gohr *
142442ea7f44SGerrit Uitslag * @param string $filename media id
1425c6571d58SAndreas Gohr * @param string $size     the size subfolder, if not specified 16x16 is used
142642ea7f44SGerrit Uitslag * @return string html
1427c6571d58SAndreas Gohr */
1428c6571d58SAndreas Gohrfunction media_printicon($filename, $size=''){
1429*24870174SAndreas Gohr    [$ext] = mimetype(mediaFN($filename),false);
143023786fd7SKate Arzamastseva
143179e79377SAndreas Gohr    if (file_exists(DOKU_INC.'lib/images/fileicons/'.$size.'/'.$ext.'.png')) {
1432c6571d58SAndreas Gohr        $icon = DOKU_BASE.'lib/images/fileicons/'.$size.'/'.$ext.'.png';
143323786fd7SKate Arzamastseva    } else {
1434c6571d58SAndreas Gohr        $icon = DOKU_BASE.'lib/images/fileicons/'.$size.'/file.png';
143523786fd7SKate Arzamastseva    }
143623786fd7SKate Arzamastseva
1437421ec38eSKate Arzamastseva    return '<img src="'.$icon.'" alt="'.$filename.'" class="icon" />';
143823786fd7SKate Arzamastseva}
143923786fd7SKate Arzamastseva
14403df72098SAndreas Gohr/**
144142ea7f44SGerrit Uitslag * Build link based on the current, adding/rewriting parameters
1442d9162c6cSKate Arzamastseva *
1443d9162c6cSKate Arzamastseva * @author Kate Arzamastseva <pshns@ukr.net>
144442ea7f44SGerrit Uitslag *
1445ebc28e69SAndreas Gohr * @param array|bool $params
144642ea7f44SGerrit Uitslag * @param string     $amp           separator
144742ea7f44SGerrit Uitslag * @param bool       $abs           absolute url?
144842ea7f44SGerrit Uitslag * @param bool       $params_array  return the parmeters array?
144942ea7f44SGerrit Uitslag * @return string|array - link or link parameters
1450d9162c6cSKate Arzamastseva */
1451035e07f1SKate Arzamastsevafunction media_managerURL($params = false, $amp = '&amp;', $abs = false, $params_array = false) {
1452d9162c6cSKate Arzamastseva    global $ID;
14538108113cSTom N Harris    global $INPUT;
1454d9162c6cSKate Arzamastseva
1455*24870174SAndreas Gohr    $gets = ['do' => 'media'];
1456*24870174SAndreas Gohr    $media_manager_params = ['tab_files', 'tab_details', 'image', 'ns', 'list', 'sort'];
145723846a98SKate Arzamastseva    foreach ($media_manager_params as $x) {
14588108113cSTom N Harris        if ($INPUT->has($x)) $gets[$x] = $INPUT->str($x);
145923846a98SKate Arzamastseva    }
1460d9162c6cSKate Arzamastseva
1461d9162c6cSKate Arzamastseva    if ($params) {
1462554a8c9fSAdrian Lang        $gets = $params + $gets;
1463d9162c6cSKate Arzamastseva    }
1464d9162c6cSKate Arzamastseva    unset($gets['id']);
1465554a8c9fSAdrian Lang    if (isset($gets['delete'])) {
14661eeeced2SKate Arzamastseva        unset($gets['image']);
14671eeeced2SKate Arzamastseva        unset($gets['tab_details']);
14681eeeced2SKate Arzamastseva    }
1469d9162c6cSKate Arzamastseva
1470035e07f1SKate Arzamastseva    if ($params_array) return $gets;
1471035e07f1SKate Arzamastseva
14726dd095f5SKate Arzamastseva    return wl($ID,$gets,$abs,$amp);
1473d9162c6cSKate Arzamastseva}
1474d9162c6cSKate Arzamastseva
1475d9162c6cSKate Arzamastseva/**
14763df72098SAndreas Gohr * Print the media upload form if permissions are correct
14773df72098SAndreas Gohr *
14783df72098SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org>
1479d9162c6cSKate Arzamastseva * @author Kate Arzamastseva <pshns@ukr.net>
1480e0c26282SGerrit Uitslag *
1481e0c26282SGerrit Uitslag * @param string $ns
1482e0c26282SGerrit Uitslag * @param int    $auth permission level
1483e0c26282SGerrit Uitslag * @param bool  $fullscreen
14843df72098SAndreas Gohr */
1485d9162c6cSKate Arzamastsevafunction media_uploadform($ns, $auth, $fullscreen = false) {
14868108113cSTom N Harris    global $lang;
14878108113cSTom N Harris    global $conf;
14888108113cSTom N Harris    global $INPUT;
14893df72098SAndreas Gohr
149088a71175SKate Arzamastseva    if ($auth < AUTH_UPLOAD) {
149188a71175SKate Arzamastseva        echo '<div class="nothing">'.$lang['media_perm_upload'].'</div>'.NL;
149288a71175SKate Arzamastseva        return;
149388a71175SKate Arzamastseva    }
149492cac9a9SKate Arzamastseva    $auth_ow = (($conf['mediarevisions']) ? AUTH_UPLOAD : AUTH_DELETE);
14953df72098SAndreas Gohr
149670c3cc9aSKate Arzamastseva    $update = false;
149770c3cc9aSKate Arzamastseva    $id = '';
14988108113cSTom N Harris    if ($auth >= $auth_ow && $fullscreen && $INPUT->str('mediado') == 'update') {
149970c3cc9aSKate Arzamastseva        $update = true;
15008108113cSTom N Harris        $id = cleanID($INPUT->str('image'));
150170c3cc9aSKate Arzamastseva    }
150270c3cc9aSKate Arzamastseva
1503d00ec455SAndreas Gohr    // The default HTML upload form
1504b960c74fSSatoshi Sahara    $form = new Form([
1505b960c74fSSatoshi Sahara        'id' => 'dw__upload',
1506b960c74fSSatoshi Sahara        'enctype' => 'multipart/form-data',
1507b960c74fSSatoshi Sahara        'action' => ($fullscreen)
1508b960c74fSSatoshi Sahara                    ? media_managerURL(['tab_files' => 'files', 'tab_details' => 'view'], '&')
1509b960c74fSSatoshi Sahara                    : DOKU_BASE.'lib/exe/mediamanager.php',
1510b960c74fSSatoshi Sahara    ]);
1511b960c74fSSatoshi Sahara    $form->addTagOpen('div')->addClass('no');
1512b960c74fSSatoshi Sahara    $form->setHiddenField('ns', hsc($ns));  // FIXME hsc required?
1513b960c74fSSatoshi Sahara    $form->addTagOpen('p');
1514b960c74fSSatoshi Sahara    $form->addTextInput('upload', $lang['txt_upload'])->id('upload__file')
1515b960c74fSSatoshi Sahara            ->attrs(['type' => 'file']);
1516b960c74fSSatoshi Sahara    $form->addTagClose('p');
1517b960c74fSSatoshi Sahara    $form->addTagOpen('p');
1518b960c74fSSatoshi Sahara    $form->addTextInput('mediaid', $lang['txt_filename'])->id('upload__name')
1519b960c74fSSatoshi Sahara            ->val(noNS($id));
1520b960c74fSSatoshi Sahara    $form->addButton('', $lang['btn_upload'])->attr('type', 'submit');
1521b960c74fSSatoshi Sahara    $form->addTagClose('p');
152292cac9a9SKate Arzamastseva    if ($auth >= $auth_ow){
1523b960c74fSSatoshi Sahara        $form->addTagOpen('p');
1524*24870174SAndreas Gohr        $attrs = [];
152570c3cc9aSKate Arzamastseva        if ($update) $attrs['checked'] = 'checked';
1526b960c74fSSatoshi Sahara        $form->addCheckbox('ow', $lang['txt_overwrt'])->id('dw__ow')->val('1')
1527b960c74fSSatoshi Sahara            ->addClass('check')->attrs($attrs);
1528b960c74fSSatoshi Sahara        $form->addTagClose('p');
1529b960c74fSSatoshi Sahara    }
1530b960c74fSSatoshi Sahara    $form->addTagClose('div');
1531b960c74fSSatoshi Sahara
1532b960c74fSSatoshi Sahara    if (!$fullscreen) {
1533b960c74fSSatoshi Sahara        echo '<div class="upload">'. $lang['mediaupload'] .'</div>'.DOKU_LF;
1534b960c74fSSatoshi Sahara    } else {
1535b960c74fSSatoshi Sahara        echo DOKU_LF;
15363df72098SAndreas Gohr    }
1537c472bad9SKate Arzamastseva
1538b960c74fSSatoshi Sahara    echo '<div id="mediamanager__uploader">'.DOKU_LF;
1539c6977b3aSSatoshi Sahara    echo $form->toHTML('Upload');
1540b960c74fSSatoshi Sahara    echo '</div>'.DOKU_LF;
1541f940e4a0SAndreas Gohr
1542f940e4a0SAndreas Gohr    echo '<p class="maxsize">';
1543f940e4a0SAndreas Gohr    printf($lang['maxuploadsize'], filesize_h(media_getuploadsize()));
154456fc6b15SAnna Dabrowska    echo ' <a class="allowedmime" href="#">'. $lang['allowedmime'] .'</a>';
1545499d9bcdSAndreas Gohr    echo ' <span>'. implode(', ', array_keys(getMimeTypes())) .'</span>';
1546b960c74fSSatoshi Sahara    echo '</p>'.DOKU_LF;
1547f940e4a0SAndreas Gohr}
1548f940e4a0SAndreas Gohr
1549f940e4a0SAndreas Gohr/**
1550f940e4a0SAndreas Gohr * Returns the size uploaded files may have
1551f940e4a0SAndreas Gohr *
1552f940e4a0SAndreas Gohr * This uses a conservative approach using the lowest number found
1553f940e4a0SAndreas Gohr * in any of the limiting ini settings
1554f940e4a0SAndreas Gohr *
1555f940e4a0SAndreas Gohr * @returns int size in bytes
1556f940e4a0SAndreas Gohr */
1557f940e4a0SAndreas Gohrfunction media_getuploadsize(){
1558f940e4a0SAndreas Gohr    $okay = 0;
1559f940e4a0SAndreas Gohr
1560*24870174SAndreas Gohr    $post = php_to_byte(@ini_get('post_max_size'));
1561*24870174SAndreas Gohr    $suho = php_to_byte(@ini_get('suhosin.post.max_value_length'));
1562*24870174SAndreas Gohr    $upld = php_to_byte(@ini_get('upload_max_filesize'));
1563f940e4a0SAndreas Gohr
1564*24870174SAndreas Gohr    if($post && ($post < $okay || $okay === 0)) $okay = $post;
1565f940e4a0SAndreas Gohr    if($suho && ($suho < $okay || $okay == 0)) $okay = $suho;
1566f940e4a0SAndreas Gohr    if($upld && ($upld < $okay || $okay == 0)) $okay = $upld;
1567f940e4a0SAndreas Gohr
1568f940e4a0SAndreas Gohr    return $okay;
15699f5dde7fSMichael Klier}
15703df72098SAndreas Gohr
15713df72098SAndreas Gohr/**
1572bf1f3ac4Ssarnowski * Print the search field form
1573bf1f3ac4Ssarnowski *
1574bf1f3ac4Ssarnowski * @author Tobias Sarnowski <sarnowski@cosmocode.de>
1575d9162c6cSKate Arzamastseva * @author Kate Arzamastseva <pshns@ukr.net>
1576e0c26282SGerrit Uitslag *
1577e0c26282SGerrit Uitslag * @param string $ns
1578e0c26282SGerrit Uitslag * @param string $query
1579e0c26282SGerrit Uitslag * @param bool $fullscreen
1580bf1f3ac4Ssarnowski */
1581d9162c6cSKate Arzamastsevafunction media_searchform($ns, $query = '', $fullscreen = false) {
1582bf1f3ac4Ssarnowski    global $lang;
1583bf1f3ac4Ssarnowski
1584bf1f3ac4Ssarnowski    // The default HTML search form
1585b960c74fSSatoshi Sahara    $form = new Form([
1586b960c74fSSatoshi Sahara        'id'     => 'dw__mediasearch',
1587b960c74fSSatoshi Sahara        'action' => ($fullscreen)
1588b960c74fSSatoshi Sahara                    ? media_managerURL([], '&')
1589b960c74fSSatoshi Sahara                    : DOKU_BASE.'lib/exe/mediamanager.php',
1590b960c74fSSatoshi Sahara    ]);
1591b960c74fSSatoshi Sahara    $form->addTagOpen('div')->addClass('no');
1592b960c74fSSatoshi Sahara    $form->setHiddenField('ns', $ns);
1593b960c74fSSatoshi Sahara    $form->setHiddenField($fullscreen ? 'mediado' : 'do', 'searchlist');
1594554a8c9fSAdrian Lang
1595b960c74fSSatoshi Sahara    $form->addTagOpen('p');
1596bde2a644SSatoshi Sahara    $form->addTextInput('q', $lang['searchmedia'])
1597b960c74fSSatoshi Sahara            ->attr('title', sprintf($lang['searchmedia_in'], hsc($ns) .':*'))
1598b960c74fSSatoshi Sahara            ->val($query);
1599bde2a644SSatoshi Sahara    $form->addHTML(' ');
1600b960c74fSSatoshi Sahara    $form->addButton('', $lang['btn_search'])->attr('type', 'submit');
1601b960c74fSSatoshi Sahara    $form->addTagClose('p');
1602b960c74fSSatoshi Sahara    $form->addTagClose('div');
1603c6977b3aSSatoshi Sahara    print $form->toHTML('SearchMedia');
1604bf1f3ac4Ssarnowski}
1605bf1f3ac4Ssarnowski
1606bf1f3ac4Ssarnowski/**
16073df72098SAndreas Gohr * Build a tree outline of available media namespaces
16083df72098SAndreas Gohr *
16093df72098SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org>
1610e0c26282SGerrit Uitslag *
1611e0c26282SGerrit Uitslag * @param string $ns
16123df72098SAndreas Gohr */
16133df72098SAndreas Gohrfunction media_nstree($ns){
16143df72098SAndreas Gohr    global $conf;
1615256ca81eSAndreas Gohr    global $lang;
16163df72098SAndreas Gohr
16173df72098SAndreas Gohr    // currently selected namespace
16183df72098SAndreas Gohr    $ns  = cleanID($ns);
16193df72098SAndreas Gohr    if(empty($ns)){
1620de3eb1d7SAdrian Lang        global $ID;
1621dd90013aSMichael Hamann        $ns = (string)getNS($ID);
16223df72098SAndreas Gohr    }
1623dd90013aSMichael Hamann
1624dd90013aSMichael Hamann    $ns_dir  = utf8_encodeFN(str_replace(':','/',$ns));
16253df72098SAndreas Gohr
1626*24870174SAndreas Gohr    $data = [];
1627*24870174SAndreas Gohr    search($data,$conf['mediadir'],'search_index',['ns' => $ns_dir, 'nofiles' => true]);
16283df72098SAndreas Gohr
16293df72098SAndreas Gohr    // wrap a list with the root level around the other namespaces
1630*24870174SAndreas Gohr    array_unshift($data, ['level' => 0, 'id' => '', 'open' =>'true', 'label' => '['.$lang['mediaroot'].']']);
16313df72098SAndreas Gohr
1632dd90013aSMichael Hamann    // insert the current ns into the hierarchy if it isn't already part of it
1633dd90013aSMichael Hamann    $ns_parts = explode(':', $ns);
1634dd90013aSMichael Hamann    $tmp_ns = '';
1635dd90013aSMichael Hamann    $pos = 0;
1636dd90013aSMichael Hamann    foreach ($ns_parts as $level => $part) {
1637dd90013aSMichael Hamann        if ($tmp_ns) $tmp_ns .= ':'.$part;
1638dd90013aSMichael Hamann        else $tmp_ns = $part;
1639dd90013aSMichael Hamann
1640dd90013aSMichael Hamann        // find the namespace parts or insert them
1641dd90013aSMichael Hamann        while ($data[$pos]['id'] != $tmp_ns) {
164264159a61SAndreas Gohr            if (
164364159a61SAndreas Gohr                $pos >= count($data) ||
16442d85e841SAndreas Gohr                ($data[$pos]['level'] <= $level+1 && Sort::strcmp($data[$pos]['id'], $tmp_ns) > 0)
164564159a61SAndreas Gohr            ) {
1646*24870174SAndreas Gohr                array_splice($data, $pos, 0, [['level' => $level+1, 'id' => $tmp_ns, 'open' => 'true']]);
1647dd90013aSMichael Hamann                break;
1648dd90013aSMichael Hamann            }
1649dd90013aSMichael Hamann            ++$pos;
1650dd90013aSMichael Hamann        }
1651dd90013aSMichael Hamann    }
1652dd90013aSMichael Hamann
16533df72098SAndreas Gohr    echo html_buildlist($data,'idx','media_nstree_item','media_nstree_li');
16543df72098SAndreas Gohr}
16553df72098SAndreas Gohr
16563df72098SAndreas Gohr/**
16573df72098SAndreas Gohr * Userfunction for html_buildlist
16583df72098SAndreas Gohr *
16593df72098SAndreas Gohr * Prints a media namespace tree item
16603df72098SAndreas Gohr *
16613df72098SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org>
166242ea7f44SGerrit Uitslag *
166342ea7f44SGerrit Uitslag * @param array $item
166442ea7f44SGerrit Uitslag * @return string html
16653df72098SAndreas Gohr */
16663df72098SAndreas Gohrfunction media_nstree_item($item){
16678108113cSTom N Harris    global $INPUT;
16683df72098SAndreas Gohr    $pos   = strrpos($item['id'], ':');
16693df72098SAndreas Gohr    $label = substr($item['id'], $pos > 0 ? $pos + 1 : 0);
16700e80bb5eSChristopher Smith    if(empty($item['label'])) $item['label'] = $label;
16713df72098SAndreas Gohr
16723df72098SAndreas Gohr    $ret  = '';
1673*24870174SAndreas Gohr    if ($INPUT->str('do') != 'media')
16743df72098SAndreas Gohr    $ret .= '<a href="'.DOKU_BASE.'lib/exe/mediamanager.php?ns='.idfilter($item['id']).'" class="idx_dir">';
1675b960c74fSSatoshi Sahara    else $ret .= '<a href="'.media_managerURL(['ns' => idfilter($item['id'], false), 'tab_files' => 'files'])
167623846a98SKate Arzamastseva        .'" class="idx_dir">';
16773df72098SAndreas Gohr    $ret .= $item['label'];
16783df72098SAndreas Gohr    $ret .= '</a>';
16793df72098SAndreas Gohr    return $ret;
16803df72098SAndreas Gohr}
16813df72098SAndreas Gohr
16823df72098SAndreas Gohr/**
16833df72098SAndreas Gohr * Userfunction for html_buildlist
16843df72098SAndreas Gohr *
16853df72098SAndreas Gohr * Prints a media namespace tree item opener
16863df72098SAndreas Gohr *
16873df72098SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org>
168842ea7f44SGerrit Uitslag *
168942ea7f44SGerrit Uitslag * @param array $item
169042ea7f44SGerrit Uitslag * @return string html
16913df72098SAndreas Gohr */
16923df72098SAndreas Gohrfunction media_nstree_li($item){
16933df72098SAndreas Gohr    $class='media level'.$item['level'];
16943df72098SAndreas Gohr    if($item['open']){
16953df72098SAndreas Gohr        $class .= ' open';
16963df72098SAndreas Gohr        $img   = DOKU_BASE.'lib/images/minus.gif';
1697e260f93bSAnika Henke        $alt   = '−';
16983df72098SAndreas Gohr    }else{
16993df72098SAndreas Gohr        $class .= ' closed';
17003df72098SAndreas Gohr        $img   = DOKU_BASE.'lib/images/plus.gif';
17017af1b404SAnika Henke        $alt   = '+';
17023df72098SAndreas Gohr    }
1703231b8c34SPierre Spring    // TODO: only deliver an image if it actually has a subtree...
17043df72098SAndreas Gohr    return '<li class="'.$class.'">'.
17057af1b404SAnika Henke        '<img src="'.$img.'" alt="'.$alt.'" />';
17063df72098SAndreas Gohr}
170713c08e2fSMichael Klier
170813c08e2fSMichael Klier/**
1709b021f0b4SAndreas Gohr * Resizes or crop the given image to the given size
1710b021f0b4SAndreas Gohr *
1711b021f0b4SAndreas Gohr * @author  Andreas Gohr <andi@splitbrain.org>
1712b021f0b4SAndreas Gohr *
1713b021f0b4SAndreas Gohr * @param string $file filename, path to file
1714b021f0b4SAndreas Gohr * @param string $ext  extension
1715b021f0b4SAndreas Gohr * @param int    $w    desired width
1716b021f0b4SAndreas Gohr * @param int    $h    desired height
1717b021f0b4SAndreas Gohr * @param bool   $crop should a center crop be used?
1718b021f0b4SAndreas Gohr * @return string path to resized or original size if failed
1719b021f0b4SAndreas Gohr */
1720b021f0b4SAndreas Gohrfunction media_mod_image($file, $ext, $w, $h=0, $crop=false)
1721b021f0b4SAndreas Gohr{
1722b021f0b4SAndreas Gohr    global $conf;
1723d967ecd8SAndreas Gohr    if(!$h) $h = 0;
1724b021f0b4SAndreas Gohr    // we wont scale up to infinity
1725b021f0b4SAndreas Gohr    if($w > 2000 || $h > 2000) return $file;
1726b021f0b4SAndreas Gohr
1727b021f0b4SAndreas Gohr    $operation = $crop ? 'crop' : 'resize';
1728b021f0b4SAndreas Gohr
1729b021f0b4SAndreas Gohr    $options = [
1730b021f0b4SAndreas Gohr        'quality' => $conf['jpg_quality'],
1731b021f0b4SAndreas Gohr        'imconvert' => $conf['im_convert'],
1732b021f0b4SAndreas Gohr    ];
1733b021f0b4SAndreas Gohr
1734*24870174SAndreas Gohr    $cache = new CacheImageMod($file, $w, $h, $ext, $crop);
1735b021f0b4SAndreas Gohr    if(!$cache->useCache()) {
1736b021f0b4SAndreas Gohr        try {
1737b021f0b4SAndreas Gohr            Slika::run($file, $options)
1738b021f0b4SAndreas Gohr                 ->autorotate()
1739b021f0b4SAndreas Gohr                 ->$operation($w, $h)
1740b021f0b4SAndreas Gohr                 ->save($cache->cache, $ext);
1741b021f0b4SAndreas Gohr            if($conf['fperm']) @chmod($cache->cache, $conf['fperm']);
1742*24870174SAndreas Gohr        } catch (Exception $e) {
1743b021f0b4SAndreas Gohr            Logger::debug($e->getMessage());
1744b021f0b4SAndreas Gohr            return $file;
1745b021f0b4SAndreas Gohr        }
1746b021f0b4SAndreas Gohr    }
1747b021f0b4SAndreas Gohr
1748b021f0b4SAndreas Gohr    return $cache->cache;
1749b021f0b4SAndreas Gohr}
1750b021f0b4SAndreas Gohr
1751b021f0b4SAndreas Gohr/**
175213c08e2fSMichael Klier * Resizes the given image to the given size
175313c08e2fSMichael Klier *
175413c08e2fSMichael Klier * @author  Andreas Gohr <andi@splitbrain.org>
175542ea7f44SGerrit Uitslag *
175642ea7f44SGerrit Uitslag * @param string $file filename, path to file
175742ea7f44SGerrit Uitslag * @param string $ext  extension
175842ea7f44SGerrit Uitslag * @param int    $w    desired width
175942ea7f44SGerrit Uitslag * @param int    $h    desired height
176042ea7f44SGerrit Uitslag * @return string path to resized or original size if failed
176113c08e2fSMichael Klier */
1762b021f0b4SAndreas Gohrfunction media_resize_image($file, $ext, $w, $h = 0)
1763b021f0b4SAndreas Gohr{
1764b021f0b4SAndreas Gohr    return media_mod_image($file, $ext, $w, $h, false);
1765d2bd34a5SAndreas Gohr}
176613c08e2fSMichael Klier
176713c08e2fSMichael Klier/**
1768d2bd34a5SAndreas Gohr * Center crops the given image to the wanted size
176913c08e2fSMichael Klier *
177013c08e2fSMichael Klier * @author  Andreas Gohr <andi@splitbrain.org>
177142ea7f44SGerrit Uitslag *
177242ea7f44SGerrit Uitslag * @param string $file filename, path to file
177342ea7f44SGerrit Uitslag * @param string $ext  extension
177442ea7f44SGerrit Uitslag * @param int    $w    desired width
177542ea7f44SGerrit Uitslag * @param int    $h    desired height
177642ea7f44SGerrit Uitslag * @return string path to resized or original size if failed
177713c08e2fSMichael Klier */
1778b021f0b4SAndreas Gohrfunction media_crop_image($file, $ext, $w, $h = 0)
1779b021f0b4SAndreas Gohr{
1780b021f0b4SAndreas Gohr    return media_mod_image($file, $ext, $w, $h, true);
178113c08e2fSMichael Klier}
178213c08e2fSMichael Klier
178313c08e2fSMichael Klier/**
17840f4e0092SChristopher Smith * Calculate a token to be used to verify fetch requests for resized or
17850f4e0092SChristopher Smith * cropped images have been internally generated - and prevent external
17860f4e0092SChristopher Smith * DDOS attacks via fetch
17870f4e0092SChristopher Smith *
17883c124064SAndreas Gohr * @author Christopher Smith <chris@jalakai.co.uk>
17893c124064SAndreas Gohr *
17900f4e0092SChristopher Smith * @param string  $id    id of the image
17910f4e0092SChristopher Smith * @param int     $w     resize/crop width
17920f4e0092SChristopher Smith * @param int     $h     resize/crop height
179342ea7f44SGerrit Uitslag * @return string token or empty string if no token required
17940f4e0092SChristopher Smith */
17950f4e0092SChristopher Smithfunction media_get_token($id,$w,$h){
17960f4e0092SChristopher Smith    // token is only required for modified images
1797cc036f74SKlap-in    if ($w || $h || media_isexternal($id)) {
17983c124064SAndreas Gohr        $token = $id;
17990f4e0092SChristopher Smith        if ($w) $token .= '.'.$w;
18000f4e0092SChristopher Smith        if ($h) $token .= '.'.$h;
18010f4e0092SChristopher Smith
1802*24870174SAndreas Gohr        return substr(PassHash::hmac('md5', $token, auth_cookiesalt()),0,6);
18030f4e0092SChristopher Smith    }
18040f4e0092SChristopher Smith
18050f4e0092SChristopher Smith    return '';
18060f4e0092SChristopher Smith}
18070f4e0092SChristopher Smith
18080f4e0092SChristopher Smith/**
180913c08e2fSMichael Klier * Download a remote file and return local filename
181013c08e2fSMichael Klier *
181113c08e2fSMichael Klier * returns false if download fails. Uses cached file if available and
181213c08e2fSMichael Klier * wanted
181313c08e2fSMichael Klier *
181413c08e2fSMichael Klier * @author  Andreas Gohr <andi@splitbrain.org>
181513c08e2fSMichael Klier * @author  Pavel Vitis <Pavel.Vitis@seznam.cz>
181642ea7f44SGerrit Uitslag *
181742ea7f44SGerrit Uitslag * @param string $url
181842ea7f44SGerrit Uitslag * @param string $ext   extension
181942ea7f44SGerrit Uitslag * @param int    $cache cachetime in seconds
182042ea7f44SGerrit Uitslag * @return false|string path to cached file
182113c08e2fSMichael Klier */
182213c08e2fSMichael Klierfunction media_get_from_URL($url,$ext,$cache){
182313c08e2fSMichael Klier    global $conf;
182413c08e2fSMichael Klier
182513c08e2fSMichael Klier    // if no cache or fetchsize just redirect
182613c08e2fSMichael Klier    if ($cache==0)           return false;
182713c08e2fSMichael Klier    if (!$conf['fetchsize']) return false;
182813c08e2fSMichael Klier
182913c08e2fSMichael Klier    $local = getCacheName(strtolower($url),".media.$ext");
183013c08e2fSMichael Klier    $mtime = @filemtime($local); // 0 if not exists
183113c08e2fSMichael Klier
183213c08e2fSMichael Klier    //decide if download needed:
183313c08e2fSMichael Klier    if(($mtime == 0) || // cache does not exist
183413c08e2fSMichael Klier        ($cache != -1 && $mtime < time() - $cache) // 'recache' and cache has expired
183513c08e2fSMichael Klier    ) {
183613c08e2fSMichael Klier        if(media_image_download($url, $local)) {
183713c08e2fSMichael Klier            return $local;
183813c08e2fSMichael Klier        } else {
183913c08e2fSMichael Klier            return false;
184013c08e2fSMichael Klier        }
184113c08e2fSMichael Klier    }
184213c08e2fSMichael Klier
184313c08e2fSMichael Klier    //if cache exists use it else
184413c08e2fSMichael Klier    if($mtime) return $local;
184513c08e2fSMichael Klier
184613c08e2fSMichael Klier    //else return false
184713c08e2fSMichael Klier    return false;
184813c08e2fSMichael Klier}
184913c08e2fSMichael Klier
185013c08e2fSMichael Klier/**
185113c08e2fSMichael Klier * Download image files
185213c08e2fSMichael Klier *
185313c08e2fSMichael Klier * @author Andreas Gohr <andi@splitbrain.org>
185442ea7f44SGerrit Uitslag *
185542ea7f44SGerrit Uitslag * @param string $url
185642ea7f44SGerrit Uitslag * @param string $file path to file in which to put the downloaded content
185742ea7f44SGerrit Uitslag * @return bool
185813c08e2fSMichael Klier */
185913c08e2fSMichael Klierfunction media_image_download($url,$file){
186013c08e2fSMichael Klier    global $conf;
186113c08e2fSMichael Klier    $http = new DokuHTTPClient();
1862a5951419SAndreas Gohr    $http->keep_alive = false; // we do single ops here, no need for keep-alive
1863a5951419SAndreas Gohr
186413c08e2fSMichael Klier    $http->max_bodysize = $conf['fetchsize'];
186513c08e2fSMichael Klier    $http->timeout = 25; //max. 25 sec
186613c08e2fSMichael Klier    $http->header_regexp = '!\r\nContent-Type: image/(jpe?g|gif|png)!i';
186713c08e2fSMichael Klier
186813c08e2fSMichael Klier    $data = $http->get($url);
186913c08e2fSMichael Klier    if(!$data) return false;
187013c08e2fSMichael Klier
187179e79377SAndreas Gohr    $fileexists = file_exists($file);
187213c08e2fSMichael Klier    $fp = @fopen($file,"w");
187313c08e2fSMichael Klier    if(!$fp) return false;
187413c08e2fSMichael Klier    fwrite($fp,$data);
187513c08e2fSMichael Klier    fclose($fp);
1876*24870174SAndreas Gohr    if(!$fileexists && $conf['fperm']) chmod($file, $conf['fperm']);
187713c08e2fSMichael Klier
187813c08e2fSMichael Klier    // check if it is really an image
187913c08e2fSMichael Klier    $info = @getimagesize($file);
188013c08e2fSMichael Klier    if(!$info){
188113c08e2fSMichael Klier        @unlink($file);
188213c08e2fSMichael Klier        return false;
188313c08e2fSMichael Klier    }
188413c08e2fSMichael Klier
188513c08e2fSMichael Klier    return true;
188613c08e2fSMichael Klier}
188713c08e2fSMichael Klier
188813c08e2fSMichael Klier/**
188913c08e2fSMichael Klier * resize images using external ImageMagick convert program
189013c08e2fSMichael Klier *
189113c08e2fSMichael Klier * @author Pavel Vitis <Pavel.Vitis@seznam.cz>
189213c08e2fSMichael Klier * @author Andreas Gohr <andi@splitbrain.org>
189342ea7f44SGerrit Uitslag *
189442ea7f44SGerrit Uitslag * @param string $ext     extension
189542ea7f44SGerrit Uitslag * @param string $from    filename path to file
189642ea7f44SGerrit Uitslag * @param int    $from_w  original width
189742ea7f44SGerrit Uitslag * @param int    $from_h  original height
189842ea7f44SGerrit Uitslag * @param string $to      path to resized file
189942ea7f44SGerrit Uitslag * @param int    $to_w    desired width
190042ea7f44SGerrit Uitslag * @param int    $to_h    desired height
190142ea7f44SGerrit Uitslag * @return bool
190213c08e2fSMichael Klier */
190313c08e2fSMichael Klierfunction media_resize_imageIM($ext,$from,$from_w,$from_h,$to,$to_w,$to_h){
190413c08e2fSMichael Klier    global $conf;
190513c08e2fSMichael Klier
190613c08e2fSMichael Klier    // check if convert is configured
190713c08e2fSMichael Klier    if(!$conf['im_convert']) return false;
190813c08e2fSMichael Klier
190913c08e2fSMichael Klier    // prepare command
191013c08e2fSMichael Klier    $cmd  = $conf['im_convert'];
191113c08e2fSMichael Klier    $cmd .= ' -resize '.$to_w.'x'.$to_h.'!';
191213c08e2fSMichael Klier    if ($ext == 'jpg' || $ext == 'jpeg') {
191313c08e2fSMichael Klier        $cmd .= ' -quality '.$conf['jpg_quality'];
191413c08e2fSMichael Klier    }
191513c08e2fSMichael Klier    $cmd .= " $from $to";
191613c08e2fSMichael Klier
191713c08e2fSMichael Klier    @exec($cmd,$out,$retval);
191813c08e2fSMichael Klier    if ($retval == 0) return true;
191913c08e2fSMichael Klier    return false;
192013c08e2fSMichael Klier}
192113c08e2fSMichael Klier
192213c08e2fSMichael Klier/**
192313c08e2fSMichael Klier * crop images using external ImageMagick convert program
192413c08e2fSMichael Klier *
192513c08e2fSMichael Klier * @author Andreas Gohr <andi@splitbrain.org>
192642ea7f44SGerrit Uitslag *
192742ea7f44SGerrit Uitslag * @param string $ext     extension
192842ea7f44SGerrit Uitslag * @param string $from    filename path to file
192942ea7f44SGerrit Uitslag * @param int    $from_w  original width
193042ea7f44SGerrit Uitslag * @param int    $from_h  original height
193142ea7f44SGerrit Uitslag * @param string $to      path to resized file
193242ea7f44SGerrit Uitslag * @param int    $to_w    desired width
193342ea7f44SGerrit Uitslag * @param int    $to_h    desired height
193442ea7f44SGerrit Uitslag * @param int    $ofs_x   offset of crop centre
193542ea7f44SGerrit Uitslag * @param int    $ofs_y   offset of crop centre
193642ea7f44SGerrit Uitslag * @return bool
1937d2bd34a5SAndreas Gohr * @deprecated 2020-09-01
193813c08e2fSMichael Klier */
193913c08e2fSMichael Klierfunction media_crop_imageIM($ext,$from,$from_w,$from_h,$to,$to_w,$to_h,$ofs_x,$ofs_y){
194013c08e2fSMichael Klier    global $conf;
1941d2bd34a5SAndreas Gohr    dbg_deprecated('splitbrain\\Slika');
194213c08e2fSMichael Klier
194313c08e2fSMichael Klier    // check if convert is configured
194413c08e2fSMichael Klier    if(!$conf['im_convert']) return false;
194513c08e2fSMichael Klier
194613c08e2fSMichael Klier    // prepare command
194713c08e2fSMichael Klier    $cmd  = $conf['im_convert'];
194813c08e2fSMichael Klier    $cmd .= ' -crop '.$to_w.'x'.$to_h.'+'.$ofs_x.'+'.$ofs_y;
194913c08e2fSMichael Klier    if ($ext == 'jpg' || $ext == 'jpeg') {
195013c08e2fSMichael Klier        $cmd .= ' -quality '.$conf['jpg_quality'];
195113c08e2fSMichael Klier    }
195213c08e2fSMichael Klier    $cmd .= " $from $to";
195313c08e2fSMichael Klier
195413c08e2fSMichael Klier    @exec($cmd,$out,$retval);
195513c08e2fSMichael Klier    if ($retval == 0) return true;
195613c08e2fSMichael Klier    return false;
195713c08e2fSMichael Klier}
195813c08e2fSMichael Klier
195913c08e2fSMichael Klier/**
196013c08e2fSMichael Klier * resize or crop images using PHP's libGD support
196113c08e2fSMichael Klier *
196213c08e2fSMichael Klier * @author Andreas Gohr <andi@splitbrain.org>
196313c08e2fSMichael Klier * @author Sebastian Wienecke <s_wienecke@web.de>
196442ea7f44SGerrit Uitslag *
196542ea7f44SGerrit Uitslag * @param string $ext     extension
196642ea7f44SGerrit Uitslag * @param string $from    filename path to file
196742ea7f44SGerrit Uitslag * @param int    $from_w  original width
196842ea7f44SGerrit Uitslag * @param int    $from_h  original height
196942ea7f44SGerrit Uitslag * @param string $to      path to resized file
197042ea7f44SGerrit Uitslag * @param int    $to_w    desired width
197142ea7f44SGerrit Uitslag * @param int    $to_h    desired height
197242ea7f44SGerrit Uitslag * @param int    $ofs_x   offset of crop centre
197342ea7f44SGerrit Uitslag * @param int    $ofs_y   offset of crop centre
197442ea7f44SGerrit Uitslag * @return bool
1975d2bd34a5SAndreas Gohr * @deprecated 2020-09-01
197613c08e2fSMichael Klier */
197713c08e2fSMichael Klierfunction media_resize_imageGD($ext,$from,$from_w,$from_h,$to,$to_w,$to_h,$ofs_x=0,$ofs_y=0){
197813c08e2fSMichael Klier    global $conf;
1979d2bd34a5SAndreas Gohr    dbg_deprecated('splitbrain\\Slika');
198013c08e2fSMichael Klier
198113c08e2fSMichael Klier    if($conf['gdlib'] < 1) return false; //no GDlib available or wanted
198213c08e2fSMichael Klier
198313c08e2fSMichael Klier    // check available memory
198413c08e2fSMichael Klier    if(!is_mem_available(($from_w * $from_h * 4) + ($to_w * $to_h * 4))){
198513c08e2fSMichael Klier        return false;
198613c08e2fSMichael Klier    }
198713c08e2fSMichael Klier
198813c08e2fSMichael Klier    // create an image of the given filetype
198959bc3b48SGerrit Uitslag    $image = false;
199013c08e2fSMichael Klier    if ($ext == 'jpg' || $ext == 'jpeg'){
199113c08e2fSMichael Klier        if(!function_exists("imagecreatefromjpeg")) return false;
199213c08e2fSMichael Klier        $image = @imagecreatefromjpeg($from);
199313c08e2fSMichael Klier    }elseif($ext == 'png') {
199413c08e2fSMichael Klier        if(!function_exists("imagecreatefrompng")) return false;
199513c08e2fSMichael Klier        $image = @imagecreatefrompng($from);
199613c08e2fSMichael Klier
199713c08e2fSMichael Klier    }elseif($ext == 'gif') {
199813c08e2fSMichael Klier        if(!function_exists("imagecreatefromgif")) return false;
199913c08e2fSMichael Klier        $image = @imagecreatefromgif($from);
200013c08e2fSMichael Klier    }
200113c08e2fSMichael Klier    if(!$image) return false;
200213c08e2fSMichael Klier
200359bc3b48SGerrit Uitslag    $newimg = false;
200413c08e2fSMichael Klier    if(($conf['gdlib']>1) && function_exists("imagecreatetruecolor") && $ext != 'gif'){
200513c08e2fSMichael Klier        $newimg = @imagecreatetruecolor ($to_w, $to_h);
200613c08e2fSMichael Klier    }
200713c08e2fSMichael Klier    if(!$newimg) $newimg = @imagecreate($to_w, $to_h);
200813c08e2fSMichael Klier    if(!$newimg){
200913c08e2fSMichael Klier        imagedestroy($image);
201013c08e2fSMichael Klier        return false;
201113c08e2fSMichael Klier    }
201213c08e2fSMichael Klier
201313c08e2fSMichael Klier    //keep png alpha channel if possible
201413c08e2fSMichael Klier    if($ext == 'png' && $conf['gdlib']>1 && function_exists('imagesavealpha')){
201513c08e2fSMichael Klier        imagealphablending($newimg, false);
201613c08e2fSMichael Klier        imagesavealpha($newimg,true);
201713c08e2fSMichael Klier    }
201813c08e2fSMichael Klier
201913c08e2fSMichael Klier    //keep gif transparent color if possible
202013c08e2fSMichael Klier    if($ext == 'gif' && function_exists('imagefill') && function_exists('imagecolorallocate')) {
202113c08e2fSMichael Klier        if(function_exists('imagecolorsforindex') && function_exists('imagecolortransparent')) {
202213c08e2fSMichael Klier            $transcolorindex = @imagecolortransparent($image);
202313c08e2fSMichael Klier            if($transcolorindex >= 0 ) { //transparent color exists
202413c08e2fSMichael Klier                $transcolor = @imagecolorsforindex($image, $transcolorindex);
202564159a61SAndreas Gohr                $transcolorindex = @imagecolorallocate(
202664159a61SAndreas Gohr                    $newimg,
202764159a61SAndreas Gohr                    $transcolor['red'],
202864159a61SAndreas Gohr                    $transcolor['green'],
202964159a61SAndreas Gohr                    $transcolor['blue']
203064159a61SAndreas Gohr                );
203113c08e2fSMichael Klier                @imagefill($newimg, 0, 0, $transcolorindex);
203213c08e2fSMichael Klier                @imagecolortransparent($newimg, $transcolorindex);
203313c08e2fSMichael Klier            }else{ //filling with white
203413c08e2fSMichael Klier                $whitecolorindex = @imagecolorallocate($newimg, 255, 255, 255);
203513c08e2fSMichael Klier                @imagefill($newimg, 0, 0, $whitecolorindex);
203613c08e2fSMichael Klier            }
203713c08e2fSMichael Klier        }else{ //filling with white
203813c08e2fSMichael Klier            $whitecolorindex = @imagecolorallocate($newimg, 255, 255, 255);
203913c08e2fSMichael Klier            @imagefill($newimg, 0, 0, $whitecolorindex);
204013c08e2fSMichael Klier        }
204113c08e2fSMichael Klier    }
204213c08e2fSMichael Klier
204313c08e2fSMichael Klier    //try resampling first
204413c08e2fSMichael Klier    if(function_exists("imagecopyresampled")){
204513c08e2fSMichael Klier        if(!@imagecopyresampled($newimg, $image, 0, 0, $ofs_x, $ofs_y, $to_w, $to_h, $from_w, $from_h)) {
204613c08e2fSMichael Klier            imagecopyresized($newimg, $image, 0, 0, $ofs_x, $ofs_y, $to_w, $to_h, $from_w, $from_h);
204713c08e2fSMichael Klier        }
204813c08e2fSMichael Klier    }else{
204913c08e2fSMichael Klier        imagecopyresized($newimg, $image, 0, 0, $ofs_x, $ofs_y, $to_w, $to_h, $from_w, $from_h);
205013c08e2fSMichael Klier    }
205113c08e2fSMichael Klier
205213c08e2fSMichael Klier    $okay = false;
205313c08e2fSMichael Klier    if ($ext == 'jpg' || $ext == 'jpeg'){
205413c08e2fSMichael Klier        if(!function_exists('imagejpeg')){
205513c08e2fSMichael Klier            $okay = false;
205613c08e2fSMichael Klier        }else{
205713c08e2fSMichael Klier            $okay = imagejpeg($newimg, $to, $conf['jpg_quality']);
205813c08e2fSMichael Klier        }
205913c08e2fSMichael Klier    }elseif($ext == 'png') {
206013c08e2fSMichael Klier        if(!function_exists('imagepng')){
206113c08e2fSMichael Klier            $okay = false;
206213c08e2fSMichael Klier        }else{
206313c08e2fSMichael Klier            $okay =  imagepng($newimg, $to);
206413c08e2fSMichael Klier        }
206513c08e2fSMichael Klier    }elseif($ext == 'gif') {
206613c08e2fSMichael Klier        if(!function_exists('imagegif')){
206713c08e2fSMichael Klier            $okay = false;
206813c08e2fSMichael Klier        }else{
206913c08e2fSMichael Klier            $okay = imagegif($newimg, $to);
207013c08e2fSMichael Klier        }
207113c08e2fSMichael Klier    }
207213c08e2fSMichael Klier
207379a2d784SGerrit Uitslag    // destroy GD image resources
207479a2d784SGerrit Uitslag    imagedestroy($image);
207579a2d784SGerrit Uitslag    imagedestroy($newimg);
207613c08e2fSMichael Klier
207713c08e2fSMichael Klier    return $okay;
207813c08e2fSMichael Klier}
207913c08e2fSMichael Klier
20803d7a9e0aSAnika Henke/**
20813d7a9e0aSAnika Henke * Return other media files with the same base name
208279e53fe5SAnika Henke * but different extensions.
20833d7a9e0aSAnika Henke *
20843d7a9e0aSAnika Henke * @param string   $src     - ID of media file
208542ea7f44SGerrit Uitslag * @param string[] $exts    - alternative extensions to find other files for
208642ea7f44SGerrit Uitslag * @return array            - array(mime type => file ID)
20873d7a9e0aSAnika Henke *
20883d7a9e0aSAnika Henke * @author Anika Henke <anika@selfthinker.org>
20893d7a9e0aSAnika Henke */
209079e53fe5SAnika Henkefunction media_alternativefiles($src, $exts){
20913d7a9e0aSAnika Henke
2092*24870174SAndreas Gohr    $files = [];
2093*24870174SAndreas Gohr    [$srcExt, ] = mimetype($src);
20943d7a9e0aSAnika Henke    $filebase = substr($src, 0, -1 * (strlen($srcExt)+1));
20953d7a9e0aSAnika Henke
20963d7a9e0aSAnika Henke    foreach($exts as $ext) {
20973d7a9e0aSAnika Henke        $fileid = $filebase.'.'.$ext;
20983d7a9e0aSAnika Henke        $file = mediaFN($fileid);
20993d7a9e0aSAnika Henke        if(file_exists($file)) {
2100*24870174SAndreas Gohr            [, $fileMime] = mimetype($file);
210179e53fe5SAnika Henke            $files[$fileMime] = $fileid;
210299f943f6SAnika Henke        }
21033d7a9e0aSAnika Henke    }
21043d7a9e0aSAnika Henke    return $files;
21053d7a9e0aSAnika Henke}
21063d7a9e0aSAnika Henke
2107f50634f0SAnika Henke/**
2108f50634f0SAnika Henke * Check if video/audio is supported to be embedded.
2109f50634f0SAnika Henke *
2110b83a74f1SAnika Henke * @param string $mime      - mimetype of media file
211142ea7f44SGerrit Uitslag * @param string $type      - type of media files to check ('video', 'audio', or null for all)
2112f50634f0SAnika Henke * @return boolean
2113f50634f0SAnika Henke *
2114f50634f0SAnika Henke * @author Anika Henke <anika@selfthinker.org>
2115f50634f0SAnika Henke */
2116f50634f0SAnika Henkefunction media_supportedav($mime, $type=NULL){
2117*24870174SAndreas Gohr    $supportedAudio = [
2118f50634f0SAnika Henke        'ogg' => 'audio/ogg',
2119f50634f0SAnika Henke        'mp3' => 'audio/mpeg',
2120*24870174SAndreas Gohr        'wav' => 'audio/wav'
2121*24870174SAndreas Gohr    ];
2122*24870174SAndreas Gohr    $supportedVideo = [
2123f50634f0SAnika Henke        'webm' => 'video/webm',
2124f50634f0SAnika Henke        'ogv' => 'video/ogg',
2125*24870174SAndreas Gohr        'mp4' => 'video/mp4'
2126*24870174SAndreas Gohr    ];
2127f50634f0SAnika Henke    if ($type == 'audio') {
2128f50634f0SAnika Henke        $supportedAv = $supportedAudio;
2129f50634f0SAnika Henke    } elseif ($type == 'video') {
2130f50634f0SAnika Henke        $supportedAv = $supportedVideo;
2131f50634f0SAnika Henke    } else {
2132f50634f0SAnika Henke        $supportedAv = array_merge($supportedAudio, $supportedVideo);
2133f50634f0SAnika Henke    }
2134f50634f0SAnika Henke    return in_array($mime, $supportedAv);
2135f50634f0SAnika Henke}
2136f50634f0SAnika Henke
21370877a1f1SSchplurtz le Déboulonné/**
21380877a1f1SSchplurtz le Déboulonné * Return track media files with the same base name
21390877a1f1SSchplurtz le Déboulonné * but extensions that indicate kind and lang.
21400877a1f1SSchplurtz le Déboulonné * ie for foo.webm search foo.sub.lang.vtt, foo.cap.lang.vtt...
21410877a1f1SSchplurtz le Déboulonné *
21420877a1f1SSchplurtz le Déboulonné * @param string   $src     - ID of media file
214301299338SSchplurtz le Déboulonné * @return array            - array(mediaID => array( kind, srclang ))
21440877a1f1SSchplurtz le Déboulonné *
21450877a1f1SSchplurtz le Déboulonné * @author Schplurtz le Déboulonné <Schplurtz@laposte.net>
21460877a1f1SSchplurtz le Déboulonné */
21470877a1f1SSchplurtz le Déboulonnéfunction media_trackfiles($src){
2148*24870174SAndreas Gohr    $kinds=[
21490877a1f1SSchplurtz le Déboulonné        'sub' => 'subtitles',
21500877a1f1SSchplurtz le Déboulonné        'cap' => 'captions',
21510877a1f1SSchplurtz le Déboulonné        'des' => 'descriptions',
21520877a1f1SSchplurtz le Déboulonné        'cha' => 'chapters',
21530877a1f1SSchplurtz le Déboulonné        'met' => 'metadata'
2154*24870174SAndreas Gohr    ];
21550877a1f1SSchplurtz le Déboulonné
2156*24870174SAndreas Gohr    $files = [];
21570877a1f1SSchplurtz le Déboulonné    $re='/\\.(sub|cap|des|cha|met)\\.([^.]+)\\.vtt$/';
21580877a1f1SSchplurtz le Déboulonné    $baseid=pathinfo($src, PATHINFO_FILENAME);
21590877a1f1SSchplurtz le Déboulonné    $pattern=mediaFN($baseid).'.*.*.vtt';
21600877a1f1SSchplurtz le Déboulonné    $list=glob($pattern);
21610877a1f1SSchplurtz le Déboulonné    foreach($list as $track) {
21620877a1f1SSchplurtz le Déboulonné        if(preg_match($re, $track, $matches)){
2163*24870174SAndreas Gohr            $files[$baseid.'.'.$matches[1].'.'.$matches[2].'.vtt']=[$kinds[$matches[1]], $matches[2]];
21640877a1f1SSchplurtz le Déboulonné        }
21650877a1f1SSchplurtz le Déboulonné    }
21660877a1f1SSchplurtz le Déboulonné    return $files;
21670877a1f1SSchplurtz le Déboulonné}
21680877a1f1SSchplurtz le Déboulonné
2169365be586SAndreas Gohr/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
2170