xref: /dokuwiki/inc/media.php (revision 7e687fd85a40bd8453b39b64bae8e989ab32fd36)
13df72098SAndreas Gohr<?php
2d4f83172SAndreas Gohr
33df72098SAndreas Gohr/**
43df72098SAndreas Gohr * All output and handler function needed for the media management popup
53df72098SAndreas Gohr *
63df72098SAndreas Gohr * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
73df72098SAndreas Gohr * @author     Andreas Gohr <andi@splitbrain.org>
83df72098SAndreas Gohr */
93df72098SAndreas Gohr
1024870174SAndreas Gohruse dokuwiki\Ui\MediaRevisions;
1124870174SAndreas Gohruse dokuwiki\Cache\CacheImageMod;
1224870174SAndreas Gohruse splitbrain\slika\Exception;
1324870174SAndreas Gohruse dokuwiki\PassHash;
140c3a5702SAndreas Gohruse dokuwiki\ChangeLog\MediaChangeLog;
15e1d9dcc8SAndreas Gohruse dokuwiki\Extension\Event;
16dd9e8e5eSAndreas Gohruse dokuwiki\File\MediaFile;
17b960c74fSSatoshi Saharause dokuwiki\Form\Form;
183df72098SAndreas Gohruse dokuwiki\HTTP\DokuHTTPClient;
1979a2d784SGerrit Uitslaguse dokuwiki\Logger;
200c3a5702SAndreas Gohruse dokuwiki\Subscriptions\MediaSubscriptionSender;
21dd9e8e5eSAndreas Gohruse dokuwiki\Ui\Media\Display;
2279a2d784SGerrit Uitslaguse dokuwiki\Ui\Media\DisplayRow;
2379a2d784SGerrit Uitslaguse dokuwiki\Ui\Media\DisplayTile;
246734bb8cSAndreas Gohruse dokuwiki\Search\MetadataSearch;
2579a2d784SGerrit Uitslaguse dokuwiki\Ui\MediaDiff;
2679a2d784SGerrit Uitslaguse dokuwiki\Utf8\PhpString;
272d85e841SAndreas Gohruse dokuwiki\Utf8\Sort;
2879a2d784SGerrit Uitslaguse splitbrain\slika\Slika;
290c3a5702SAndreas Gohr
303df72098SAndreas Gohr/**
313df72098SAndreas Gohr * Lists pages which currently use a media file selected for deletion
323df72098SAndreas Gohr *
333df72098SAndreas Gohr * References uses the same visual as search results and share
343df72098SAndreas Gohr * their CSS tags except pagenames won't be links.
353df72098SAndreas Gohr *
363df72098SAndreas Gohr * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
3742ea7f44SGerrit Uitslag *
3842ea7f44SGerrit Uitslag * @param array $data
3942ea7f44SGerrit Uitslag * @param string $id
403df72098SAndreas Gohr */
41d868eb89SAndreas Gohrfunction media_filesinuse($data, $id)
42d868eb89SAndreas Gohr{
433df72098SAndreas Gohr    global $lang;
443df72098SAndreas Gohr    echo '<h1>' . $lang['reference'] . ' <code>' . hsc(noNS($id)) . '</code></h1>';
453df72098SAndreas Gohr    echo '<p>' . hsc($lang['ref_inuse']) . '</p>';
463df72098SAndreas Gohr
473df72098SAndreas Gohr    $hidden = 0; //count of hits without read permission
483df72098SAndreas Gohr    foreach ($data as $row) {
49a05e297aSAndreas Gohr        if (auth_quickaclcheck($row) >= AUTH_READ && isVisiblePage($row)) {
503df72098SAndreas Gohr            echo '<div class="search_result">';
51a05e297aSAndreas Gohr            echo '<span class="mediaref_ref">' . hsc($row) . '</span>';
523df72098SAndreas Gohr            echo '</div>';
53177d6836SAndreas Gohr        } else $hidden++;
543df72098SAndreas Gohr    }
553df72098SAndreas Gohr    if ($hidden) {
5626dfc232SAndreas Gohr        echo '<div class="mediaref_hidden">' . $lang['ref_hidden'] . '</div>';
573df72098SAndreas Gohr    }
583df72098SAndreas Gohr}
593df72098SAndreas Gohr
603df72098SAndreas Gohr/**
613df72098SAndreas Gohr * Handles the saving of image meta data
623df72098SAndreas Gohr *
633df72098SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org>
64cf832786SKate Arzamastseva * @author Kate Arzamastseva <pshns@ukr.net>
65e0c26282SGerrit Uitslag *
66e0c26282SGerrit Uitslag * @param string $id media id
67e0c26282SGerrit Uitslag * @param int $auth permission level
68e0c26282SGerrit Uitslag * @param array $data
6942ea7f44SGerrit Uitslag * @return false|string
703df72098SAndreas Gohr */
71d868eb89SAndreas Gohrfunction media_metasave($id, $auth, $data)
72d868eb89SAndreas Gohr{
733df72098SAndreas Gohr    if ($auth < AUTH_UPLOAD) return false;
74f2ea8432SAndreas Gohr    if (!checkSecurityToken()) return false;
753df72098SAndreas Gohr    global $lang;
760b308644SOtto Vainio    global $conf;
773df72098SAndreas Gohr    $src = mediaFN($id);
783df72098SAndreas Gohr
793df72098SAndreas Gohr    $meta = new JpegMeta($src);
803df72098SAndreas Gohr    $meta->_parseAll();
813df72098SAndreas Gohr
823df72098SAndreas Gohr    foreach ($data as $key => $val) {
833df72098SAndreas Gohr        $val = trim($val);
843df72098SAndreas Gohr        if (empty($val)) {
853df72098SAndreas Gohr            $meta->deleteField($key);
863df72098SAndreas Gohr        } else {
873df72098SAndreas Gohr            $meta->setField($key, $val);
883df72098SAndreas Gohr        }
893df72098SAndreas Gohr    }
903df72098SAndreas Gohr
91cf832786SKate Arzamastseva    $old = @filemtime($src);
9279e79377SAndreas Gohr    if (!file_exists(mediaFN($id, $old)) && file_exists($src)) {
93cf832786SKate Arzamastseva        // add old revision to the attic
94cf832786SKate Arzamastseva        media_saveOldRevision($id);
95cf832786SKate Arzamastseva    }
96ac3ed4afSGerrit Uitslag    $filesize_old = filesize($src);
973df72098SAndreas Gohr    if ($meta->save()) {
980b308644SOtto Vainio        if ($conf['fperm']) chmod($src, $conf['fperm']);
99ac3ed4afSGerrit Uitslag        @clearstatcache(true, $src);
100cf832786SKate Arzamastseva        $new = @filemtime($src);
101ac3ed4afSGerrit Uitslag        $filesize_new = filesize($src);
102ac3ed4afSGerrit Uitslag        $sizechange = $filesize_new - $filesize_old;
103ac3ed4afSGerrit Uitslag
104cf832786SKate Arzamastseva        // add a log entry to the media changelog
105ac3ed4afSGerrit Uitslag        addMediaLogEntry($new, $id, DOKU_CHANGE_TYPE_EDIT, $lang['media_meta_edited'], '', null, $sizechange);
106cf832786SKate Arzamastseva
1073df72098SAndreas Gohr        msg($lang['metasaveok'], 1);
1083df72098SAndreas Gohr        return $id;
1093df72098SAndreas Gohr    } else {
1103df72098SAndreas Gohr        msg($lang['metasaveerr'], -1);
1113df72098SAndreas Gohr        return false;
1123df72098SAndreas Gohr    }
1133df72098SAndreas Gohr}
1143df72098SAndreas Gohr
1153df72098SAndreas Gohr/**
116d54f7963SKlap-in * check if a media is external source
117d54f7963SKlap-in *
118d54f7963SKlap-in * @author Gerrit Uitslag <klapinklapin@gmail.com>
11942ea7f44SGerrit Uitslag *
120d54f7963SKlap-in * @param string $id the media ID or URL
121d54f7963SKlap-in * @return bool
122d54f7963SKlap-in */
123d868eb89SAndreas Gohrfunction media_isexternal($id)
124d868eb89SAndreas Gohr{
125fe578fe9SElan Ruusamäe    if (preg_match('#^(?:https?|ftp)://#i', $id)) return true;
126d54f7963SKlap-in    return false;
127d54f7963SKlap-in}
128d54f7963SKlap-in
129d54f7963SKlap-in/**
130add8678fSAndreas Gohr * Check if a media item is public (eg, external URL or readable by @ALL)
131add8678fSAndreas Gohr *
132add8678fSAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org>
13342ea7f44SGerrit Uitslag *
134add8678fSAndreas Gohr * @param string $id  the media ID or URL
135add8678fSAndreas Gohr * @return bool
136add8678fSAndreas Gohr */
137d868eb89SAndreas Gohrfunction media_ispublic($id)
138d868eb89SAndreas Gohr{
139d54f7963SKlap-in    if (media_isexternal($id)) return true;
140add8678fSAndreas Gohr    $id = cleanID($id);
141*7e687fd8SAndreas Gohr    if (auth_aclcheck(mediaAclPath($id), '', []) >= AUTH_READ) return true;
142add8678fSAndreas Gohr    return false;
143add8678fSAndreas Gohr}
144add8678fSAndreas Gohr
145add8678fSAndreas Gohr/**
1463df72098SAndreas Gohr * Display the form to edit image meta data
1473df72098SAndreas Gohr *
1483df72098SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org>
149d9162c6cSKate Arzamastseva * @author Kate Arzamastseva <pshns@ukr.net>
150e0c26282SGerrit Uitslag *
151e0c26282SGerrit Uitslag * @param string $id media id
152e0c26282SGerrit Uitslag * @param int $auth permission level
153e0c26282SGerrit Uitslag * @return bool
1543df72098SAndreas Gohr */
155d868eb89SAndreas Gohrfunction media_metaform($id, $auth)
156d868eb89SAndreas Gohr{
157ebc28e69SAndreas Gohr    global $lang;
1583df72098SAndreas Gohr
15988a71175SKate Arzamastseva    if ($auth < AUTH_UPLOAD) {
160b960c74fSSatoshi Sahara        echo '<div class="nothing">' . $lang['media_perm_upload'] . '</div>' . DOKU_LF;
16188a71175SKate Arzamastseva        return false;
16288a71175SKate Arzamastseva    }
16388a71175SKate Arzamastseva
1643df72098SAndreas Gohr    // load the field descriptions
1653df72098SAndreas Gohr    static $fields = null;
166b960c74fSSatoshi Sahara    if ($fields === null) {
1673e98e685SKate Arzamastseva        $config_files = getConfigFiles('mediameta');
1683e98e685SKate Arzamastseva        foreach ($config_files as $config_file) {
16979e79377SAndreas Gohr            if (file_exists($config_file)) include($config_file);
1703df72098SAndreas Gohr        }
1713df72098SAndreas Gohr    }
1723df72098SAndreas Gohr
1733df72098SAndreas Gohr    $src = mediaFN($id);
1743df72098SAndreas Gohr
1753df72098SAndreas Gohr    // output
176b960c74fSSatoshi Sahara    $form = new Form([
177b960c74fSSatoshi Sahara            'action' => media_managerURL(['tab_details' => 'view'], '&'),
178b960c74fSSatoshi Sahara            'class' => 'meta'
179b960c74fSSatoshi Sahara    ]);
180b960c74fSSatoshi Sahara    $form->addTagOpen('div')->addClass('no');
181b960c74fSSatoshi Sahara    $form->setHiddenField('img', $id);
182b960c74fSSatoshi Sahara    $form->setHiddenField('mediado', 'save');
1833df72098SAndreas Gohr    foreach ($fields as $key => $field) {
1843df72098SAndreas Gohr        // get current value
1853e98e685SKate Arzamastseva        if (empty($field[0])) continue;
18624870174SAndreas Gohr        $tags = [$field[0]];
1875cefb623SEduardo Mozart de Oliveira        if (isset($field[3]) && is_array($field[3])) $tags = array_merge($tags, $field[3]);
1883df72098SAndreas Gohr        $value = tpl_img_getTag($tags, '', $src);
189ca6a0701SAndreas Gohr        $value = cleanText($value);
1903df72098SAndreas Gohr
1913df72098SAndreas Gohr        // prepare attributes
19224870174SAndreas Gohr        $p = [
193b960c74fSSatoshi Sahara            'class' => 'edit',
194b960c74fSSatoshi Sahara            'id'    => 'meta__' . $key,
19524870174SAndreas Gohr            'name'  => 'meta[' . $field[0] . ']'
19624870174SAndreas Gohr        ];
1973df72098SAndreas Gohr
198b960c74fSSatoshi Sahara        $form->addTagOpen('div')->addClass('row');
1993df72098SAndreas Gohr        if ($field[2] == 'text') {
200bde2a644SSatoshi Sahara            $form->addTextInput(
20164159a61SAndreas Gohr                $p['name'],
20279a2d784SGerrit Uitslag                ($lang[$field[1]] ?: $field[1] . ':')
203b960c74fSSatoshi Sahara            )->id($p['id'])->addClass($p['class'])->val($value);
2043df72098SAndreas Gohr        } else {
205b960c74fSSatoshi Sahara            $form->addTextarea($p['name'], $lang[$field[1]])->id($p['id'])
206b960c74fSSatoshi Sahara                ->val(formText($value))
207b960c74fSSatoshi Sahara                ->addClass($p['class'])
208b960c74fSSatoshi Sahara                ->attr('rows', '6')->attr('cols', '50');
2093df72098SAndreas Gohr        }
210b960c74fSSatoshi Sahara        $form->addTagClose('div');
2113df72098SAndreas Gohr    }
212b960c74fSSatoshi Sahara    $form->addTagOpen('div')->addClass('buttons');
213b960c74fSSatoshi Sahara    $form->addButton('mediado[save]', $lang['btn_save'])->attr('type', 'submit')
214b960c74fSSatoshi Sahara        ->attrs(['accesskey' => 's']);
215b960c74fSSatoshi Sahara    $form->addTagClose('div');
216ebc28e69SAndreas Gohr
217b960c74fSSatoshi Sahara    $form->addTagClose('div');
218b960c74fSSatoshi Sahara    echo $form->toHTML();
219ebc28e69SAndreas Gohr    return true;
2203df72098SAndreas Gohr}
2213df72098SAndreas Gohr
222666cdec5SMichael Klier/**
22387229c84SAdrian Lang * Convenience function to check if a media file is still in use
224666cdec5SMichael Klier *
225666cdec5SMichael Klier * @author Michael Klier <chi@chimeric.de>
226e0c26282SGerrit Uitslag *
227e0c26282SGerrit Uitslag * @param string $id media id
228e0c26282SGerrit Uitslag * @return array|bool
229666cdec5SMichael Klier */
230d868eb89SAndreas Gohrfunction media_inuse($id)
231d868eb89SAndreas Gohr{
232666cdec5SMichael Klier    global $conf;
233ebc28e69SAndreas Gohr
234666cdec5SMichael Klier    if ($conf['refcheck']) {
2356734bb8cSAndreas Gohr        $mediareferences = (new MetadataSearch())->mediause($id, true);
23624870174SAndreas Gohr        if ($mediareferences === []) {
2376dae2464SAndreas Gohr            return false;
238666cdec5SMichael Klier        } else {
239666cdec5SMichael Klier            return $mediareferences;
240666cdec5SMichael Klier        }
241666cdec5SMichael Klier    } else {
242666cdec5SMichael Klier        return false;
243666cdec5SMichael Klier    }
244666cdec5SMichael Klier}
245a05e297aSAndreas Gohr
2463df72098SAndreas Gohr/**
2473df72098SAndreas Gohr * Handles media file deletions
2483df72098SAndreas Gohr *
2493df72098SAndreas Gohr * If configured, checks for media references before deletion
2503df72098SAndreas Gohr *
2513df72098SAndreas Gohr * @author             Andreas Gohr <andi@splitbrain.org>
25242ea7f44SGerrit Uitslag *
253ebc28e69SAndreas Gohr * @param string $id media id
25422db8df7SAndreas Gohr * @param int $auth no longer used
25587229c84SAdrian Lang * @return int One of: 0,
25663703ba5SAndreas Gohr *                     DOKU_MEDIA_DELETED,
25763703ba5SAndreas Gohr *                     DOKU_MEDIA_DELETED | DOKU_MEDIA_EMPTY_NS,
25863703ba5SAndreas Gohr *                     DOKU_MEDIA_NOT_AUTH,
25963703ba5SAndreas Gohr *                     DOKU_MEDIA_INUSE
2603df72098SAndreas Gohr */
261d868eb89SAndreas Gohrfunction media_delete($id, $auth)
262d868eb89SAndreas Gohr{
2636183fb05SKate Arzamastseva    global $lang;
264*7e687fd8SAndreas Gohr    $auth = auth_quickaclcheck(mediaAclPath($id));
26587229c84SAdrian Lang    if ($auth < AUTH_DELETE) return DOKU_MEDIA_NOT_AUTH;
26687229c84SAdrian Lang    if (media_inuse($id)) return DOKU_MEDIA_INUSE;
2673df72098SAndreas Gohr
2683df72098SAndreas Gohr    $file = mediaFN($id);
2694a961e72SMichal Kolodziejski
2704a961e72SMichal Kolodziejski    // trigger an event - MEDIA_DELETE_FILE
27124870174SAndreas Gohr    $data = [];
272666cdec5SMichael Klier    $data['id']   = $id;
27379a2d784SGerrit Uitslag    $data['name'] = PhpString::basename($file);
2744a961e72SMichal Kolodziejski    $data['path'] = $file;
27579e79377SAndreas Gohr    $data['size'] = (file_exists($file)) ? filesize($file) : 0;
276666cdec5SMichael Klier
277666cdec5SMichael Klier    $data['unl'] = false;
278666cdec5SMichael Klier    $data['del'] = false;
279e1d9dcc8SAndreas Gohr    $evt = new Event('MEDIA_DELETE_FILE', $data);
2804a961e72SMichal Kolodziejski    if ($evt->advise_before()) {
2816183fb05SKate Arzamastseva        $old = @filemtime($file);
28279e79377SAndreas Gohr        if (!file_exists(mediaFN($id, $old)) && file_exists($file)) {
2836183fb05SKate Arzamastseva            // add old revision to the attic
2846183fb05SKate Arzamastseva            media_saveOldRevision($id);
2856183fb05SKate Arzamastseva        }
2866183fb05SKate Arzamastseva
287666cdec5SMichael Klier        $data['unl'] = @unlink($file);
288666cdec5SMichael Klier        if ($data['unl']) {
289ac3ed4afSGerrit Uitslag            $sizechange = 0 - $data['size'];
290ac3ed4afSGerrit Uitslag            addMediaLogEntry(time(), $id, DOKU_CHANGE_TYPE_DELETE, $lang['deleted'], '', null, $sizechange);
291ac3ed4afSGerrit Uitslag
292666cdec5SMichael Klier            $data['del'] = io_sweepNS($id, 'mediadir');
2933df72098SAndreas Gohr        }
2944a961e72SMichal Kolodziejski    }
2954a961e72SMichal Kolodziejski    $evt->advise_after();
2964a961e72SMichal Kolodziejski    unset($evt);
2974a961e72SMichal Kolodziejski
298666cdec5SMichael Klier    if ($data['unl'] && $data['del']) {
29987229c84SAdrian Lang        return DOKU_MEDIA_DELETED | DOKU_MEDIA_EMPTY_NS;
3003df72098SAndreas Gohr    }
3013df72098SAndreas Gohr
30287229c84SAdrian Lang    return $data['unl'] ? DOKU_MEDIA_DELETED : 0;
3033df72098SAndreas Gohr}
3043df72098SAndreas Gohr
3053df72098SAndreas Gohr/**
3062d6cc64fSKate Arzamastseva * Handle file uploads via XMLHttpRequest
3072d6cc64fSKate Arzamastseva *
308ebc28e69SAndreas Gohr * @param string $ns   target namespace
309ebc28e69SAndreas Gohr * @param int    $auth current auth check result
31042ea7f44SGerrit Uitslag * @return false|string false on error, id of the new file on success
3112d6cc64fSKate Arzamastseva */
312d868eb89SAndreas Gohrfunction media_upload_xhr($ns, $auth)
313d868eb89SAndreas Gohr{
314da45d883SKate Arzamastseva    if (!checkSecurityToken()) return false;
3158108113cSTom N Harris    global $INPUT;
316da45d883SKate Arzamastseva
3178108113cSTom N Harris    $id = $INPUT->get->str('qqfile');
31824870174SAndreas Gohr    [$ext, $mime] = mimetype($id);
3192d6cc64fSKate Arzamastseva    $input = fopen("php://input", "r");
3202d6cc64fSKate Arzamastseva    if (!($tmp = io_mktmpdir())) return false;
32162231793SKate Arzamastseva    $path = $tmp . '/' . md5($id);
3222d6cc64fSKate Arzamastseva    $target = fopen($path, "w");
323063fb5b5SAndreas Gohr    $realSize = stream_copy_to_stream($input, $target);
3242d6cc64fSKate Arzamastseva    fclose($target);
325063fb5b5SAndreas Gohr    fclose($input);
3262b9be456SAndreas Gohr    if ($INPUT->server->has('CONTENT_LENGTH') && ($realSize != $INPUT->server->int('CONTENT_LENGTH'))) {
327063fb5b5SAndreas Gohr        unlink($path);
328063fb5b5SAndreas Gohr        return false;
329063fb5b5SAndreas Gohr    }
330063fb5b5SAndreas Gohr
3312d6cc64fSKate Arzamastseva    $res = media_save(
33224870174SAndreas Gohr        ['name' => $path, 'mime' => $mime, 'ext'  => $ext],
3332d6cc64fSKate Arzamastseva        $ns . ':' . $id,
33479a2d784SGerrit Uitslag        ($INPUT->get->str('ow') == 'true'),
3352d6cc64fSKate Arzamastseva        $auth,
3362d6cc64fSKate Arzamastseva        'copy'
3372d6cc64fSKate Arzamastseva    );
3382d6cc64fSKate Arzamastseva    unlink($path);
339900a9e9eSGerrit Uitslag    if ($tmp) io_rmdir($tmp, true);
3402d6cc64fSKate Arzamastseva    if (is_array($res)) {
3412d6cc64fSKate Arzamastseva        msg($res[0], $res[1]);
3422d6cc64fSKate Arzamastseva        return false;
3432d6cc64fSKate Arzamastseva    }
3442d6cc64fSKate Arzamastseva    return $res;
3452d6cc64fSKate Arzamastseva}
3462d6cc64fSKate Arzamastseva
3472d6cc64fSKate Arzamastseva/**
3483df72098SAndreas Gohr * Handles media file uploads
3493df72098SAndreas Gohr *
3503df72098SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org>
35111d9dfa5SMichael Klier * @author Michael Klier <chi@chimeric.de>
35242ea7f44SGerrit Uitslag *
353ebc28e69SAndreas Gohr * @param string     $ns    target namespace
354ebc28e69SAndreas Gohr * @param int        $auth  current auth check result
355ebc28e69SAndreas Gohr * @param bool|array $file  $_FILES member, $_FILES['upload'] if false
35642ea7f44SGerrit Uitslag * @return false|string false on error, id of the new file on success
3573df72098SAndreas Gohr */
358d868eb89SAndreas Gohrfunction media_upload($ns, $auth, $file = false)
359d868eb89SAndreas Gohr{
360f2ea8432SAndreas Gohr    if (!checkSecurityToken()) return false;
3613df72098SAndreas Gohr    global $lang;
3628108113cSTom N Harris    global $INPUT;
3633df72098SAndreas Gohr
36444409c3dSAndreas Gohr    // get file and id
3658108113cSTom N Harris    $id   = $INPUT->post->str('mediaid');
3662d6cc64fSKate Arzamastseva    if (!$file) $file = $_FILES['upload'];
3673df72098SAndreas Gohr    if (empty($id)) $id = $file['name'];
36844409c3dSAndreas Gohr
36999766eefSAndreas Gohr    // check for errors (messages are done in lib/exe/mediamanager.php)
37099766eefSAndreas Gohr    if ($file['error']) return false;
3719676dc23SAndreas Gohr
37244409c3dSAndreas Gohr    // check extensions
37324870174SAndreas Gohr    [$fext, $fmime] = mimetype($file['name']);
37424870174SAndreas Gohr    [$iext, $imime] = mimetype($id);
37544409c3dSAndreas Gohr    if ($fext && !$iext) {
3768cb1eb01SAndreas Gohr        // no extension specified in id - read original one
37744409c3dSAndreas Gohr        $id   .= '.' . $fext;
3788cb1eb01SAndreas Gohr        $imime = $fmime;
37944409c3dSAndreas Gohr    } elseif ($fext && $fext != $iext) {
38044409c3dSAndreas Gohr        // extension was changed, print warning
38144409c3dSAndreas Gohr        msg(sprintf($lang['mediaextchange'], $fext, $iext));
38244409c3dSAndreas Gohr    }
38344409c3dSAndreas Gohr
38424870174SAndreas Gohr    $res = media_save(
38524870174SAndreas Gohr        [
38624870174SAndreas Gohr            'name' => $file['tmp_name'],
387ffb291f2SAdrian Lang            'mime' => $imime,
38824870174SAndreas Gohr            'ext' => $iext
38924870174SAndreas Gohr        ],
39024870174SAndreas Gohr        $ns . ':' . $id,
39124870174SAndreas Gohr        $INPUT->post->bool('ow'),
39224870174SAndreas Gohr        $auth,
39324870174SAndreas Gohr        'copy_uploaded_file'
39424870174SAndreas Gohr    );
395ffb291f2SAdrian Lang    if (is_array($res)) {
396ffb291f2SAdrian Lang        msg($res[0], $res[1]);
397ffb291f2SAdrian Lang        return false;
398ffb291f2SAdrian Lang    }
399ffb291f2SAdrian Lang    return $res;
400ffb291f2SAdrian Lang}
401ffb291f2SAdrian Lang
402ffb291f2SAdrian Lang/**
40371f17ac4SAndreas Gohr * An alternative to move_uploaded_file that copies
40471f17ac4SAndreas Gohr *
40571f17ac4SAndreas Gohr * Using copy, makes sure any setgid bits on the media directory are honored
40671f17ac4SAndreas Gohr *
40771f17ac4SAndreas Gohr * @see   move_uploaded_file()
40842ea7f44SGerrit Uitslag *
40971f17ac4SAndreas Gohr * @param string $from
41071f17ac4SAndreas Gohr * @param string $to
41171f17ac4SAndreas Gohr * @return bool
41271f17ac4SAndreas Gohr */
413d868eb89SAndreas Gohrfunction copy_uploaded_file($from, $to)
414d868eb89SAndreas Gohr{
41571f17ac4SAndreas Gohr    if (!is_uploaded_file($from)) return false;
41671f17ac4SAndreas Gohr    $ok = copy($from, $to);
41771f17ac4SAndreas Gohr    @unlink($from);
41871f17ac4SAndreas Gohr    return $ok;
41971f17ac4SAndreas Gohr}
42071f17ac4SAndreas Gohr
42171f17ac4SAndreas Gohr/**
422ffb291f2SAdrian Lang * This generates an action event and delegates to _media_upload_action().
423ffb291f2SAdrian Lang * Action plugins are allowed to pre/postprocess the uploaded file.
424ffb291f2SAdrian Lang * (The triggered event is preventable.)
425ffb291f2SAdrian Lang *
426ffb291f2SAdrian Lang * Event data:
427ffb291f2SAdrian Lang * $data[0]     fn_tmp:    the temporary file name (read from $_FILES)
428ffb291f2SAdrian Lang * $data[1]     fn:        the file name of the uploaded file
429ffb291f2SAdrian Lang * $data[2]     id:        the future directory id of the uploaded file
430ffb291f2SAdrian Lang * $data[3]     imime:     the mimetype of the uploaded file
431ffb291f2SAdrian Lang * $data[4]     overwrite: if an existing file is going to be overwritten
43252a281e8SGerrit Uitslag * $data[5]     move:      name of function that performs move/copy/..
433ffb291f2SAdrian Lang *
434ffb291f2SAdrian Lang * @triggers MEDIA_UPLOAD_FINISH
43542ea7f44SGerrit Uitslag *
436e0c26282SGerrit Uitslag * @param array  $file
43752a281e8SGerrit Uitslag * @param string $id   media id
43842ea7f44SGerrit Uitslag * @param bool   $ow   overwrite?
439e0c26282SGerrit Uitslag * @param int    $auth permission level
44052a281e8SGerrit Uitslag * @param string $move name of functions that performs move/copy/..
44142ea7f44SGerrit Uitslag * @return false|array|string
442e0c26282SGerrit Uitslag */
443d868eb89SAndreas Gohrfunction media_save($file, $id, $ow, $auth, $move)
444d868eb89SAndreas Gohr{
445ffb291f2SAdrian Lang    if ($auth < AUTH_UPLOAD) {
44624870174SAndreas Gohr        return ["You don't have permissions to upload files.", -1];
447ffb291f2SAdrian Lang    }
448ffb291f2SAdrian Lang
449ffb291f2SAdrian Lang    if (!isset($file['mime']) || !isset($file['ext'])) {
45024870174SAndreas Gohr        [$ext, $mime] = mimetype($id);
451ffb291f2SAdrian Lang        if (!isset($file['mime'])) {
452ffb291f2SAdrian Lang            $file['mime'] = $mime;
453ffb291f2SAdrian Lang        }
454ffb291f2SAdrian Lang        if (!isset($file['ext'])) {
455ffb291f2SAdrian Lang            $file['ext'] = $ext;
456ffb291f2SAdrian Lang        }
457ffb291f2SAdrian Lang    }
458ffb291f2SAdrian Lang
45992cac9a9SKate Arzamastseva    global $lang, $conf;
460ffb291f2SAdrian Lang
4613df72098SAndreas Gohr    // get filename
4623543c6deSAndreas Gohr    $id   = cleanID($id);
4633df72098SAndreas Gohr    $fn   = mediaFN($id);
4643df72098SAndreas Gohr
4653df72098SAndreas Gohr    // get filetype regexp
4663df72098SAndreas Gohr    $types = array_keys(getMimeTypes());
467bad6fc0dSAndreas Gohr    $types = array_map(
46824870174SAndreas Gohr        static fn($q) => preg_quote($q, "/"),
469bad6fc0dSAndreas Gohr        $types
470bad6fc0dSAndreas Gohr    );
47124870174SAndreas Gohr    $regex = implode('|', $types);
4723df72098SAndreas Gohr
4733df72098SAndreas Gohr    // because a temp file was created already
474ffb291f2SAdrian Lang    if (!preg_match('/\.(' . $regex . ')$/i', $fn)) {
47524870174SAndreas Gohr        return [$lang['uploadwrong'], -1];
476ffb291f2SAdrian Lang    }
477ffb291f2SAdrian Lang
4783df72098SAndreas Gohr    //check for overwrite
47979e79377SAndreas Gohr    $overwrite = file_exists($fn);
480e5d185e1SKate Arzamastseva    $auth_ow = (($conf['mediarevisions']) ? AUTH_UPLOAD : AUTH_DELETE);
481e5d185e1SKate Arzamastseva    if ($overwrite && (!$ow || $auth < $auth_ow)) {
48224870174SAndreas Gohr        return [$lang['uploadexist'], 0];
4833df72098SAndreas Gohr    }
4848cb1eb01SAndreas Gohr    // check for valid content
485ffb291f2SAdrian Lang    $ok = media_contentcheck($file['name'], $file['mime']);
4868cb1eb01SAndreas Gohr    if ($ok == -1) {
48724870174SAndreas Gohr        return [sprintf($lang['uploadbadcontent'], '.' . $file['ext']), -1];
4888cb1eb01SAndreas Gohr    } elseif ($ok == -2) {
48924870174SAndreas Gohr        return [$lang['uploadspam'], -1];
49026ceae18SAndreas Gohr    } elseif ($ok == -3) {
49124870174SAndreas Gohr        return [$lang['uploadxss'], -1];
4928cb1eb01SAndreas Gohr    }
4938cb1eb01SAndreas Gohr
49411d9dfa5SMichael Klier    // prepare event data
49524870174SAndreas Gohr    $data = [];
496ffb291f2SAdrian Lang    $data[0] = $file['name'];
49711d9dfa5SMichael Klier    $data[1] = $fn;
49811d9dfa5SMichael Klier    $data[2] = $id;
499ffb291f2SAdrian Lang    $data[3] = $file['mime'];
50099c8d7f2Smichael    $data[4] = $overwrite;
501ffb291f2SAdrian Lang    $data[5] = $move;
50211d9dfa5SMichael Klier
50311d9dfa5SMichael Klier    // trigger event
504cbb44eabSAndreas Gohr    return Event::createAndTrigger('MEDIA_UPLOAD_FINISH', $data, '_media_upload_action', true);
50511d9dfa5SMichael Klier}
50611d9dfa5SMichael Klier
50711d9dfa5SMichael Klier/**
50842ea7f44SGerrit Uitslag * Callback adapter for media_upload_finish() triggered by MEDIA_UPLOAD_FINISH
50942ea7f44SGerrit Uitslag *
51011d9dfa5SMichael Klier * @author Michael Klier <chi@chimeric.de>
51142ea7f44SGerrit Uitslag *
51242ea7f44SGerrit Uitslag * @param array $data event data
51342ea7f44SGerrit Uitslag * @return false|array|string
51411d9dfa5SMichael Klier */
515d868eb89SAndreas Gohrfunction _media_upload_action($data)
516d868eb89SAndreas Gohr{
51711d9dfa5SMichael Klier    // fixme do further sanity tests of given data?
518ffb291f2SAdrian Lang    if (is_array($data) && count($data) === 6) {
519ffb291f2SAdrian Lang        return media_upload_finish($data[0], $data[1], $data[2], $data[3], $data[4], $data[5]);
52011d9dfa5SMichael Klier    } else {
52111d9dfa5SMichael Klier        return false; //callback error
52211d9dfa5SMichael Klier    }
52311d9dfa5SMichael Klier}
52411d9dfa5SMichael Klier
52511d9dfa5SMichael Klier/**
52611d9dfa5SMichael Klier * Saves an uploaded media file
52711d9dfa5SMichael Klier *
52811d9dfa5SMichael Klier * @author Andreas Gohr <andi@splitbrain.org>
52911d9dfa5SMichael Klier * @author Michael Klier <chi@chimeric.de>
530cbe26ad6SKate Arzamastseva * @author Kate Arzamastseva <pshns@ukr.net>
53142ea7f44SGerrit Uitslag *
53242ea7f44SGerrit Uitslag * @param string $fn_tmp
53342ea7f44SGerrit Uitslag * @param string $fn
53442ea7f44SGerrit Uitslag * @param string $id        media id
53542ea7f44SGerrit Uitslag * @param string $imime     mime type
53642ea7f44SGerrit Uitslag * @param bool   $overwrite overwrite existing?
53742ea7f44SGerrit Uitslag * @param string $move      function name
53842ea7f44SGerrit Uitslag * @return array|string
53911d9dfa5SMichael Klier */
540d868eb89SAndreas Gohrfunction media_upload_finish($fn_tmp, $fn, $id, $imime, $overwrite, $move = 'move_uploaded_file')
541d868eb89SAndreas Gohr{
54211d9dfa5SMichael Klier    global $conf;
54311d9dfa5SMichael Klier    global $lang;
5449c1bd4bcSKate Arzamastseva    global $REV;
54511d9dfa5SMichael Klier
546e4f389efSKate Arzamastseva    $old = @filemtime($fn);
54779e79377SAndreas Gohr    if (!file_exists(mediaFN($id, $old)) && file_exists($fn)) {
548e4f389efSKate Arzamastseva        // add old revision to the attic if missing
549cbe26ad6SKate Arzamastseva        media_saveOldRevision($id);
550e4f389efSKate Arzamastseva    }
551e4f389efSKate Arzamastseva
5523df72098SAndreas Gohr    // prepare directory
553cc7d0c94SBen Coburn    io_createNamespace($id, 'media');
55411d9dfa5SMichael Klier
555ac3ed4afSGerrit Uitslag    $filesize_old = file_exists($fn) ? filesize($fn) : 0;
556ac3ed4afSGerrit Uitslag
557ffb291f2SAdrian Lang    if ($move($fn_tmp, $fn)) {
55823846a98SKate Arzamastseva        @clearstatcache(true, $fn);
559dad6764eSKate Arzamastseva        $new = @filemtime($fn);
56074400ea5SBen Coburn        // Set the correct permission here.
56174400ea5SBen Coburn        // Always chmod media because they may be saved with different permissions than expected from the php umask.
56274400ea5SBen Coburn        // (Should normally chmod to $conf['fperm'] only if $conf['fperm'] is set.)
56374400ea5SBen Coburn        chmod($fn, $conf['fmode']);
5643df72098SAndreas Gohr        msg($lang['uploadsucc'], 1);
56583734cddSPhy        media_notify($id, $fn, $imime, $old, $new);
56699c8d7f2Smichael        // add a log entry to the media changelog
567ac3ed4afSGerrit Uitslag        $filesize_new = filesize($fn);
568ac3ed4afSGerrit Uitslag        $sizechange = $filesize_new - $filesize_old;
5699c1bd4bcSKate Arzamastseva        if ($REV) {
57064159a61SAndreas Gohr            addMediaLogEntry(
57164159a61SAndreas Gohr                $new,
57264159a61SAndreas Gohr                $id,
57364159a61SAndreas Gohr                DOKU_CHANGE_TYPE_REVERT,
57464159a61SAndreas Gohr                sprintf($lang['restored'], dformat($REV)),
57564159a61SAndreas Gohr                $REV,
57664159a61SAndreas Gohr                null,
57764159a61SAndreas Gohr                $sizechange
57864159a61SAndreas Gohr            );
5799c1bd4bcSKate Arzamastseva        } elseif ($overwrite) {
580ac3ed4afSGerrit Uitslag            addMediaLogEntry($new, $id, DOKU_CHANGE_TYPE_EDIT, '', '', null, $sizechange);
58199c8d7f2Smichael        } else {
582ac3ed4afSGerrit Uitslag            addMediaLogEntry($new, $id, DOKU_CHANGE_TYPE_CREATE, $lang['created'], '', null, $sizechange);
58399c8d7f2Smichael        }
5843df72098SAndreas Gohr        return $id;
5853df72098SAndreas Gohr    } else {
58624870174SAndreas Gohr        return [$lang['uploadfail'], -1];
5873df72098SAndreas Gohr    }
5883df72098SAndreas Gohr}
5893df72098SAndreas Gohr
5908cb1eb01SAndreas Gohr/**
591cbe26ad6SKate Arzamastseva * Moves the current version of media file to the media_attic
592cbe26ad6SKate Arzamastseva * directory
593cbe26ad6SKate Arzamastseva *
594cbe26ad6SKate Arzamastseva * @author Kate Arzamastseva <pshns@ukr.net>
59542ea7f44SGerrit Uitslag *
596cbe26ad6SKate Arzamastseva * @param string $id
597cbe26ad6SKate Arzamastseva * @return int - revision date
598e4f389efSKate Arzamastseva */
599d868eb89SAndreas Gohrfunction media_saveOldRevision($id)
600d868eb89SAndreas Gohr{
601dbf57c96SKate Arzamastseva    global $conf, $lang;
602dbf57c96SKate Arzamastseva
603e4f389efSKate Arzamastseva    $oldf = mediaFN($id);
60479e79377SAndreas Gohr    if (!file_exists($oldf)) return '';
605e4f389efSKate Arzamastseva    $date = filemtime($oldf);
606e5d185e1SKate Arzamastseva    if (!$conf['mediarevisions']) return $date;
607e5d185e1SKate Arzamastseva
608047bad06SGerrit Uitslag    $medialog = new MediaChangeLog($id);
609047bad06SGerrit Uitslag    if (!$medialog->getRevisionInfo($date)) {
610dbf57c96SKate Arzamastseva        // there was an external edit,
611dbf57c96SKate Arzamastseva        // there is no log entry for current version of file
612ac3ed4afSGerrit Uitslag        $sizechange = filesize($oldf);
61379e79377SAndreas Gohr        if (!file_exists(mediaMetaFN($id, '.changes'))) {
614ac3ed4afSGerrit Uitslag            addMediaLogEntry($date, $id, DOKU_CHANGE_TYPE_CREATE, $lang['created'], '', null, $sizechange);
615dbf57c96SKate Arzamastseva        } else {
616ac3ed4afSGerrit Uitslag            $oldRev = $medialog->getRevisions(-1, 1); // from changelog
617ac3ed4afSGerrit Uitslag            $oldRev = (int) (empty($oldRev) ? 0 : $oldRev[0]);
618ac3ed4afSGerrit Uitslag            $filesize_old = filesize(mediaFN($id, $oldRev));
61924870174SAndreas Gohr            $sizechange -= $filesize_old;
620ac3ed4afSGerrit Uitslag
621ac3ed4afSGerrit Uitslag            addMediaLogEntry($date, $id, DOKU_CHANGE_TYPE_EDIT, '', '', null, $sizechange);
622dbf57c96SKate Arzamastseva        }
623dbf57c96SKate Arzamastseva    }
624dbf57c96SKate Arzamastseva
625e4f389efSKate Arzamastseva    $newf = mediaFN($id, $date);
626e4f389efSKate Arzamastseva    io_makeFileDir($newf);
627cbe26ad6SKate Arzamastseva    if (copy($oldf, $newf)) {
628e4f389efSKate Arzamastseva        // Set the correct permission here.
629e4f389efSKate Arzamastseva        // Always chmod media because they may be saved with different permissions than expected from the php umask.
630e4f389efSKate Arzamastseva        // (Should normally chmod to $conf['fperm'] only if $conf['fperm'] is set.)
631e4f389efSKate Arzamastseva        chmod($newf, $conf['fmode']);
632e4f389efSKate Arzamastseva    }
633e4f389efSKate Arzamastseva    return $date;
634e4f389efSKate Arzamastseva}
635e4f389efSKate Arzamastseva
636e4f389efSKate Arzamastseva/**
6378cb1eb01SAndreas Gohr * This function checks if the uploaded content is really what the
63826ceae18SAndreas Gohr * mimetype says it is. We also do spam checking for text types here.
6398cb1eb01SAndreas Gohr *
6408cb1eb01SAndreas Gohr * We need to do this stuff because we can not rely on the browser
6418cb1eb01SAndreas Gohr * to do this check correctly. Yes, IE is broken as usual.
6428cb1eb01SAndreas Gohr *
6438cb1eb01SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org>
64426ceae18SAndreas Gohr * @link   http://www.splitbrain.org/blog/2007-02/12-internet_explorer_facilitates_cross_site_scripting
6458cb1eb01SAndreas Gohr * @fixme  check all 26 magic IE filetypes here?
64642ea7f44SGerrit Uitslag *
64742ea7f44SGerrit Uitslag * @param string $file path to file
64842ea7f44SGerrit Uitslag * @param string $mime mimetype
64942ea7f44SGerrit Uitslag * @return int
6508cb1eb01SAndreas Gohr */
651d868eb89SAndreas Gohrfunction media_contentcheck($file, $mime)
652d868eb89SAndreas Gohr{
65326ceae18SAndreas Gohr    global $conf;
65426ceae18SAndreas Gohr    if ($conf['iexssprotect']) {
65526ceae18SAndreas Gohr        $fh = @fopen($file, 'rb');
65626ceae18SAndreas Gohr        if ($fh) {
65726ceae18SAndreas Gohr            $bytes = fread($fh, 256);
65826ceae18SAndreas Gohr            fclose($fh);
65926ceae18SAndreas Gohr            if (preg_match('/<(script|a|img|html|body|iframe)[\s>]/i', $bytes)) {
66042ea7f44SGerrit Uitslag                return -3; //XSS: possibly malicious content
66126ceae18SAndreas Gohr            }
66226ceae18SAndreas Gohr        }
66326ceae18SAndreas Gohr    }
6646c16a3a9Sfiwswe    if (str_starts_with($mime, 'image/')) {
6658cb1eb01SAndreas Gohr        $info = @getimagesize($file);
6668cb1eb01SAndreas Gohr        if ($mime == 'image/gif' && $info[2] != 1) {
66742ea7f44SGerrit Uitslag            return -1; // uploaded content did not match the file extension
6688cb1eb01SAndreas Gohr        } elseif ($mime == 'image/jpeg' && $info[2] != 2) {
6698cb1eb01SAndreas Gohr            return -1;
6708cb1eb01SAndreas Gohr        } elseif ($mime == 'image/png' && $info[2] != 3) {
6718cb1eb01SAndreas Gohr            return -1;
6728cb1eb01SAndreas Gohr        }
6738cb1eb01SAndreas Gohr        # fixme maybe check other images types as well
6746c16a3a9Sfiwswe    } elseif (str_starts_with($mime, 'text/')) {
6758cb1eb01SAndreas Gohr        global $TEXT;
6768cb1eb01SAndreas Gohr        $TEXT = io_readFile($file);
6778cb1eb01SAndreas Gohr        if (checkwordblock()) {
67842ea7f44SGerrit Uitslag            return -2; //blocked by the spam blacklist
6798cb1eb01SAndreas Gohr        }
6808cb1eb01SAndreas Gohr    }
6818cb1eb01SAndreas Gohr    return 0;
6828cb1eb01SAndreas Gohr}
6833df72098SAndreas Gohr
6843df72098SAndreas Gohr/**
68575030359SAndreas Gohr * Send a notify mail on uploads
68675030359SAndreas Gohr *
68775030359SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org>
68842ea7f44SGerrit Uitslag *
68942ea7f44SGerrit Uitslag * @param string   $id      media id
69042ea7f44SGerrit Uitslag * @param string   $file    path to file
69142ea7f44SGerrit Uitslag * @param string   $mime    mime type
69242ea7f44SGerrit Uitslag * @param bool|int $old_rev revision timestamp or false
69375030359SAndreas Gohr */
694d868eb89SAndreas Gohrfunction media_notify($id, $file, $mime, $old_rev = false, $current_rev = false)
695d868eb89SAndreas Gohr{
69675030359SAndreas Gohr    global $conf;
69779a2d784SGerrit Uitslag    if (empty($conf['notify'])) return; //notify enabled?
69875030359SAndreas Gohr
699704a815fSMichael Große    $subscription = new MediaSubscriptionSender();
70079a2d784SGerrit Uitslag    $subscription->sendMediaDiff($conf['notify'], 'uploadmail', $id, $old_rev, $current_rev);
70175030359SAndreas Gohr}
70275030359SAndreas Gohr
70375030359SAndreas Gohr/**
7043df72098SAndreas Gohr * List all files in a given Media namespace
70542ea7f44SGerrit Uitslag *
70621d806cdSGerrit Uitslag * @param string      $ns             namespace
70742ea7f44SGerrit Uitslag * @param null|int    $auth           permission level
70842ea7f44SGerrit Uitslag * @param string      $jump           id
70942ea7f44SGerrit Uitslag * @param bool        $fullscreenview
7108702de7fSGerrit Uitslag * @param bool|string $sort           sorting order, false skips sorting
7113df72098SAndreas Gohr */
712d868eb89SAndreas Gohrfunction media_filelist($ns, $auth = null, $jump = '', $fullscreenview = false, $sort = false)
713d868eb89SAndreas Gohr{
7143df72098SAndreas Gohr    global $conf;
7153df72098SAndreas Gohr    global $lang;
7163df72098SAndreas Gohr    $ns = cleanID($ns);
7173df72098SAndreas Gohr
7183df72098SAndreas Gohr    // check auth our self if not given (needed for ajax calls)
7193df72098SAndreas Gohr    if (is_null($auth)) $auth = auth_quickaclcheck("$ns:*");
7203df72098SAndreas Gohr
721d9162c6cSKate Arzamastseva    if (!$fullscreenview) echo '<h1 id="media__ns">:' . hsc($ns) . '</h1>' . NL;
7223df72098SAndreas Gohr
7233df72098SAndreas Gohr    if ($auth < AUTH_READ) {
7243df72098SAndreas Gohr        // FIXME: print permission warning here instead?
7253df72098SAndreas Gohr        echo '<div class="nothing">' . $lang['nothingfound'] . '</div>' . NL;
72656fe6664SAndreas Gohr    } else {
72789274c0dSChristopher Smith        if (!$fullscreenview) {
72889274c0dSChristopher Smith            media_uploadform($ns, $auth);
72989274c0dSChristopher Smith            media_searchform($ns);
73089274c0dSChristopher Smith        }
7313df72098SAndreas Gohr
7323df72098SAndreas Gohr        $dir = utf8_encodeFN(str_replace(':', '/', $ns));
73324870174SAndreas Gohr        $data = [];
734dccd6b2bSAndreas Gohr        search(
735dccd6b2bSAndreas Gohr            $data,
736dccd6b2bSAndreas Gohr            $conf['mediadir'],
737dccd6b2bSAndreas Gohr            'search_mediafiles',
738dccd6b2bSAndreas Gohr            ['showmsg' => true, 'depth' => 1],
739dccd6b2bSAndreas Gohr            $dir,
740dccd6b2bSAndreas Gohr            1,
741dccd6b2bSAndreas Gohr            $sort
742dccd6b2bSAndreas Gohr        );
7433df72098SAndreas Gohr
744093fe67eSAndreas Gohr        if ($data === []) {
7453df72098SAndreas Gohr            echo '<div class="nothing">' . $lang['nothingfound'] . '</div>' . NL;
7465b9353faSKate Arzamastseva        } else {
7475b9353faSKate Arzamastseva            if ($fullscreenview) {
748554a8c9fSAdrian Lang                echo '<ul class="' . _media_get_list_type() . '">';
7495b9353faSKate Arzamastseva            }
7505b9353faSKate Arzamastseva            foreach ($data as $item) {
7515b9353faSKate Arzamastseva                if (!$fullscreenview) {
7524f33babfSAndreas Gohr                    //FIXME old call: media_printfile($item,$auth,$jump);
75379a2d784SGerrit Uitslag                    $display = new DisplayRow($item);
7549453716dSAndreas Gohr                    $display->scrollIntoView($jump == $item->getID());
7554f33babfSAndreas Gohr                    $display->show();
7565b9353faSKate Arzamastseva                } else {
7574f33babfSAndreas Gohr                    //FIXME old call: media_printfile_thumbs($item,$auth,$jump);
7584f33babfSAndreas Gohr                    echo '<li>';
75979a2d784SGerrit Uitslag                    $display = new DisplayTile($item);
7609453716dSAndreas Gohr                    $display->scrollIntoView($jump == $item->getID());
7614f33babfSAndreas Gohr                    $display->show();
7624f33babfSAndreas Gohr                    echo '</li>';
7635b9353faSKate Arzamastseva                }
7645b9353faSKate Arzamastseva            }
76594add303SAnika Henke            if ($fullscreenview) echo '</ul>' . NL;
7663df72098SAndreas Gohr        }
76756fe6664SAndreas Gohr    }
768d9162c6cSKate Arzamastseva}
769d9162c6cSKate Arzamastseva
770d9162c6cSKate Arzamastseva/**
771d9162c6cSKate Arzamastseva * Prints tabs for files list actions
772d9162c6cSKate Arzamastseva *
773d9162c6cSKate Arzamastseva * @author Kate Arzamastseva <pshns@ukr.net>
77495b451bcSAdrian Lang * @author Adrian Lang <mail@adrianlang.de>
77595b451bcSAdrian Lang *
776035e07f1SKate Arzamastseva * @param string $selected_tab - opened tab
777d9162c6cSKate Arzamastseva */
77895b451bcSAdrian Lang
779d868eb89SAndreas Gohrfunction media_tabs_files($selected_tab = '')
780d868eb89SAndreas Gohr{
781d9162c6cSKate Arzamastseva    global $lang;
78224870174SAndreas Gohr    $tabs = [];
7837d34963bSAndreas Gohr    foreach (
7847d34963bSAndreas Gohr        [
78524870174SAndreas Gohr            'files' => 'mediaselect',
78695b451bcSAdrian Lang            'upload' => 'media_uploadtab',
78724870174SAndreas Gohr            'search' => 'media_searchtab'
7887d34963bSAndreas Gohr        ] as $tab => $caption
7897d34963bSAndreas Gohr    ) {
79024870174SAndreas Gohr        $tabs[$tab] = [
79124870174SAndreas Gohr            'href'    => media_managerURL(['tab_files' => $tab], '&'),
79224870174SAndreas Gohr            'caption' => $lang[$caption]
79324870174SAndreas Gohr        ];
79495b451bcSAdrian Lang    }
795d9162c6cSKate Arzamastseva
79695b451bcSAdrian Lang    html_tabs($tabs, $selected_tab);
797d9162c6cSKate Arzamastseva}
798d9162c6cSKate Arzamastseva
799d9162c6cSKate Arzamastseva/**
800d9162c6cSKate Arzamastseva * Prints tabs for files details actions
801d9162c6cSKate Arzamastseva *
802d9162c6cSKate Arzamastseva * @author Kate Arzamastseva <pshns@ukr.net>
803ebc28e69SAndreas Gohr * @param string $image filename of the current image
804ebc28e69SAndreas Gohr * @param string $selected_tab opened tab
805d9162c6cSKate Arzamastseva */
806d868eb89SAndreas Gohrfunction media_tabs_details($image, $selected_tab = '')
807d868eb89SAndreas Gohr{
808e5d185e1SKate Arzamastseva    global $lang, $conf;
809d9162c6cSKate Arzamastseva
81024870174SAndreas Gohr    $tabs = [];
81124870174SAndreas Gohr    $tabs['view'] = [
81224870174SAndreas Gohr        'href'    => media_managerURL(['tab_details' => 'view'], '&'),
81324870174SAndreas Gohr        'caption' => $lang['media_viewtab']
81424870174SAndreas Gohr    ];
815d9162c6cSKate Arzamastseva
81624870174SAndreas Gohr    [, $mime] = mimetype($image);
81779e79377SAndreas Gohr    if ($mime == 'image/jpeg' && file_exists(mediaFN($image))) {
81824870174SAndreas Gohr        $tabs['edit'] = [
81924870174SAndreas Gohr            'href'    => media_managerURL(['tab_details' => 'edit'], '&'),
82024870174SAndreas Gohr            'caption' => $lang['media_edittab']
82124870174SAndreas Gohr        ];
822dd9ba38eSKate Arzamastseva    }
823e5d185e1SKate Arzamastseva    if ($conf['mediarevisions']) {
82424870174SAndreas Gohr        $tabs['history'] = [
82524870174SAndreas Gohr            'href'    => media_managerURL(['tab_details' => 'history'], '&'),
82624870174SAndreas Gohr            'caption' => $lang['media_historytab']
82724870174SAndreas Gohr        ];
828e5d185e1SKate Arzamastseva    }
829d9162c6cSKate Arzamastseva
83095b451bcSAdrian Lang    html_tabs($tabs, $selected_tab);
831d9162c6cSKate Arzamastseva}
832d9162c6cSKate Arzamastseva
833d9162c6cSKate Arzamastseva/**
834d9162c6cSKate Arzamastseva * Prints options for the tab that displays a list of all files
835d9162c6cSKate Arzamastseva *
836d9162c6cSKate Arzamastseva * @author Kate Arzamastseva <pshns@ukr.net>
837d9162c6cSKate Arzamastseva */
838d868eb89SAndreas Gohrfunction media_tab_files_options()
839d868eb89SAndreas Gohr{
8408108113cSTom N Harris    global $lang;
8418108113cSTom N Harris    global $INPUT;
842b7e5821dSAndreas Gohr    global $ID;
843b960c74fSSatoshi Sahara
844b960c74fSSatoshi Sahara    $form = new Form([
845b960c74fSSatoshi Sahara            'method' => 'get',
846b960c74fSSatoshi Sahara            'action' => wl($ID),
847b960c74fSSatoshi Sahara            'class' => 'options'
848b960c74fSSatoshi Sahara    ]);
849b960c74fSSatoshi Sahara    $form->addTagOpen('div')->addClass('no');
850b960c74fSSatoshi Sahara    $form->setHiddenField('sectok', null);
851b960c74fSSatoshi Sahara    $media_manager_params = media_managerURL([], '', false, true);
85238b2bf35SAnika Henke    foreach ($media_manager_params as $pKey => $pVal) {
853b960c74fSSatoshi Sahara        $form->setHiddenField($pKey, $pVal);
85438b2bf35SAnika Henke    }
8558108113cSTom N Harris    if ($INPUT->has('q')) {
856b960c74fSSatoshi Sahara        $form->setHiddenField('q', $INPUT->str('q'));
857554a8c9fSAdrian Lang    }
858b960c74fSSatoshi Sahara    $form->addHTML('<ul>' . NL);
8597d34963bSAndreas Gohr    foreach (
8607d34963bSAndreas Gohr        [
86124870174SAndreas Gohr            'list' => ['listType', ['thumbs', 'rows']],
86224870174SAndreas Gohr            'sort' => ['sortBy', ['name', 'date']]
8637d34963bSAndreas Gohr        ] as $group => $content
8647d34963bSAndreas Gohr    ) {
865ec88e837SAndreas Gohr        $checked = "_media_get_{$group}_type";
866554a8c9fSAdrian Lang        $checked = $checked();
867d9162c6cSKate Arzamastseva
868b960c74fSSatoshi Sahara        $form->addHTML('<li class="' . $content[0] . '">');
86995b451bcSAdrian Lang        foreach ($content[1] as $option) {
87024870174SAndreas Gohr            $attrs = [];
871554a8c9fSAdrian Lang            if ($checked == $option) {
87295b451bcSAdrian Lang                $attrs['checked'] = 'checked';
87395b451bcSAdrian Lang            }
874b960c74fSSatoshi Sahara            $radio = $form->addRadioButton(
875b960c74fSSatoshi Sahara                $group . '_dwmedia',
876b960c74fSSatoshi Sahara                $lang['media_' . $group . '_' . $option]
877b960c74fSSatoshi Sahara            )->val($option)->id($content[0] . '__' . $option)->addClass($option);
878b960c74fSSatoshi Sahara            $radio->attrs($attrs);
87995b451bcSAdrian Lang        }
880b960c74fSSatoshi Sahara        $form->addHTML('</li>' . NL);
88195b451bcSAdrian Lang    }
882b960c74fSSatoshi Sahara    $form->addHTML('<li>');
883b960c74fSSatoshi Sahara    $form->addButton('', $lang['btn_apply'])->attr('type', 'submit');
884b960c74fSSatoshi Sahara    $form->addHTML('</li>' . NL);
885b960c74fSSatoshi Sahara    $form->addHTML('</ul>' . NL);
886b960c74fSSatoshi Sahara    $form->addTagClose('div');
88726dfc232SAndreas Gohr    echo $form->toHTML();
888d9162c6cSKate Arzamastseva}
889d9162c6cSKate Arzamastseva
890d9162c6cSKate Arzamastseva/**
89187deddfaSKate Arzamastseva * Returns type of sorting for the list of files in media manager
89287deddfaSKate Arzamastseva *
89387deddfaSKate Arzamastseva * @author Kate Arzamastseva <pshns@ukr.net>
89442ea7f44SGerrit Uitslag *
89587deddfaSKate Arzamastseva * @return string - sort type
89687deddfaSKate Arzamastseva */
897d868eb89SAndreas Gohrfunction _media_get_sort_type()
898d868eb89SAndreas Gohr{
89924870174SAndreas Gohr    return _media_get_display_param('sort', ['default' => 'name', 'date']);
90087deddfaSKate Arzamastseva}
901554a8c9fSAdrian Lang
9026ffaeda9SGerrit Uitslag/**
9036ffaeda9SGerrit Uitslag * Returns type of listing for the list of files in media manager
9046ffaeda9SGerrit Uitslag *
9056ffaeda9SGerrit Uitslag * @author Kate Arzamastseva <pshns@ukr.net>
90642ea7f44SGerrit Uitslag *
9076ffaeda9SGerrit Uitslag * @return string - list type
9086ffaeda9SGerrit Uitslag */
909d868eb89SAndreas Gohrfunction _media_get_list_type()
910d868eb89SAndreas Gohr{
91124870174SAndreas Gohr    return _media_get_display_param('list', ['default' => 'thumbs', 'rows']);
91287deddfaSKate Arzamastseva}
913554a8c9fSAdrian Lang
9146ffaeda9SGerrit Uitslag/**
9156ffaeda9SGerrit Uitslag * Get display parameters
9166ffaeda9SGerrit Uitslag *
9176ffaeda9SGerrit Uitslag * @param string $param   name of parameter
9186ffaeda9SGerrit Uitslag * @param array  $values  allowed values, where default value has index key 'default'
9196ffaeda9SGerrit Uitslag * @return string the parameter value
9206ffaeda9SGerrit Uitslag */
921d868eb89SAndreas Gohrfunction _media_get_display_param($param, $values)
922d868eb89SAndreas Gohr{
9238108113cSTom N Harris    global $INPUT;
9248108113cSTom N Harris    if (in_array($INPUT->str($param), $values)) {
925554a8c9fSAdrian Lang        // FIXME: Set cookie
9268108113cSTom N Harris        return $INPUT->str($param);
927554a8c9fSAdrian Lang    } else {
9283629bc8cSAdrian Lang        $val = get_doku_pref($param, $values['default']);
9293629bc8cSAdrian Lang        if (!in_array($val, $values)) {
9303629bc8cSAdrian Lang            $val = $values['default'];
9313629bc8cSAdrian Lang        }
9323629bc8cSAdrian Lang        return $val;
933554a8c9fSAdrian Lang    }
93487deddfaSKate Arzamastseva}
93587deddfaSKate Arzamastseva
93687deddfaSKate Arzamastseva/**
937d9162c6cSKate Arzamastseva * Prints tab that displays a list of all files
938d9162c6cSKate Arzamastseva *
939d9162c6cSKate Arzamastseva * @author Kate Arzamastseva <pshns@ukr.net>
94042ea7f44SGerrit Uitslag *
94142ea7f44SGerrit Uitslag * @param string    $ns
94242ea7f44SGerrit Uitslag * @param null|int  $auth permission level
94342ea7f44SGerrit Uitslag * @param string    $jump item id
944d9162c6cSKate Arzamastseva */
945d868eb89SAndreas Gohrfunction media_tab_files($ns, $auth = null, $jump = '')
946d868eb89SAndreas Gohr{
947d9162c6cSKate Arzamastseva    global $lang;
948d9162c6cSKate Arzamastseva    if (is_null($auth)) $auth = auth_quickaclcheck("$ns:*");
949d9162c6cSKate Arzamastseva
950d9162c6cSKate Arzamastseva    if ($auth < AUTH_READ) {
95188a71175SKate Arzamastseva        echo '<div class="nothing">' . $lang['media_perm_read'] . '</div>' . NL;
952d9162c6cSKate Arzamastseva    } else {
95395b451bcSAdrian Lang        media_filelist($ns, $auth, $jump, true, _media_get_sort_type());
954d9162c6cSKate Arzamastseva    }
955d9162c6cSKate Arzamastseva}
956d9162c6cSKate Arzamastseva
957d9162c6cSKate Arzamastseva/**
958d9162c6cSKate Arzamastseva * Prints tab that displays uploading form
959d9162c6cSKate Arzamastseva *
960d9162c6cSKate Arzamastseva * @author Kate Arzamastseva <pshns@ukr.net>
96142ea7f44SGerrit Uitslag *
96242ea7f44SGerrit Uitslag * @param string   $ns
96342ea7f44SGerrit Uitslag * @param null|int $auth permission level
96442ea7f44SGerrit Uitslag * @param string   $jump item id
965d9162c6cSKate Arzamastseva */
966d868eb89SAndreas Gohrfunction media_tab_upload($ns, $auth = null, $jump = '')
967d868eb89SAndreas Gohr{
968d9162c6cSKate Arzamastseva    global $lang;
969d9162c6cSKate Arzamastseva    if (is_null($auth)) $auth = auth_quickaclcheck("$ns:*");
970d9162c6cSKate Arzamastseva
97194add303SAnika Henke    echo '<div class="upload">' . NL;
97295b451bcSAdrian Lang    if ($auth >= AUTH_UPLOAD) {
97395b451bcSAdrian Lang        echo '<p>' . $lang['mediaupload'] . '</p>';
97495b451bcSAdrian Lang    }
975d9162c6cSKate Arzamastseva    media_uploadform($ns, $auth, true);
97694add303SAnika Henke    echo '</div>' . NL;
977d9162c6cSKate Arzamastseva}
978d9162c6cSKate Arzamastseva
979d9162c6cSKate Arzamastseva/**
980d9162c6cSKate Arzamastseva * Prints tab that displays search form
981d9162c6cSKate Arzamastseva *
982d9162c6cSKate Arzamastseva * @author Kate Arzamastseva <pshns@ukr.net>
98342ea7f44SGerrit Uitslag *
98442ea7f44SGerrit Uitslag * @param string $ns
98542ea7f44SGerrit Uitslag * @param null|int $auth permission level
986d9162c6cSKate Arzamastseva */
987d868eb89SAndreas Gohrfunction media_tab_search($ns, $auth = null)
988d868eb89SAndreas Gohr{
9898108113cSTom N Harris    global $INPUT;
990d9162c6cSKate Arzamastseva
9918108113cSTom N Harris    $do = $INPUT->str('mediado');
9928108113cSTom N Harris    $query = $INPUT->str('q');
99394add303SAnika Henke    echo '<div class="search">' . NL;
994d9162c6cSKate Arzamastseva
995d9162c6cSKate Arzamastseva    media_searchform($ns, $query, true);
9962dba8df4SAdrian Lang    if ($do == 'searchlist' || $query) {
99795b451bcSAdrian Lang        media_searchlist($query, $ns, $auth, true, _media_get_sort_type());
99895b451bcSAdrian Lang    }
99994add303SAnika Henke    echo '</div>' . NL;
1000d9162c6cSKate Arzamastseva}
1001d9162c6cSKate Arzamastseva
1002d9162c6cSKate Arzamastseva/**
1003d9162c6cSKate Arzamastseva * Prints tab that displays mediafile details
1004d9162c6cSKate Arzamastseva *
1005d9162c6cSKate Arzamastseva * @author Kate Arzamastseva <pshns@ukr.net>
1006e0c26282SGerrit Uitslag *
1007e0c26282SGerrit Uitslag * @param string     $image media id
1008e0c26282SGerrit Uitslag * @param string     $ns
1009e0c26282SGerrit Uitslag * @param null|int   $auth  permission level
101042ea7f44SGerrit Uitslag * @param string|int $rev   revision timestamp or empty string
1011d9162c6cSKate Arzamastseva */
1012d868eb89SAndreas Gohrfunction media_tab_view($image, $ns, $auth = null, $rev = '')
1013d868eb89SAndreas Gohr{
1014ebc28e69SAndreas Gohr    global $lang;
1015d9162c6cSKate Arzamastseva    if (is_null($auth)) $auth = auth_quickaclcheck("$ns:*");
1016d9162c6cSKate Arzamastseva
1017e136d6ccSKate Arzamastseva    if ($image && $auth >= AUTH_READ) {
1018dd9e8e5eSAndreas Gohr        $mf = new MediaFile($image, $rev);
1019dd9e8e5eSAndreas Gohr        echo (new Display($mf))->getDetailHtml();
1020e136d6ccSKate Arzamastseva        media_preview_buttons($image, $auth, $rev);
1021dd9e8e5eSAndreas Gohr        media_details($image, $auth, $rev, $mf->getMeta());
1022e136d6ccSKate Arzamastseva    } else {
102394add303SAnika Henke        echo '<div class="nothing">' . $lang['media_perm_read'] . '</div>' . NL;
1024e136d6ccSKate Arzamastseva    }
1025d9162c6cSKate Arzamastseva}
1026d9162c6cSKate Arzamastseva
1027d9162c6cSKate Arzamastseva/**
1028d9162c6cSKate Arzamastseva * Prints tab that displays form for editing mediafile metadata
1029d9162c6cSKate Arzamastseva *
1030d9162c6cSKate Arzamastseva * @author Kate Arzamastseva <pshns@ukr.net>
1031e0c26282SGerrit Uitslag *
1032e0c26282SGerrit Uitslag * @param string     $image media id
1033e0c26282SGerrit Uitslag * @param string     $ns
1034e0c26282SGerrit Uitslag * @param null|int   $auth permission level
1035d9162c6cSKate Arzamastseva */
1036d868eb89SAndreas Gohrfunction media_tab_edit($image, $ns, $auth = null)
1037d868eb89SAndreas Gohr{
1038d9162c6cSKate Arzamastseva    if (is_null($auth)) $auth = auth_quickaclcheck("$ns:*");
1039d9162c6cSKate Arzamastseva
10401eeeced2SKate Arzamastseva    if ($image) {
104124870174SAndreas Gohr        [, $mime] = mimetype($image);
104230fd72fbSKate Arzamastseva        if ($mime == 'image/jpeg') media_metaform($image, $auth);
10431eeeced2SKate Arzamastseva    }
1044d9162c6cSKate Arzamastseva}
1045d9162c6cSKate Arzamastseva
1046d9162c6cSKate Arzamastseva/**
1047d9162c6cSKate Arzamastseva * Prints tab that displays mediafile revisions
1048d9162c6cSKate Arzamastseva *
1049d9162c6cSKate Arzamastseva * @author Kate Arzamastseva <pshns@ukr.net>
1050e0c26282SGerrit Uitslag *
1051e0c26282SGerrit Uitslag * @param string     $image media id
1052e0c26282SGerrit Uitslag * @param string     $ns
1053e0c26282SGerrit Uitslag * @param null|int   $auth permission level
1054d9162c6cSKate Arzamastseva */
1055d868eb89SAndreas Gohrfunction media_tab_history($image, $ns, $auth = null)
1056d868eb89SAndreas Gohr{
1057d9162c6cSKate Arzamastseva    global $lang;
10588108113cSTom N Harris    global $INPUT;
10598108113cSTom N Harris
1060d9162c6cSKate Arzamastseva    if (is_null($auth)) $auth = auth_quickaclcheck("$ns:*");
10618108113cSTom N Harris    $do = $INPUT->str('mediado');
1062d9162c6cSKate Arzamastseva
10632e55802cSKate Arzamastseva    if ($auth >= AUTH_READ && $image) {
10642e55802cSKate Arzamastseva        if ($do == 'diff') {
106524870174SAndreas Gohr            (new MediaDiff($image))->show(); //media_diff($image, $ns, $auth);
10662e55802cSKate Arzamastseva        } else {
1067a46cc3dcSAndreas Gohr            $first = $INPUT->int('first', -1);
106824870174SAndreas Gohr            (new MediaRevisions($image))->show($first);
10692e55802cSKate Arzamastseva        }
107088a71175SKate Arzamastseva    } else {
107188a71175SKate Arzamastseva        echo '<div class="nothing">' . $lang['media_perm_read'] . '</div>' . NL;
10722e55802cSKate Arzamastseva    }
10733df72098SAndreas Gohr}
10743df72098SAndreas Gohr
10753df72098SAndreas Gohr/**
1076e136d6ccSKate Arzamastseva * Prints mediafile action buttons
1077e136d6ccSKate Arzamastseva *
1078e136d6ccSKate Arzamastseva * @author Kate Arzamastseva <pshns@ukr.net>
1079e0c26282SGerrit Uitslag *
1080e0c26282SGerrit Uitslag * @param string     $image media id
1081e0c26282SGerrit Uitslag * @param int        $auth  permission level
1082871895a7SSatoshi Sahara * @param int|string $rev   revision timestamp, or empty string
1083e136d6ccSKate Arzamastseva */
1084d868eb89SAndreas Gohrfunction media_preview_buttons($image, $auth, $rev = '')
1085d868eb89SAndreas Gohr{
1086e5d185e1SKate Arzamastseva    global $lang, $conf;
1087e136d6ccSKate Arzamastseva
1088871895a7SSatoshi Sahara    echo '<ul class="actions">';
10891eeeced2SKate Arzamastseva
109079e79377SAndreas Gohr    if ($auth >= AUTH_DELETE && !$rev && file_exists(mediaFN($image))) {
1091e136d6ccSKate Arzamastseva        // delete button
1092b960c74fSSatoshi Sahara        $form = new Form([
1093b960c74fSSatoshi Sahara            'id' => 'mediamanager__btn_delete',
1094b960c74fSSatoshi Sahara            'action' => media_managerURL(['delete' => $image], '&'),
1095b960c74fSSatoshi Sahara        ]);
1096b960c74fSSatoshi Sahara        $form->addTagOpen('div')->addClass('no');
1097b960c74fSSatoshi Sahara        $form->addButton('', $lang['btn_delete'])->attr('type', 'submit');
1098b960c74fSSatoshi Sahara        $form->addTagClose('div');
109995b451bcSAdrian Lang        echo '<li>';
1100b960c74fSSatoshi Sahara        echo $form->toHTML();
1101871895a7SSatoshi Sahara        echo '</li>';
1102e5d185e1SKate Arzamastseva    }
1103e5d185e1SKate Arzamastseva
1104e5d185e1SKate Arzamastseva    $auth_ow = (($conf['mediarevisions']) ? AUTH_UPLOAD : AUTH_DELETE);
1105e5d185e1SKate Arzamastseva    if ($auth >= $auth_ow && !$rev) {
1106e136d6ccSKate Arzamastseva        // upload new version button
1107b960c74fSSatoshi Sahara        $form = new Form([
1108b960c74fSSatoshi Sahara            'id' => 'mediamanager__btn_update',
1109b960c74fSSatoshi Sahara            'action' => media_managerURL(['image' => $image, 'mediado' => 'update'], '&'),
1110b960c74fSSatoshi Sahara        ]);
1111b960c74fSSatoshi Sahara        $form->addTagOpen('div')->addClass('no');
1112b960c74fSSatoshi Sahara        $form->addButton('', $lang['media_update'])->attr('type', 'submit');
1113b960c74fSSatoshi Sahara        $form->addTagClose('div');
111495b451bcSAdrian Lang        echo '<li>';
1115b960c74fSSatoshi Sahara        echo $form->toHTML();
1116871895a7SSatoshi Sahara        echo '</li>';
111770c3cc9aSKate Arzamastseva    }
1118e136d6ccSKate Arzamastseva
111979e79377SAndreas Gohr    if ($auth >= AUTH_UPLOAD && $rev && $conf['mediarevisions'] && file_exists(mediaFN($image, $rev))) {
1120e136d6ccSKate Arzamastseva        // restore button
1121b960c74fSSatoshi Sahara        $form = new Form([
1122b960c74fSSatoshi Sahara            'id' => 'mediamanager__btn_restore',
1123b960c74fSSatoshi Sahara            'action' => media_managerURL(['image' => $image], '&'),
1124b960c74fSSatoshi Sahara        ]);
1125b960c74fSSatoshi Sahara        $form->addTagOpen('div')->addClass('no');
1126b960c74fSSatoshi Sahara        $form->setHiddenField('mediado', 'restore');
1127b960c74fSSatoshi Sahara        $form->setHiddenField('rev', $rev);
1128b960c74fSSatoshi Sahara        $form->addButton('', $lang['media_restore'])->attr('type', 'submit');
1129b960c74fSSatoshi Sahara        $form->addTagClose('div');
113095b451bcSAdrian Lang        echo '<li>';
1131b960c74fSSatoshi Sahara        echo $form->toHTML();
1132871895a7SSatoshi Sahara        echo '</li>';
11339c1bd4bcSKate Arzamastseva    }
1134e136d6ccSKate Arzamastseva
1135871895a7SSatoshi Sahara    echo '</ul>';
11362e55802cSKate Arzamastseva}
11372e55802cSKate Arzamastseva
11382e55802cSKate Arzamastseva/**
1139fa8e5c77SKate Arzamastseva * Returns the requested EXIF/IPTC tag from the image meta
1140fa8e5c77SKate Arzamastseva *
1141fa8e5c77SKate Arzamastseva * @author Kate Arzamastseva <pshns@ukr.net>
1142e0c26282SGerrit Uitslag *
114342ea7f44SGerrit Uitslag * @param array    $tags array with tags, first existing is returned
1144fa8e5c77SKate Arzamastseva * @param JpegMeta $meta
114542ea7f44SGerrit Uitslag * @param string   $alt  alternative value
1146fa8e5c77SKate Arzamastseva * @return string
1147fa8e5c77SKate Arzamastseva */
1148d868eb89SAndreas Gohrfunction media_getTag($tags, $meta = false, $alt = '')
1149d868eb89SAndreas Gohr{
1150871895a7SSatoshi Sahara    if (!$meta) return $alt;
1151fa8e5c77SKate Arzamastseva    $info = $meta->getField($tags);
1152871895a7SSatoshi Sahara    if (!$info) return $alt;
1153fa8e5c77SKate Arzamastseva    return $info;
1154fa8e5c77SKate Arzamastseva}
1155fa8e5c77SKate Arzamastseva
1156fa8e5c77SKate Arzamastseva/**
1157e136d6ccSKate Arzamastseva * Returns mediafile tags
11582e55802cSKate Arzamastseva *
11592e55802cSKate Arzamastseva * @author Kate Arzamastseva <pshns@ukr.net>
1160e0c26282SGerrit Uitslag *
1161e136d6ccSKate Arzamastseva * @param JpegMeta $meta
116242ea7f44SGerrit Uitslag * @return array list of tags of the mediafile
11632e55802cSKate Arzamastseva */
1164d868eb89SAndreas Gohrfunction media_file_tags($meta)
1165d868eb89SAndreas Gohr{
1166532850edSKate Arzamastseva    // load the field descriptions
11673e98e685SKate Arzamastseva    static $fields = null;
11683e98e685SKate Arzamastseva    if (is_null($fields)) {
11693e98e685SKate Arzamastseva        $config_files = getConfigFiles('mediameta');
11703e98e685SKate Arzamastseva        foreach ($config_files as $config_file) {
117179e79377SAndreas Gohr            if (file_exists($config_file)) include($config_file);
1172532850edSKate Arzamastseva        }
1173532850edSKate Arzamastseva    }
11741eeeced2SKate Arzamastseva
117524870174SAndreas Gohr    $tags = [];
1176dd9ba38eSKate Arzamastseva
117724870174SAndreas Gohr    foreach ($fields as $tag) {
117824870174SAndreas Gohr        $t = [];
117924870174SAndreas Gohr        if (!empty($tag[0])) $t = [$tag[0]];
11800e80bb5eSChristopher Smith        if (isset($tag[3]) && is_array($tag[3])) $t = array_merge($t, $tag[3]);
1181e136d6ccSKate Arzamastseva        $value = media_getTag($t, $meta);
118224870174SAndreas Gohr        $tags[] = ['tag' => $tag, 'value' => $value];
1183e136d6ccSKate Arzamastseva    }
1184e136d6ccSKate Arzamastseva
1185e136d6ccSKate Arzamastseva    return $tags;
1186e136d6ccSKate Arzamastseva}
1187e136d6ccSKate Arzamastseva
1188e136d6ccSKate Arzamastseva/**
1189e136d6ccSKate Arzamastseva * Prints mediafile tags
1190e136d6ccSKate Arzamastseva *
1191e136d6ccSKate Arzamastseva * @author Kate Arzamastseva <pshns@ukr.net>
119242ea7f44SGerrit Uitslag *
1193e0c26282SGerrit Uitslag * @param string        $image image id
1194e0c26282SGerrit Uitslag * @param int           $auth  permission level
1195e0c26282SGerrit Uitslag * @param string|int    $rev   revision timestamp, or empty string
1196e0c26282SGerrit Uitslag * @param bool|JpegMeta $meta  image object, or create one if false
1197e0c26282SGerrit Uitslag */
1198d868eb89SAndreas Gohrfunction media_details($image, $auth, $rev = '', $meta = false)
1199d868eb89SAndreas Gohr{
1200e136d6ccSKate Arzamastseva    global $lang;
1201e136d6ccSKate Arzamastseva
1202e136d6ccSKate Arzamastseva    if (!$meta) $meta = new JpegMeta(mediaFN($image, $rev));
1203e136d6ccSKate Arzamastseva    $tags = media_file_tags($meta);
1204e136d6ccSKate Arzamastseva
120594add303SAnika Henke    echo '<dl>' . NL;
1206e136d6ccSKate Arzamastseva    foreach ($tags as $tag) {
1207e136d6ccSKate Arzamastseva        if ($tag['value']) {
1208e136d6ccSKate Arzamastseva            $value = cleanText($tag['value']);
1209fde860beSGerrit Uitslag            echo '<dt>' . $lang[$tag['tag'][1]] . '</dt><dd>';
12104a90f94bSSatoshi Sahara            if ($tag['tag'][2] == 'date') {
12114a90f94bSSatoshi Sahara                echo dformat($value);
12124a90f94bSSatoshi Sahara            } else {
12134a90f94bSSatoshi Sahara                echo hsc($value);
12144a90f94bSSatoshi Sahara            }
121594add303SAnika Henke            echo '</dd>' . NL;
12161eeeced2SKate Arzamastseva        }
1217e136d6ccSKate Arzamastseva    }
121894add303SAnika Henke    echo '</dl>' . NL;
121922e68399Sflammy    echo '<dl>' . NL;
122022e68399Sflammy    echo '<dt>' . $lang['reference'] . ':</dt>';
12216734bb8cSAndreas Gohr    $media_usage = (new MetadataSearch())->mediause($image, true);
122224870174SAndreas Gohr    if ($media_usage !== []) {
122322e68399Sflammy        foreach ($media_usage as $path) {
122422e68399Sflammy            echo '<dd>' . html_wikilink($path) . '</dd>';
122522e68399Sflammy        }
122622e68399Sflammy    } else {
122722e68399Sflammy        echo '<dd>' . $lang['nothingfound'] . '</dd>';
122822e68399Sflammy    }
122922e68399Sflammy    echo '</dl>' . NL;
12301eeeced2SKate Arzamastseva}
12312e55802cSKate Arzamastseva
12322e55802cSKate Arzamastseva/**
12332e55802cSKate Arzamastseva * Shows difference between two revisions of file
12342e55802cSKate Arzamastseva *
12352e55802cSKate Arzamastseva * @author Kate Arzamastseva <pshns@ukr.net>
123642ea7f44SGerrit Uitslag *
1237e0c26282SGerrit Uitslag * @param string $image  image id
1238e0c26282SGerrit Uitslag * @param string $ns
1239e0c26282SGerrit Uitslag * @param int $auth permission level
1240e0c26282SGerrit Uitslag * @param bool $fromajax
124179a2d784SGerrit Uitslag *
1242297071beSSatoshi Sahara * @deprecated 2020-12-31
1243e0c26282SGerrit Uitslag */
1244d868eb89SAndreas Gohrfunction media_diff($image, $ns, $auth, $fromajax = false)
1245d868eb89SAndreas Gohr{
124679a2d784SGerrit Uitslag    dbg_deprecated('see ' . MediaDiff::class . '::show()');
124759e81a43SKate Arzamastseva}
124859e81a43SKate Arzamastseva
12496ffaeda9SGerrit Uitslag/**
12506ffaeda9SGerrit Uitslag * Callback for media file diff
12516ffaeda9SGerrit Uitslag *
125242ea7f44SGerrit Uitslag * @param array $data event data
125379a2d784SGerrit Uitslag *
1254297071beSSatoshi Sahara * @deprecated 2020-12-31
12556ffaeda9SGerrit Uitslag */
1256d868eb89SAndreas Gohrfunction _media_file_diff($data)
1257d868eb89SAndreas Gohr{
125879a2d784SGerrit Uitslag    dbg_deprecated('see ' . MediaDiff::class . '::show()');
125959e81a43SKate Arzamastseva}
126059e81a43SKate Arzamastseva
126159e81a43SKate Arzamastseva/**
126259e81a43SKate Arzamastseva * Shows difference between two revisions of image
126359e81a43SKate Arzamastseva *
126459e81a43SKate Arzamastseva * @author Kate Arzamastseva <pshns@ukr.net>
1265e0c26282SGerrit Uitslag *
1266e0c26282SGerrit Uitslag * @param string $image
1267e0c26282SGerrit Uitslag * @param string|int $l_rev revision timestamp, or empty string
1268e0c26282SGerrit Uitslag * @param string|int $r_rev revision timestamp, or empty string
1269e0c26282SGerrit Uitslag * @param string $ns
1270e0c26282SGerrit Uitslag * @param int $auth permission level
1271e0c26282SGerrit Uitslag * @param bool $fromajax
1272297071beSSatoshi Sahara * @deprecated 2020-12-31
127359e81a43SKate Arzamastseva */
1274d868eb89SAndreas Gohrfunction media_file_diff($image, $l_rev, $r_rev, $ns, $auth, $fromajax)
1275d868eb89SAndreas Gohr{
127679a2d784SGerrit Uitslag    dbg_deprecated('see ' . MediaDiff::class . '::showFileDiff()');
1277e136d6ccSKate Arzamastseva}
1278e136d6ccSKate Arzamastseva
1279e136d6ccSKate Arzamastseva/**
1280e136d6ccSKate Arzamastseva * Prints two images side by side
1281fa8e5c77SKate Arzamastseva * and slider
1282e136d6ccSKate Arzamastseva *
1283e136d6ccSKate Arzamastseva * @author Kate Arzamastseva <pshns@ukr.net>
128442ea7f44SGerrit Uitslag *
128542ea7f44SGerrit Uitslag * @param string $image   image id
1286e0c26282SGerrit Uitslag * @param int    $l_rev   revision timestamp, or empty string
1287e0c26282SGerrit Uitslag * @param int    $r_rev   revision timestamp, or empty string
128842ea7f44SGerrit Uitslag * @param array  $l_size  array with width and height
128942ea7f44SGerrit Uitslag * @param array  $r_size  array with width and height
129050fc55feSKate Arzamastseva * @param string $type
1291297071beSSatoshi Sahara * @deprecated 2020-12-31
1292e136d6ccSKate Arzamastseva */
1293d868eb89SAndreas Gohrfunction media_image_diff($image, $l_rev, $r_rev, $l_size, $r_size, $type)
1294d868eb89SAndreas Gohr{
129579a2d784SGerrit Uitslag    dbg_deprecated('see ' . MediaDiff::class . '::showImageDiff()');
12961eeeced2SKate Arzamastseva}
12971eeeced2SKate Arzamastseva
12981eeeced2SKate Arzamastseva/**
12999c1bd4bcSKate Arzamastseva * Restores an old revision of a media file
13009c1bd4bcSKate Arzamastseva *
130142ea7f44SGerrit Uitslag * @param string $image media id
130242ea7f44SGerrit Uitslag * @param int    $rev   revision timestamp or empty string
13039c1bd4bcSKate Arzamastseva * @param int    $auth
13049c1bd4bcSKate Arzamastseva * @return string - file's id
130542ea7f44SGerrit Uitslag *
13069c1bd4bcSKate Arzamastseva * @author Kate Arzamastseva <pshns@ukr.net>
13079c1bd4bcSKate Arzamastseva */
1308d868eb89SAndreas Gohrfunction media_restore($image, $rev, $auth)
1309d868eb89SAndreas Gohr{
1310e5d185e1SKate Arzamastseva    global $conf;
131180525638SKate Arzamastseva    if ($auth < AUTH_UPLOAD || !$conf['mediarevisions']) return false;
131292cac9a9SKate Arzamastseva    $removed = (!file_exists(mediaFN($image)) && file_exists(mediaMetaFN($image, '.changes')));
131392cac9a9SKate Arzamastseva    if (!$image || (!file_exists(mediaFN($image)) && !$removed)) return false;
13149c1bd4bcSKate Arzamastseva    if (!$rev || !file_exists(mediaFN($image, $rev))) return false;
131524870174SAndreas Gohr    [, $imime, ] = mimetype($image);
1316dccd6b2bSAndreas Gohr    $res = media_upload_finish(
1317dccd6b2bSAndreas Gohr        mediaFN($image, $rev),
13189c1bd4bcSKate Arzamastseva        mediaFN($image),
13199c1bd4bcSKate Arzamastseva        $image,
13209c1bd4bcSKate Arzamastseva        $imime,
13219c1bd4bcSKate Arzamastseva        true,
1322dccd6b2bSAndreas Gohr        'copy'
1323dccd6b2bSAndreas Gohr    );
13249c1bd4bcSKate Arzamastseva    if (is_array($res)) {
13259c1bd4bcSKate Arzamastseva        msg($res[0], $res[1]);
13269c1bd4bcSKate Arzamastseva        return false;
13279c1bd4bcSKate Arzamastseva    }
13289c1bd4bcSKate Arzamastseva    return $res;
13299c1bd4bcSKate Arzamastseva}
13309c1bd4bcSKate Arzamastseva
13319c1bd4bcSKate Arzamastseva/**
1332bf1f3ac4Ssarnowski * List all files found by the search request
1333c9f56829SAndreas Gohr *
1334c9f56829SAndreas Gohr * @author Tobias Sarnowski <sarnowski@cosmocode.de>
1335c9f56829SAndreas Gohr * @author Andreas Gohr <gohr@cosmocode.de>
1336d9162c6cSKate Arzamastseva * @author Kate Arzamastseva <pshns@ukr.net>
1337c9f56829SAndreas Gohr * @triggers MEDIA_SEARCH
1338e0c26282SGerrit Uitslag *
1339e0c26282SGerrit Uitslag * @param string $query
1340e0c26282SGerrit Uitslag * @param string $ns
1341e0c26282SGerrit Uitslag * @param null|int $auth
1342e0c26282SGerrit Uitslag * @param bool $fullscreen
1343e0c26282SGerrit Uitslag * @param string $sort
1344bf1f3ac4Ssarnowski */
1345d868eb89SAndreas Gohrfunction media_searchlist($query, $ns, $auth = null, $fullscreen = false, $sort = 'natural')
1346d868eb89SAndreas Gohr{
1347bf1f3ac4Ssarnowski    global $conf;
1348bf1f3ac4Ssarnowski    global $lang;
13498e69fd30SKate Arzamastseva
1350bf1f3ac4Ssarnowski    $ns = cleanID($ns);
135124870174SAndreas Gohr    $evdata = [
135256fe6664SAndreas Gohr        'ns'    => $ns,
135324870174SAndreas Gohr        'data'  => [],
135456fe6664SAndreas Gohr        'query' => $query
135524870174SAndreas Gohr    ];
13567ed31746SSzymon Olewniczak    if (!blank($query)) {
1357e1d9dcc8SAndreas Gohr        $evt = new Event('MEDIA_SEARCH', $evdata);
1358bf1f3ac4Ssarnowski        if ($evt->advise_before()) {
135956fe6664SAndreas Gohr            $dir = utf8_encodeFN(str_replace(':', '/', $evdata['ns']));
136076472096SSzymon Olewniczak            $quoted = preg_quote($evdata['query'], '/');
136176472096SSzymon Olewniczak            //apply globbing
136224870174SAndreas Gohr            $quoted = str_replace(['\*', '\?'], ['.*', '.'], $quoted, $count);
136323e31e76SSzymon Olewniczak
136423e31e76SSzymon Olewniczak            //if we use globbing file name must match entirely but may be preceded by arbitrary namespace
136523e31e76SSzymon Olewniczak            if ($count > 0) $quoted = '^([^:]*:)*' . $quoted . '$';
136623e31e76SSzymon Olewniczak
136776472096SSzymon Olewniczak            $pattern = '/' . $quoted . '/i';
1368dccd6b2bSAndreas Gohr            search(
1369dccd6b2bSAndreas Gohr                $evdata['data'],
137056fe6664SAndreas Gohr                $conf['mediadir'],
13714f33babfSAndreas Gohr                'search_mediafiles',
137224870174SAndreas Gohr                ['showmsg' => false, 'pattern' => $pattern],
137300e3e394SChristopher Smith                $dir,
137400e3e394SChristopher Smith                1,
1375dccd6b2bSAndreas Gohr                $sort
1376dccd6b2bSAndreas Gohr            );
1377bf1f3ac4Ssarnowski        }
1378bf1f3ac4Ssarnowski        $evt->advise_after();
1379bf1f3ac4Ssarnowski        unset($evt);
138056fe6664SAndreas Gohr    }
1381bf1f3ac4Ssarnowski
1382d9162c6cSKate Arzamastseva    if (!$fullscreen) {
138356fe6664SAndreas Gohr        echo '<h1 id="media__ns">' . sprintf($lang['searchmedia_in'], hsc($ns) . ':*') . '</h1>' . NL;
138456fe6664SAndreas Gohr        media_searchform($ns, $query);
1385d9162c6cSKate Arzamastseva    }
138656fe6664SAndreas Gohr
138756fe6664SAndreas Gohr    if (!count($evdata['data'])) {
1388bf1f3ac4Ssarnowski        echo '<div class="nothing">' . $lang['nothingfound'] . '</div>' . NL;
13895b9353faSKate Arzamastseva    } else {
13905b9353faSKate Arzamastseva        if ($fullscreen) {
1391554a8c9fSAdrian Lang            echo '<ul class="' . _media_get_list_type() . '">';
13925b9353faSKate Arzamastseva        }
13935b9353faSKate Arzamastseva        foreach ($evdata['data'] as $item) {
13944f33babfSAndreas Gohr            if (!$fullscreen) {
13954f33babfSAndreas Gohr                // FIXME old call: media_printfile($item,$item['perm'],'',true);
139679a2d784SGerrit Uitslag                $display = new DisplayRow($item);
139779b00823SAndreas Gohr                $display->relativeDisplay($ns);
13984f33babfSAndreas Gohr                $display->show();
13994f33babfSAndreas Gohr            } else {
14004f33babfSAndreas Gohr                // FIXME old call: media_printfile_thumbs($item,$item['perm'],false,true);
140179a2d784SGerrit Uitslag                $display = new DisplayTile($item);
140279b00823SAndreas Gohr                $display->relativeDisplay($ns);
14034f33babfSAndreas Gohr                echo '<li>';
14044f33babfSAndreas Gohr                $display->show();
14054f33babfSAndreas Gohr                echo '</li>';
14064f33babfSAndreas Gohr            }
1407bf1f3ac4Ssarnowski        }
140894add303SAnika Henke        if ($fullscreen) echo '</ul>' . NL;
14095b9353faSKate Arzamastseva    }
1410bf1f3ac4Ssarnowski}
1411bf1f3ac4Ssarnowski
1412bf1f3ac4Ssarnowski/**
1413c6571d58SAndreas Gohr * Display a media icon
1414c6571d58SAndreas Gohr *
141542ea7f44SGerrit Uitslag * @param string $filename media id
1416c6571d58SAndreas Gohr * @param string $size     the size subfolder, if not specified 16x16 is used
141742ea7f44SGerrit Uitslag * @return string html
1418c6571d58SAndreas Gohr */
1419d868eb89SAndreas Gohrfunction media_printicon($filename, $size = '')
1420d868eb89SAndreas Gohr{
142124870174SAndreas Gohr    [$ext] = mimetype(mediaFN($filename), false);
142223786fd7SKate Arzamastseva
142379e79377SAndreas Gohr    if (file_exists(DOKU_INC . 'lib/images/fileicons/' . $size . '/' . $ext . '.png')) {
1424c6571d58SAndreas Gohr        $icon = DOKU_BASE . 'lib/images/fileicons/' . $size . '/' . $ext . '.png';
142523786fd7SKate Arzamastseva    } else {
1426c6571d58SAndreas Gohr        $icon = DOKU_BASE . 'lib/images/fileicons/' . $size . '/file.png';
142723786fd7SKate Arzamastseva    }
142823786fd7SKate Arzamastseva
1429421ec38eSKate Arzamastseva    return '<img src="' . $icon . '" alt="' . $filename . '" class="icon" />';
143023786fd7SKate Arzamastseva}
143123786fd7SKate Arzamastseva
14323df72098SAndreas Gohr/**
143342ea7f44SGerrit Uitslag * Build link based on the current, adding/rewriting parameters
1434d9162c6cSKate Arzamastseva *
1435d9162c6cSKate Arzamastseva * @author Kate Arzamastseva <pshns@ukr.net>
143642ea7f44SGerrit Uitslag *
1437ebc28e69SAndreas Gohr * @param array|bool $params
143842ea7f44SGerrit Uitslag * @param string     $amp           separator
143942ea7f44SGerrit Uitslag * @param bool       $abs           absolute url?
144042ea7f44SGerrit Uitslag * @param bool       $params_array  return the parmeters array?
144142ea7f44SGerrit Uitslag * @return string|array - link or link parameters
1442d9162c6cSKate Arzamastseva */
1443d868eb89SAndreas Gohrfunction media_managerURL($params = false, $amp = '&amp;', $abs = false, $params_array = false)
1444d868eb89SAndreas Gohr{
1445d9162c6cSKate Arzamastseva    global $ID;
14468108113cSTom N Harris    global $INPUT;
1447d9162c6cSKate Arzamastseva
144824870174SAndreas Gohr    $gets = ['do' => 'media'];
144924870174SAndreas Gohr    $media_manager_params = ['tab_files', 'tab_details', 'image', 'ns', 'list', 'sort'];
145023846a98SKate Arzamastseva    foreach ($media_manager_params as $x) {
14518108113cSTom N Harris        if ($INPUT->has($x)) $gets[$x] = $INPUT->str($x);
145223846a98SKate Arzamastseva    }
1453d9162c6cSKate Arzamastseva
1454d9162c6cSKate Arzamastseva    if ($params) {
1455554a8c9fSAdrian Lang        $gets = $params + $gets;
1456d9162c6cSKate Arzamastseva    }
1457d9162c6cSKate Arzamastseva    unset($gets['id']);
1458554a8c9fSAdrian Lang    if (isset($gets['delete'])) {
14591eeeced2SKate Arzamastseva        unset($gets['image']);
14601eeeced2SKate Arzamastseva        unset($gets['tab_details']);
14611eeeced2SKate Arzamastseva    }
1462d9162c6cSKate Arzamastseva
1463035e07f1SKate Arzamastseva    if ($params_array) return $gets;
1464035e07f1SKate Arzamastseva
14656dd095f5SKate Arzamastseva    return wl($ID, $gets, $abs, $amp);
1466d9162c6cSKate Arzamastseva}
1467d9162c6cSKate Arzamastseva
1468d9162c6cSKate Arzamastseva/**
14693df72098SAndreas Gohr * Print the media upload form if permissions are correct
14703df72098SAndreas Gohr *
14713df72098SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org>
1472d9162c6cSKate Arzamastseva * @author Kate Arzamastseva <pshns@ukr.net>
1473e0c26282SGerrit Uitslag *
1474e0c26282SGerrit Uitslag * @param string $ns
1475e0c26282SGerrit Uitslag * @param int    $auth permission level
1476e0c26282SGerrit Uitslag * @param bool  $fullscreen
14773df72098SAndreas Gohr */
1478d868eb89SAndreas Gohrfunction media_uploadform($ns, $auth, $fullscreen = false)
1479d868eb89SAndreas Gohr{
14808108113cSTom N Harris    global $lang;
14818108113cSTom N Harris    global $conf;
14828108113cSTom N Harris    global $INPUT;
14833df72098SAndreas Gohr
148488a71175SKate Arzamastseva    if ($auth < AUTH_UPLOAD) {
148588a71175SKate Arzamastseva        echo '<div class="nothing">' . $lang['media_perm_upload'] . '</div>' . NL;
148688a71175SKate Arzamastseva        return;
148788a71175SKate Arzamastseva    }
148892cac9a9SKate Arzamastseva    $auth_ow = (($conf['mediarevisions']) ? AUTH_UPLOAD : AUTH_DELETE);
14893df72098SAndreas Gohr
149070c3cc9aSKate Arzamastseva    $update = false;
149170c3cc9aSKate Arzamastseva    $id = '';
14928108113cSTom N Harris    if ($auth >= $auth_ow && $fullscreen && $INPUT->str('mediado') == 'update') {
149370c3cc9aSKate Arzamastseva        $update = true;
14948108113cSTom N Harris        $id = cleanID($INPUT->str('image'));
149570c3cc9aSKate Arzamastseva    }
149670c3cc9aSKate Arzamastseva
1497d00ec455SAndreas Gohr    // The default HTML upload form
1498b960c74fSSatoshi Sahara    $form = new Form([
1499b960c74fSSatoshi Sahara        'id' => 'dw__upload',
1500b960c74fSSatoshi Sahara        'enctype' => 'multipart/form-data',
1501b960c74fSSatoshi Sahara        'action' => ($fullscreen)
1502b960c74fSSatoshi Sahara                    ? media_managerURL(['tab_files' => 'files', 'tab_details' => 'view'], '&')
1503b960c74fSSatoshi Sahara                    : DOKU_BASE . 'lib/exe/mediamanager.php',
1504b960c74fSSatoshi Sahara    ]);
1505b960c74fSSatoshi Sahara    $form->addTagOpen('div')->addClass('no');
1506b960c74fSSatoshi Sahara    $form->setHiddenField('ns', hsc($ns));  // FIXME hsc required?
1507b960c74fSSatoshi Sahara    $form->addTagOpen('p');
1508b960c74fSSatoshi Sahara    $form->addTextInput('upload', $lang['txt_upload'])->id('upload__file')
1509b960c74fSSatoshi Sahara            ->attrs(['type' => 'file']);
1510b960c74fSSatoshi Sahara    $form->addTagClose('p');
1511b960c74fSSatoshi Sahara    $form->addTagOpen('p');
1512b960c74fSSatoshi Sahara    $form->addTextInput('mediaid', $lang['txt_filename'])->id('upload__name')
1513b960c74fSSatoshi Sahara            ->val(noNS($id));
1514b960c74fSSatoshi Sahara    $form->addButton('', $lang['btn_upload'])->attr('type', 'submit');
1515b960c74fSSatoshi Sahara    $form->addTagClose('p');
151692cac9a9SKate Arzamastseva    if ($auth >= $auth_ow) {
1517b960c74fSSatoshi Sahara        $form->addTagOpen('p');
151824870174SAndreas Gohr        $attrs = [];
151970c3cc9aSKate Arzamastseva        if ($update) $attrs['checked'] = 'checked';
1520b960c74fSSatoshi Sahara        $form->addCheckbox('ow', $lang['txt_overwrt'])->id('dw__ow')->val('1')
1521b960c74fSSatoshi Sahara            ->addClass('check')->attrs($attrs);
1522b960c74fSSatoshi Sahara        $form->addTagClose('p');
1523b960c74fSSatoshi Sahara    }
1524b960c74fSSatoshi Sahara    $form->addTagClose('div');
1525b960c74fSSatoshi Sahara
1526b960c74fSSatoshi Sahara    if (!$fullscreen) {
1527b960c74fSSatoshi Sahara        echo '<div class="upload">' . $lang['mediaupload'] . '</div>' . DOKU_LF;
1528b960c74fSSatoshi Sahara    } else {
1529b960c74fSSatoshi Sahara        echo DOKU_LF;
15303df72098SAndreas Gohr    }
1531c472bad9SKate Arzamastseva
1532b960c74fSSatoshi Sahara    echo '<div id="mediamanager__uploader">' . DOKU_LF;
1533c6977b3aSSatoshi Sahara    echo $form->toHTML('Upload');
1534b960c74fSSatoshi Sahara    echo '</div>' . DOKU_LF;
1535f940e4a0SAndreas Gohr
1536f940e4a0SAndreas Gohr    echo '<p class="maxsize">';
1537f940e4a0SAndreas Gohr    printf($lang['maxuploadsize'], filesize_h(media_getuploadsize()));
153856fc6b15SAnna Dabrowska    echo ' <a class="allowedmime" href="#">' . $lang['allowedmime'] . '</a>';
1539499d9bcdSAndreas Gohr    echo ' <span>' . implode(', ', array_keys(getMimeTypes())) . '</span>';
1540b960c74fSSatoshi Sahara    echo '</p>' . DOKU_LF;
1541f940e4a0SAndreas Gohr}
1542f940e4a0SAndreas Gohr
1543f940e4a0SAndreas Gohr/**
1544f940e4a0SAndreas Gohr * Returns the size uploaded files may have
1545f940e4a0SAndreas Gohr *
1546f940e4a0SAndreas Gohr * This uses a conservative approach using the lowest number found
1547f940e4a0SAndreas Gohr * in any of the limiting ini settings
1548f940e4a0SAndreas Gohr *
1549f940e4a0SAndreas Gohr * @returns int size in bytes
1550f940e4a0SAndreas Gohr */
1551d868eb89SAndreas Gohrfunction media_getuploadsize()
1552d868eb89SAndreas Gohr{
1553f940e4a0SAndreas Gohr    $okay = 0;
1554f940e4a0SAndreas Gohr
155524870174SAndreas Gohr    $post = php_to_byte(@ini_get('post_max_size'));
155624870174SAndreas Gohr    $suho = php_to_byte(@ini_get('suhosin.post.max_value_length'));
155724870174SAndreas Gohr    $upld = php_to_byte(@ini_get('upload_max_filesize'));
1558f940e4a0SAndreas Gohr
155924870174SAndreas Gohr    if ($post && ($post < $okay || $okay === 0)) $okay = $post;
1560f940e4a0SAndreas Gohr    if ($suho && ($suho < $okay || $okay == 0)) $okay = $suho;
1561f940e4a0SAndreas Gohr    if ($upld && ($upld < $okay || $okay == 0)) $okay = $upld;
1562f940e4a0SAndreas Gohr
1563f940e4a0SAndreas Gohr    return $okay;
15649f5dde7fSMichael Klier}
15653df72098SAndreas Gohr
15663df72098SAndreas Gohr/**
1567bf1f3ac4Ssarnowski * Print the search field form
1568bf1f3ac4Ssarnowski *
1569bf1f3ac4Ssarnowski * @author Tobias Sarnowski <sarnowski@cosmocode.de>
1570d9162c6cSKate Arzamastseva * @author Kate Arzamastseva <pshns@ukr.net>
1571e0c26282SGerrit Uitslag *
1572e0c26282SGerrit Uitslag * @param string $ns
1573e0c26282SGerrit Uitslag * @param string $query
1574e0c26282SGerrit Uitslag * @param bool $fullscreen
1575bf1f3ac4Ssarnowski */
1576d868eb89SAndreas Gohrfunction media_searchform($ns, $query = '', $fullscreen = false)
1577d868eb89SAndreas Gohr{
1578bf1f3ac4Ssarnowski    global $lang;
1579bf1f3ac4Ssarnowski
1580bf1f3ac4Ssarnowski    // The default HTML search form
1581b960c74fSSatoshi Sahara    $form = new Form([
1582b960c74fSSatoshi Sahara        'id'     => 'dw__mediasearch',
1583b960c74fSSatoshi Sahara        'action' => ($fullscreen)
1584b960c74fSSatoshi Sahara                    ? media_managerURL([], '&')
1585b960c74fSSatoshi Sahara                    : DOKU_BASE . 'lib/exe/mediamanager.php',
1586b960c74fSSatoshi Sahara    ]);
1587b960c74fSSatoshi Sahara    $form->addTagOpen('div')->addClass('no');
1588b960c74fSSatoshi Sahara    $form->setHiddenField('ns', $ns);
1589b960c74fSSatoshi Sahara    $form->setHiddenField($fullscreen ? 'mediado' : 'do', 'searchlist');
1590554a8c9fSAdrian Lang
1591b960c74fSSatoshi Sahara    $form->addTagOpen('p');
1592bde2a644SSatoshi Sahara    $form->addTextInput('q', $lang['searchmedia'])
1593b960c74fSSatoshi Sahara            ->attr('title', sprintf($lang['searchmedia_in'], hsc($ns) . ':*'))
1594b960c74fSSatoshi Sahara            ->val($query);
1595bde2a644SSatoshi Sahara    $form->addHTML(' ');
1596b960c74fSSatoshi Sahara    $form->addButton('', $lang['btn_search'])->attr('type', 'submit');
1597b960c74fSSatoshi Sahara    $form->addTagClose('p');
1598b960c74fSSatoshi Sahara    $form->addTagClose('div');
159926dfc232SAndreas Gohr    echo $form->toHTML('SearchMedia');
1600bf1f3ac4Ssarnowski}
1601bf1f3ac4Ssarnowski
1602bf1f3ac4Ssarnowski/**
16033df72098SAndreas Gohr * Build a tree outline of available media namespaces
16043df72098SAndreas Gohr *
16053df72098SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org>
1606e0c26282SGerrit Uitslag *
1607e0c26282SGerrit Uitslag * @param string $ns
16083df72098SAndreas Gohr */
1609d868eb89SAndreas Gohrfunction media_nstree($ns)
1610d868eb89SAndreas Gohr{
16113df72098SAndreas Gohr    global $conf;
1612256ca81eSAndreas Gohr    global $lang;
16133df72098SAndreas Gohr
16143df72098SAndreas Gohr    // currently selected namespace
16153df72098SAndreas Gohr    $ns = cleanID($ns);
16163df72098SAndreas Gohr    if (empty($ns)) {
1617de3eb1d7SAdrian Lang        global $ID;
1618dd90013aSMichael Hamann        $ns = (string)getNS($ID);
16193df72098SAndreas Gohr    }
1620dd90013aSMichael Hamann
1621dd90013aSMichael Hamann    $ns_dir = utf8_encodeFN(str_replace(':', '/', $ns));
16223df72098SAndreas Gohr
162324870174SAndreas Gohr    $data = [];
162424870174SAndreas Gohr    search($data, $conf['mediadir'], 'search_index', ['ns' => $ns_dir, 'nofiles' => true]);
16253df72098SAndreas Gohr
16263df72098SAndreas Gohr    // wrap a list with the root level around the other namespaces
162724870174SAndreas Gohr    array_unshift($data, ['level' => 0, 'id' => '', 'open' => 'true', 'label' => '[' . $lang['mediaroot'] . ']']);
16283df72098SAndreas Gohr
1629dd90013aSMichael Hamann    // insert the current ns into the hierarchy if it isn't already part of it
1630dd90013aSMichael Hamann    $ns_parts = explode(':', $ns);
1631dd90013aSMichael Hamann    $tmp_ns = '';
1632dd90013aSMichael Hamann    $pos = 0;
1633de301a35SDamien Regad    $insert = false;
1634dd90013aSMichael Hamann    foreach ($ns_parts as $level => $part) {
1635186263b2SDamien Regad        if ($tmp_ns) {
1636186263b2SDamien Regad            $tmp_ns .= ':' . $part;
1637186263b2SDamien Regad        } else {
1638186263b2SDamien Regad            $tmp_ns = $part;
1639186263b2SDamien Regad        }
1640dd90013aSMichael Hamann
1641de301a35SDamien Regad        // find the namespace parts
16429988e853SDamien Regad        while (array_key_exists($pos, $data) && $data[$pos]['id'] != $tmp_ns) {
164364159a61SAndreas Gohr            if (
164464159a61SAndreas Gohr                $pos >= count($data) ||
16452d85e841SAndreas Gohr                ($data[$pos]['level'] <= $level + 1 && Sort::strcmp($data[$pos]['id'], $tmp_ns) > 0)
164664159a61SAndreas Gohr            ) {
1647de301a35SDamien Regad                $insert = true;
1648dd90013aSMichael Hamann                break;
1649dd90013aSMichael Hamann            }
1650dd90013aSMichael Hamann            ++$pos;
1651dd90013aSMichael Hamann        }
1652de301a35SDamien Regad        // insert namespace in hierarchy; if not found in above loop, append it to the end
1653b3894732Ssplitbrain        if ($insert || $pos === count($data)) {
1654de301a35SDamien Regad            array_splice($data, $pos, 0, [['level' => $level + 1, 'id' => $tmp_ns, 'open' => 'true']]);
1655de301a35SDamien Regad        }
1656dd90013aSMichael Hamann    }
1657dd90013aSMichael Hamann
16583df72098SAndreas Gohr    echo html_buildlist($data, 'idx', 'media_nstree_item', 'media_nstree_li');
16593df72098SAndreas Gohr}
16603df72098SAndreas Gohr
16613df72098SAndreas Gohr/**
16623df72098SAndreas Gohr * Userfunction for html_buildlist
16633df72098SAndreas Gohr *
16643df72098SAndreas Gohr * Prints a media namespace tree item
16653df72098SAndreas Gohr *
16663df72098SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org>
166742ea7f44SGerrit Uitslag *
166842ea7f44SGerrit Uitslag * @param array $item
166942ea7f44SGerrit Uitslag * @return string html
16703df72098SAndreas Gohr */
1671d868eb89SAndreas Gohrfunction media_nstree_item($item)
1672d868eb89SAndreas Gohr{
16738108113cSTom N Harris    global $INPUT;
16743df72098SAndreas Gohr    $pos   = strrpos($item['id'], ':');
16753df72098SAndreas Gohr    $label = substr($item['id'], $pos > 0 ? $pos + 1 : 0);
16760e80bb5eSChristopher Smith    if (empty($item['label'])) $item['label'] = $label;
16773df72098SAndreas Gohr
16783df72098SAndreas Gohr    $ret  = '';
167924870174SAndreas Gohr    if ($INPUT->str('do') != 'media')
16803df72098SAndreas Gohr    $ret .= '<a href="' . DOKU_BASE . 'lib/exe/mediamanager.php?ns=' . idfilter($item['id']) . '" class="idx_dir">';
1681b960c74fSSatoshi Sahara    else $ret .= '<a href="' . media_managerURL(['ns' => idfilter($item['id'], false), 'tab_files' => 'files'])
168223846a98SKate Arzamastseva        . '" class="idx_dir">';
16833df72098SAndreas Gohr    $ret .= $item['label'];
16843df72098SAndreas Gohr    $ret .= '</a>';
16853df72098SAndreas Gohr    return $ret;
16863df72098SAndreas Gohr}
16873df72098SAndreas Gohr
16883df72098SAndreas Gohr/**
16893df72098SAndreas Gohr * Userfunction for html_buildlist
16903df72098SAndreas Gohr *
16913df72098SAndreas Gohr * Prints a media namespace tree item opener
16923df72098SAndreas Gohr *
16933df72098SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org>
169442ea7f44SGerrit Uitslag *
169542ea7f44SGerrit Uitslag * @param array $item
169642ea7f44SGerrit Uitslag * @return string html
16973df72098SAndreas Gohr */
1698d868eb89SAndreas Gohrfunction media_nstree_li($item)
1699d868eb89SAndreas Gohr{
17003df72098SAndreas Gohr    $class = 'media level' . $item['level'];
17013df72098SAndreas Gohr    if ($item['open']) {
17023df72098SAndreas Gohr        $class .= ' open';
17033df72098SAndreas Gohr        $img   = DOKU_BASE . 'lib/images/minus.gif';
1704e260f93bSAnika Henke        $alt   = '−';
17053df72098SAndreas Gohr    } else {
17063df72098SAndreas Gohr        $class .= ' closed';
17073df72098SAndreas Gohr        $img   = DOKU_BASE . 'lib/images/plus.gif';
17087af1b404SAnika Henke        $alt   = '+';
17093df72098SAndreas Gohr    }
1710231b8c34SPierre Spring    // TODO: only deliver an image if it actually has a subtree...
17113df72098SAndreas Gohr    return '<li class="' . $class . '">' .
17127af1b404SAnika Henke        '<img src="' . $img . '" alt="' . $alt . '" />';
17133df72098SAndreas Gohr}
171413c08e2fSMichael Klier
171513c08e2fSMichael Klier/**
1716b021f0b4SAndreas Gohr * Resizes or crop the given image to the given size
1717b021f0b4SAndreas Gohr *
1718b021f0b4SAndreas Gohr * @author  Andreas Gohr <andi@splitbrain.org>
1719b021f0b4SAndreas Gohr *
1720b021f0b4SAndreas Gohr * @param string $file filename, path to file
1721b021f0b4SAndreas Gohr * @param string $ext  extension
1722b021f0b4SAndreas Gohr * @param int    $w    desired width
1723b021f0b4SAndreas Gohr * @param int    $h    desired height
1724b021f0b4SAndreas Gohr * @param bool   $crop should a center crop be used?
1725b021f0b4SAndreas Gohr * @return string path to resized or original size if failed
1726b021f0b4SAndreas Gohr */
1727b021f0b4SAndreas Gohrfunction media_mod_image($file, $ext, $w, $h = 0, $crop = false)
1728b021f0b4SAndreas Gohr{
1729b021f0b4SAndreas Gohr    global $conf;
1730d967ecd8SAndreas Gohr    if (!$h) $h = 0;
1731b021f0b4SAndreas Gohr    // we wont scale up to infinity
1732b021f0b4SAndreas Gohr    if ($w > 2000 || $h > 2000) return $file;
1733b021f0b4SAndreas Gohr
1734b021f0b4SAndreas Gohr    $operation = $crop ? 'crop' : 'resize';
1735b021f0b4SAndreas Gohr
1736b021f0b4SAndreas Gohr    $options = [
1737b021f0b4SAndreas Gohr        'quality' => $conf['jpg_quality'],
1738b021f0b4SAndreas Gohr        'imconvert' => $conf['im_convert'],
1739b021f0b4SAndreas Gohr    ];
1740b021f0b4SAndreas Gohr
174124870174SAndreas Gohr    $cache = new CacheImageMod($file, $w, $h, $ext, $crop);
1742b021f0b4SAndreas Gohr    if (!$cache->useCache()) {
1743b021f0b4SAndreas Gohr        try {
1744b021f0b4SAndreas Gohr            Slika::run($file, $options)
1745b021f0b4SAndreas Gohr                 ->autorotate()
1746b021f0b4SAndreas Gohr                 ->$operation($w, $h)
1747b021f0b4SAndreas Gohr                 ->save($cache->cache, $ext);
1748b021f0b4SAndreas Gohr            if ($conf['fperm']) @chmod($cache->cache, $conf['fperm']);
174924870174SAndreas Gohr        } catch (Exception $e) {
1750b021f0b4SAndreas Gohr            Logger::debug($e->getMessage());
1751b021f0b4SAndreas Gohr            return $file;
1752b021f0b4SAndreas Gohr        }
1753b021f0b4SAndreas Gohr    }
1754b021f0b4SAndreas Gohr
1755b021f0b4SAndreas Gohr    return $cache->cache;
1756b021f0b4SAndreas Gohr}
1757b021f0b4SAndreas Gohr
1758b021f0b4SAndreas Gohr/**
175913c08e2fSMichael Klier * Resizes the given image to the given size
176013c08e2fSMichael Klier *
176113c08e2fSMichael Klier * @author  Andreas Gohr <andi@splitbrain.org>
176242ea7f44SGerrit Uitslag *
176342ea7f44SGerrit Uitslag * @param string $file filename, path to file
176442ea7f44SGerrit Uitslag * @param string $ext  extension
176542ea7f44SGerrit Uitslag * @param int    $w    desired width
176642ea7f44SGerrit Uitslag * @param int    $h    desired height
176742ea7f44SGerrit Uitslag * @return string path to resized or original size if failed
176813c08e2fSMichael Klier */
1769b021f0b4SAndreas Gohrfunction media_resize_image($file, $ext, $w, $h = 0)
1770b021f0b4SAndreas Gohr{
1771b021f0b4SAndreas Gohr    return media_mod_image($file, $ext, $w, $h, false);
1772d2bd34a5SAndreas Gohr}
177313c08e2fSMichael Klier
177413c08e2fSMichael Klier/**
1775d2bd34a5SAndreas Gohr * Center crops the given image to the wanted size
177613c08e2fSMichael Klier *
177713c08e2fSMichael Klier * @author  Andreas Gohr <andi@splitbrain.org>
177842ea7f44SGerrit Uitslag *
177942ea7f44SGerrit Uitslag * @param string $file filename, path to file
178042ea7f44SGerrit Uitslag * @param string $ext  extension
178142ea7f44SGerrit Uitslag * @param int    $w    desired width
178242ea7f44SGerrit Uitslag * @param int    $h    desired height
178342ea7f44SGerrit Uitslag * @return string path to resized or original size if failed
178413c08e2fSMichael Klier */
1785b021f0b4SAndreas Gohrfunction media_crop_image($file, $ext, $w, $h = 0)
1786b021f0b4SAndreas Gohr{
1787b021f0b4SAndreas Gohr    return media_mod_image($file, $ext, $w, $h, true);
178813c08e2fSMichael Klier}
178913c08e2fSMichael Klier
179013c08e2fSMichael Klier/**
17910f4e0092SChristopher Smith * Calculate a token to be used to verify fetch requests for resized or
17920f4e0092SChristopher Smith * cropped images have been internally generated - and prevent external
17930f4e0092SChristopher Smith * DDOS attacks via fetch
17940f4e0092SChristopher Smith *
17953c124064SAndreas Gohr * @author Christopher Smith <chris@jalakai.co.uk>
17963c124064SAndreas Gohr *
17970f4e0092SChristopher Smith * @param string  $id    id of the image
17980f4e0092SChristopher Smith * @param int     $w     resize/crop width
17990f4e0092SChristopher Smith * @param int     $h     resize/crop height
180042ea7f44SGerrit Uitslag * @return string token or empty string if no token required
18010f4e0092SChristopher Smith */
1802d868eb89SAndreas Gohrfunction media_get_token($id, $w, $h)
1803d868eb89SAndreas Gohr{
18040f4e0092SChristopher Smith    // token is only required for modified images
1805cc036f74SKlap-in    if ($w || $h || media_isexternal($id)) {
18063c124064SAndreas Gohr        $token = $id;
18070f4e0092SChristopher Smith        if ($w) $token .= '.' . $w;
18080f4e0092SChristopher Smith        if ($h) $token .= '.' . $h;
18090f4e0092SChristopher Smith
181024870174SAndreas Gohr        return substr(PassHash::hmac('md5', $token, auth_cookiesalt()), 0, 6);
18110f4e0092SChristopher Smith    }
18120f4e0092SChristopher Smith
18130f4e0092SChristopher Smith    return '';
18140f4e0092SChristopher Smith}
18150f4e0092SChristopher Smith
18160f4e0092SChristopher Smith/**
181713c08e2fSMichael Klier * Download a remote file and return local filename
181813c08e2fSMichael Klier *
181913c08e2fSMichael Klier * returns false if download fails. Uses cached file if available and
182013c08e2fSMichael Klier * wanted
182113c08e2fSMichael Klier *
182213c08e2fSMichael Klier * @author  Andreas Gohr <andi@splitbrain.org>
182313c08e2fSMichael Klier * @author  Pavel Vitis <Pavel.Vitis@seznam.cz>
182442ea7f44SGerrit Uitslag *
182542ea7f44SGerrit Uitslag * @param string $url
182642ea7f44SGerrit Uitslag * @param string $ext   extension
182742ea7f44SGerrit Uitslag * @param int    $cache cachetime in seconds
182842ea7f44SGerrit Uitslag * @return false|string path to cached file
182913c08e2fSMichael Klier */
1830d868eb89SAndreas Gohrfunction media_get_from_URL($url, $ext, $cache)
1831d868eb89SAndreas Gohr{
183213c08e2fSMichael Klier    global $conf;
183313c08e2fSMichael Klier
183413c08e2fSMichael Klier    // if no cache or fetchsize just redirect
183513c08e2fSMichael Klier    if ($cache == 0)           return false;
183613c08e2fSMichael Klier    if (!$conf['fetchsize']) return false;
183713c08e2fSMichael Klier
183813c08e2fSMichael Klier    $local = getCacheName(strtolower($url), ".media.$ext");
183913c08e2fSMichael Klier    $mtime = @filemtime($local); // 0 if not exists
184013c08e2fSMichael Klier
184113c08e2fSMichael Klier    //decide if download needed:
18427d34963bSAndreas Gohr    if (
18437d34963bSAndreas Gohr        ($mtime == 0) || // cache does not exist
184413c08e2fSMichael Klier        ($cache != -1 && $mtime < time() - $cache) // 'recache' and cache has expired
184513c08e2fSMichael Klier    ) {
184613c08e2fSMichael Klier        if (media_image_download($url, $local)) {
184713c08e2fSMichael Klier            return $local;
184813c08e2fSMichael Klier        } else {
184913c08e2fSMichael Klier            return false;
185013c08e2fSMichael Klier        }
185113c08e2fSMichael Klier    }
185213c08e2fSMichael Klier
185313c08e2fSMichael Klier    //if cache exists use it else
185413c08e2fSMichael Klier    if ($mtime) return $local;
185513c08e2fSMichael Klier
185613c08e2fSMichael Klier    //else return false
185713c08e2fSMichael Klier    return false;
185813c08e2fSMichael Klier}
185913c08e2fSMichael Klier
186013c08e2fSMichael Klier/**
186113c08e2fSMichael Klier * Download image files
186213c08e2fSMichael Klier *
186313c08e2fSMichael Klier * @author Andreas Gohr <andi@splitbrain.org>
186442ea7f44SGerrit Uitslag *
186542ea7f44SGerrit Uitslag * @param string $url
186642ea7f44SGerrit Uitslag * @param string $file path to file in which to put the downloaded content
186742ea7f44SGerrit Uitslag * @return bool
186813c08e2fSMichael Klier */
1869d868eb89SAndreas Gohrfunction media_image_download($url, $file)
1870d868eb89SAndreas Gohr{
187113c08e2fSMichael Klier    global $conf;
187213c08e2fSMichael Klier    $http = new DokuHTTPClient();
1873a5951419SAndreas Gohr    $http->keep_alive = false; // we do single ops here, no need for keep-alive
1874a5951419SAndreas Gohr
187513c08e2fSMichael Klier    $http->max_bodysize = $conf['fetchsize'];
187613c08e2fSMichael Klier    $http->timeout = 25; //max. 25 sec
187713c08e2fSMichael Klier    $http->header_regexp = '!\r\nContent-Type: image/(jpe?g|gif|png)!i';
187813c08e2fSMichael Klier
187913c08e2fSMichael Klier    $data = $http->get($url);
188013c08e2fSMichael Klier    if (!$data) return false;
188113c08e2fSMichael Klier
188279e79377SAndreas Gohr    $fileexists = file_exists($file);
188313c08e2fSMichael Klier    $fp = @fopen($file, "w");
188413c08e2fSMichael Klier    if (!$fp) return false;
188513c08e2fSMichael Klier    fwrite($fp, $data);
188613c08e2fSMichael Klier    fclose($fp);
188724870174SAndreas Gohr    if (!$fileexists && $conf['fperm']) chmod($file, $conf['fperm']);
188813c08e2fSMichael Klier
188913c08e2fSMichael Klier    // check if it is really an image
189013c08e2fSMichael Klier    $info = @getimagesize($file);
189113c08e2fSMichael Klier    if (!$info) {
189213c08e2fSMichael Klier        @unlink($file);
189313c08e2fSMichael Klier        return false;
189413c08e2fSMichael Klier    }
189513c08e2fSMichael Klier
189613c08e2fSMichael Klier    return true;
189713c08e2fSMichael Klier}
189813c08e2fSMichael Klier
189913c08e2fSMichael Klier/**
190013c08e2fSMichael Klier * resize images using external ImageMagick convert program
190113c08e2fSMichael Klier *
190213c08e2fSMichael Klier * @author Pavel Vitis <Pavel.Vitis@seznam.cz>
190313c08e2fSMichael Klier * @author Andreas Gohr <andi@splitbrain.org>
190442ea7f44SGerrit Uitslag *
190542ea7f44SGerrit Uitslag * @param string $ext     extension
190642ea7f44SGerrit Uitslag * @param string $from    filename path to file
190742ea7f44SGerrit Uitslag * @param int    $from_w  original width
190842ea7f44SGerrit Uitslag * @param int    $from_h  original height
190942ea7f44SGerrit Uitslag * @param string $to      path to resized file
191042ea7f44SGerrit Uitslag * @param int    $to_w    desired width
191142ea7f44SGerrit Uitslag * @param int    $to_h    desired height
191242ea7f44SGerrit Uitslag * @return bool
191313c08e2fSMichael Klier */
1914d868eb89SAndreas Gohrfunction media_resize_imageIM($ext, $from, $from_w, $from_h, $to, $to_w, $to_h)
1915d868eb89SAndreas Gohr{
191613c08e2fSMichael Klier    global $conf;
191713c08e2fSMichael Klier
191813c08e2fSMichael Klier    // check if convert is configured
191913c08e2fSMichael Klier    if (!$conf['im_convert']) return false;
192013c08e2fSMichael Klier
192113c08e2fSMichael Klier    // prepare command
192213c08e2fSMichael Klier    $cmd  = $conf['im_convert'];
192313c08e2fSMichael Klier    $cmd .= ' -resize ' . $to_w . 'x' . $to_h . '!';
192413c08e2fSMichael Klier    if ($ext == 'jpg' || $ext == 'jpeg') {
192513c08e2fSMichael Klier        $cmd .= ' -quality ' . $conf['jpg_quality'];
192613c08e2fSMichael Klier    }
192713c08e2fSMichael Klier    $cmd .= " $from $to";
192813c08e2fSMichael Klier
192913c08e2fSMichael Klier    @exec($cmd, $out, $retval);
193013c08e2fSMichael Klier    if ($retval == 0) return true;
193113c08e2fSMichael Klier    return false;
193213c08e2fSMichael Klier}
193313c08e2fSMichael Klier
193413c08e2fSMichael Klier/**
193513c08e2fSMichael Klier * crop images using external ImageMagick convert program
193613c08e2fSMichael Klier *
193713c08e2fSMichael Klier * @author Andreas Gohr <andi@splitbrain.org>
193842ea7f44SGerrit Uitslag *
193942ea7f44SGerrit Uitslag * @param string $ext     extension
194042ea7f44SGerrit Uitslag * @param string $from    filename path to file
194142ea7f44SGerrit Uitslag * @param int    $from_w  original width
194242ea7f44SGerrit Uitslag * @param int    $from_h  original height
194342ea7f44SGerrit Uitslag * @param string $to      path to resized file
194442ea7f44SGerrit Uitslag * @param int    $to_w    desired width
194542ea7f44SGerrit Uitslag * @param int    $to_h    desired height
194642ea7f44SGerrit Uitslag * @param int    $ofs_x   offset of crop centre
194742ea7f44SGerrit Uitslag * @param int    $ofs_y   offset of crop centre
194842ea7f44SGerrit Uitslag * @return bool
1949d2bd34a5SAndreas Gohr * @deprecated 2020-09-01
195013c08e2fSMichael Klier */
1951d868eb89SAndreas Gohrfunction media_crop_imageIM($ext, $from, $from_w, $from_h, $to, $to_w, $to_h, $ofs_x, $ofs_y)
1952d868eb89SAndreas Gohr{
195313c08e2fSMichael Klier    global $conf;
1954d2bd34a5SAndreas Gohr    dbg_deprecated('splitbrain\\Slika');
195513c08e2fSMichael Klier
195613c08e2fSMichael Klier    // check if convert is configured
195713c08e2fSMichael Klier    if (!$conf['im_convert']) return false;
195813c08e2fSMichael Klier
195913c08e2fSMichael Klier    // prepare command
196013c08e2fSMichael Klier    $cmd  = $conf['im_convert'];
196113c08e2fSMichael Klier    $cmd .= ' -crop ' . $to_w . 'x' . $to_h . '+' . $ofs_x . '+' . $ofs_y;
196213c08e2fSMichael Klier    if ($ext == 'jpg' || $ext == 'jpeg') {
196313c08e2fSMichael Klier        $cmd .= ' -quality ' . $conf['jpg_quality'];
196413c08e2fSMichael Klier    }
196513c08e2fSMichael Klier    $cmd .= " $from $to";
196613c08e2fSMichael Klier
196713c08e2fSMichael Klier    @exec($cmd, $out, $retval);
196813c08e2fSMichael Klier    if ($retval == 0) return true;
196913c08e2fSMichael Klier    return false;
197013c08e2fSMichael Klier}
197113c08e2fSMichael Klier
197213c08e2fSMichael Klier/**
197313c08e2fSMichael Klier * resize or crop images using PHP's libGD support
197413c08e2fSMichael Klier *
197513c08e2fSMichael Klier * @author Andreas Gohr <andi@splitbrain.org>
197613c08e2fSMichael Klier * @author Sebastian Wienecke <s_wienecke@web.de>
197742ea7f44SGerrit Uitslag *
197842ea7f44SGerrit Uitslag * @param string $ext     extension
197942ea7f44SGerrit Uitslag * @param string $from    filename path to file
198042ea7f44SGerrit Uitslag * @param int    $from_w  original width
198142ea7f44SGerrit Uitslag * @param int    $from_h  original height
198242ea7f44SGerrit Uitslag * @param string $to      path to resized file
198342ea7f44SGerrit Uitslag * @param int    $to_w    desired width
198442ea7f44SGerrit Uitslag * @param int    $to_h    desired height
198542ea7f44SGerrit Uitslag * @param int    $ofs_x   offset of crop centre
198642ea7f44SGerrit Uitslag * @param int    $ofs_y   offset of crop centre
198742ea7f44SGerrit Uitslag * @return bool
1988d2bd34a5SAndreas Gohr * @deprecated 2020-09-01
198913c08e2fSMichael Klier */
1990d868eb89SAndreas Gohrfunction media_resize_imageGD($ext, $from, $from_w, $from_h, $to, $to_w, $to_h, $ofs_x = 0, $ofs_y = 0)
1991d868eb89SAndreas Gohr{
199213c08e2fSMichael Klier    global $conf;
1993d2bd34a5SAndreas Gohr    dbg_deprecated('splitbrain\\Slika');
199413c08e2fSMichael Klier
199513c08e2fSMichael Klier    if ($conf['gdlib'] < 1) return false; //no GDlib available or wanted
199613c08e2fSMichael Klier
199713c08e2fSMichael Klier    // check available memory
199813c08e2fSMichael Klier    if (!is_mem_available(($from_w * $from_h * 4) + ($to_w * $to_h * 4))) {
199913c08e2fSMichael Klier        return false;
200013c08e2fSMichael Klier    }
200113c08e2fSMichael Klier
200213c08e2fSMichael Klier    // create an image of the given filetype
200359bc3b48SGerrit Uitslag    $image = false;
200413c08e2fSMichael Klier    if ($ext == 'jpg' || $ext == 'jpeg') {
200513c08e2fSMichael Klier        if (!function_exists("imagecreatefromjpeg")) return false;
200613c08e2fSMichael Klier        $image = @imagecreatefromjpeg($from);
200713c08e2fSMichael Klier    } elseif ($ext == 'png') {
200813c08e2fSMichael Klier        if (!function_exists("imagecreatefrompng")) return false;
200913c08e2fSMichael Klier        $image = @imagecreatefrompng($from);
201013c08e2fSMichael Klier    } elseif ($ext == 'gif') {
201113c08e2fSMichael Klier        if (!function_exists("imagecreatefromgif")) return false;
201213c08e2fSMichael Klier        $image = @imagecreatefromgif($from);
201313c08e2fSMichael Klier    }
201413c08e2fSMichael Klier    if (!$image) return false;
201513c08e2fSMichael Klier
201659bc3b48SGerrit Uitslag    $newimg = false;
201713c08e2fSMichael Klier    if (($conf['gdlib'] > 1) && function_exists("imagecreatetruecolor") && $ext != 'gif') {
201813c08e2fSMichael Klier        $newimg = @imagecreatetruecolor($to_w, $to_h);
201913c08e2fSMichael Klier    }
202013c08e2fSMichael Klier    if (!$newimg) $newimg = @imagecreate($to_w, $to_h);
202113c08e2fSMichael Klier    if (!$newimg) {
202213c08e2fSMichael Klier        imagedestroy($image);
202313c08e2fSMichael Klier        return false;
202413c08e2fSMichael Klier    }
202513c08e2fSMichael Klier
202613c08e2fSMichael Klier    //keep png alpha channel if possible
202713c08e2fSMichael Klier    if ($ext == 'png' && $conf['gdlib'] > 1 && function_exists('imagesavealpha')) {
202813c08e2fSMichael Klier        imagealphablending($newimg, false);
202913c08e2fSMichael Klier        imagesavealpha($newimg, true);
203013c08e2fSMichael Klier    }
203113c08e2fSMichael Klier
203213c08e2fSMichael Klier    //keep gif transparent color if possible
203313c08e2fSMichael Klier    if ($ext == 'gif' && function_exists('imagefill') && function_exists('imagecolorallocate')) {
203413c08e2fSMichael Klier        if (function_exists('imagecolorsforindex') && function_exists('imagecolortransparent')) {
203513c08e2fSMichael Klier            $transcolorindex = @imagecolortransparent($image);
203613c08e2fSMichael Klier            if ($transcolorindex >= 0) { //transparent color exists
203713c08e2fSMichael Klier                $transcolor = @imagecolorsforindex($image, $transcolorindex);
203864159a61SAndreas Gohr                $transcolorindex = @imagecolorallocate(
203964159a61SAndreas Gohr                    $newimg,
204064159a61SAndreas Gohr                    $transcolor['red'],
204164159a61SAndreas Gohr                    $transcolor['green'],
204264159a61SAndreas Gohr                    $transcolor['blue']
204364159a61SAndreas Gohr                );
204413c08e2fSMichael Klier                @imagefill($newimg, 0, 0, $transcolorindex);
204513c08e2fSMichael Klier                @imagecolortransparent($newimg, $transcolorindex);
204613c08e2fSMichael Klier            } else { //filling with white
204713c08e2fSMichael Klier                $whitecolorindex = @imagecolorallocate($newimg, 255, 255, 255);
204813c08e2fSMichael Klier                @imagefill($newimg, 0, 0, $whitecolorindex);
204913c08e2fSMichael Klier            }
205013c08e2fSMichael Klier        } else { //filling with white
205113c08e2fSMichael Klier            $whitecolorindex = @imagecolorallocate($newimg, 255, 255, 255);
205213c08e2fSMichael Klier            @imagefill($newimg, 0, 0, $whitecolorindex);
205313c08e2fSMichael Klier        }
205413c08e2fSMichael Klier    }
205513c08e2fSMichael Klier
205613c08e2fSMichael Klier    //try resampling first
205713c08e2fSMichael Klier    if (function_exists("imagecopyresampled")) {
205813c08e2fSMichael Klier        if (!@imagecopyresampled($newimg, $image, 0, 0, $ofs_x, $ofs_y, $to_w, $to_h, $from_w, $from_h)) {
205913c08e2fSMichael Klier            imagecopyresized($newimg, $image, 0, 0, $ofs_x, $ofs_y, $to_w, $to_h, $from_w, $from_h);
206013c08e2fSMichael Klier        }
206113c08e2fSMichael Klier    } else {
206213c08e2fSMichael Klier        imagecopyresized($newimg, $image, 0, 0, $ofs_x, $ofs_y, $to_w, $to_h, $from_w, $from_h);
206313c08e2fSMichael Klier    }
206413c08e2fSMichael Klier
206513c08e2fSMichael Klier    $okay = false;
206613c08e2fSMichael Klier    if ($ext == 'jpg' || $ext == 'jpeg') {
206713c08e2fSMichael Klier        if (!function_exists('imagejpeg')) {
206813c08e2fSMichael Klier            $okay = false;
206913c08e2fSMichael Klier        } else {
207013c08e2fSMichael Klier            $okay = imagejpeg($newimg, $to, $conf['jpg_quality']);
207113c08e2fSMichael Klier        }
207213c08e2fSMichael Klier    } elseif ($ext == 'png') {
207313c08e2fSMichael Klier        if (!function_exists('imagepng')) {
207413c08e2fSMichael Klier            $okay = false;
207513c08e2fSMichael Klier        } else {
207613c08e2fSMichael Klier            $okay =  imagepng($newimg, $to);
207713c08e2fSMichael Klier        }
207813c08e2fSMichael Klier    } elseif ($ext == 'gif') {
207913c08e2fSMichael Klier        if (!function_exists('imagegif')) {
208013c08e2fSMichael Klier            $okay = false;
208113c08e2fSMichael Klier        } else {
208213c08e2fSMichael Klier            $okay = imagegif($newimg, $to);
208313c08e2fSMichael Klier        }
208413c08e2fSMichael Klier    }
208513c08e2fSMichael Klier
208679a2d784SGerrit Uitslag    // destroy GD image resources
208779a2d784SGerrit Uitslag    imagedestroy($image);
208879a2d784SGerrit Uitslag    imagedestroy($newimg);
208913c08e2fSMichael Klier
209013c08e2fSMichael Klier    return $okay;
209113c08e2fSMichael Klier}
209213c08e2fSMichael Klier
20933d7a9e0aSAnika Henke/**
20943d7a9e0aSAnika Henke * Return other media files with the same base name
209579e53fe5SAnika Henke * but different extensions.
20963d7a9e0aSAnika Henke *
20973d7a9e0aSAnika Henke * @param string   $src     - ID of media file
209842ea7f44SGerrit Uitslag * @param string[] $exts    - alternative extensions to find other files for
209942ea7f44SGerrit Uitslag * @return array            - array(mime type => file ID)
21003d7a9e0aSAnika Henke *
21013d7a9e0aSAnika Henke * @author Anika Henke <anika@selfthinker.org>
21023d7a9e0aSAnika Henke */
2103d868eb89SAndreas Gohrfunction media_alternativefiles($src, $exts)
2104d868eb89SAndreas Gohr{
21053d7a9e0aSAnika Henke
210624870174SAndreas Gohr    $files = [];
2107a19c9aa0SGerrit Uitslag    [$srcExt, /* srcMime */] = mimetype($src);
21083d7a9e0aSAnika Henke    $filebase = substr($src, 0, -1 * (strlen($srcExt) + 1));
21093d7a9e0aSAnika Henke
21103d7a9e0aSAnika Henke    foreach ($exts as $ext) {
21113d7a9e0aSAnika Henke        $fileid = $filebase . '.' . $ext;
21123d7a9e0aSAnika Henke        $file = mediaFN($fileid);
21133d7a9e0aSAnika Henke        if (file_exists($file)) {
2114a19c9aa0SGerrit Uitslag            [/* fileExt */, $fileMime] = mimetype($file);
211579e53fe5SAnika Henke            $files[$fileMime] = $fileid;
211699f943f6SAnika Henke        }
21173d7a9e0aSAnika Henke    }
21183d7a9e0aSAnika Henke    return $files;
21193d7a9e0aSAnika Henke}
21203d7a9e0aSAnika Henke
2121f50634f0SAnika Henke/**
2122f50634f0SAnika Henke * Check if video/audio is supported to be embedded.
2123f50634f0SAnika Henke *
2124b83a74f1SAnika Henke * @param string $mime      - mimetype of media file
212542ea7f44SGerrit Uitslag * @param string $type      - type of media files to check ('video', 'audio', or null for all)
2126f50634f0SAnika Henke * @return boolean
2127f50634f0SAnika Henke *
2128f50634f0SAnika Henke * @author Anika Henke <anika@selfthinker.org>
2129f50634f0SAnika Henke */
2130ed823bcdSAndreas Gohrfunction media_supportedav($mime, $type = null)
2131d868eb89SAndreas Gohr{
213224870174SAndreas Gohr    $supportedAudio = [
2133f50634f0SAnika Henke        'ogg' => 'audio/ogg',
2134f50634f0SAnika Henke        'mp3' => 'audio/mpeg',
213524870174SAndreas Gohr        'wav' => 'audio/wav'
213624870174SAndreas Gohr    ];
213724870174SAndreas Gohr    $supportedVideo = [
2138f50634f0SAnika Henke        'webm' => 'video/webm',
2139f50634f0SAnika Henke        'ogv' => 'video/ogg',
214024870174SAndreas Gohr        'mp4' => 'video/mp4'
214124870174SAndreas Gohr    ];
2142f50634f0SAnika Henke    if ($type == 'audio') {
2143f50634f0SAnika Henke        $supportedAv = $supportedAudio;
2144f50634f0SAnika Henke    } elseif ($type == 'video') {
2145f50634f0SAnika Henke        $supportedAv = $supportedVideo;
2146f50634f0SAnika Henke    } else {
2147f50634f0SAnika Henke        $supportedAv = array_merge($supportedAudio, $supportedVideo);
2148f50634f0SAnika Henke    }
2149f50634f0SAnika Henke    return in_array($mime, $supportedAv);
2150f50634f0SAnika Henke}
2151f50634f0SAnika Henke
21520877a1f1SSchplurtz le Déboulonné/**
21530877a1f1SSchplurtz le Déboulonné * Return track media files with the same base name
21540877a1f1SSchplurtz le Déboulonné * but extensions that indicate kind and lang.
21550877a1f1SSchplurtz le Déboulonné * ie for foo.webm search foo.sub.lang.vtt, foo.cap.lang.vtt...
21560877a1f1SSchplurtz le Déboulonné *
21570877a1f1SSchplurtz le Déboulonné * @param string   $src     - ID of media file
215801299338SSchplurtz le Déboulonné * @return array            - array(mediaID => array( kind, srclang ))
21590877a1f1SSchplurtz le Déboulonné *
21600877a1f1SSchplurtz le Déboulonné * @author Schplurtz le Déboulonné <Schplurtz@laposte.net>
21610877a1f1SSchplurtz le Déboulonné */
2162d868eb89SAndreas Gohrfunction media_trackfiles($src)
2163d868eb89SAndreas Gohr{
216424870174SAndreas Gohr    $kinds = [
21650877a1f1SSchplurtz le Déboulonné        'sub' => 'subtitles',
21660877a1f1SSchplurtz le Déboulonné        'cap' => 'captions',
21670877a1f1SSchplurtz le Déboulonné        'des' => 'descriptions',
21680877a1f1SSchplurtz le Déboulonné        'cha' => 'chapters',
21690877a1f1SSchplurtz le Déboulonné        'met' => 'metadata'
217024870174SAndreas Gohr    ];
21710877a1f1SSchplurtz le Déboulonné
217224870174SAndreas Gohr    $files = [];
21730877a1f1SSchplurtz le Déboulonné    $re = '/\\.(sub|cap|des|cha|met)\\.([^.]+)\\.vtt$/';
21740877a1f1SSchplurtz le Déboulonné    $baseid = pathinfo($src, PATHINFO_FILENAME);
21750877a1f1SSchplurtz le Déboulonné    $pattern = mediaFN($baseid) . '.*.*.vtt';
21760877a1f1SSchplurtz le Déboulonné    $list = glob($pattern);
21770877a1f1SSchplurtz le Déboulonné    foreach ($list as $track) {
21780877a1f1SSchplurtz le Déboulonné        if (preg_match($re, $track, $matches)) {
217924870174SAndreas Gohr            $files[$baseid . '.' . $matches[1] . '.' . $matches[2] . '.vtt'] = [$kinds[$matches[1]], $matches[2]];
21800877a1f1SSchplurtz le Déboulonné        }
21810877a1f1SSchplurtz le Déboulonné    }
21820877a1f1SSchplurtz le Déboulonné    return $files;
21830877a1f1SSchplurtz le Déboulonné}
21840877a1f1SSchplurtz le Déboulonné
2185365be586SAndreas Gohr/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
2186