Failed Conditions
Push — mediaitems ( 8f7d0e...4f33ba )
by Andreas
05:42 queued 03:05
created

media.php ➔ media_searchlist()   C

Complexity

Conditions 10
Paths 104

Size

Total Lines 63

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 10
nc 104
nop 5
dl 0
loc 63
rs 6.9139
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * All output and handler function needed for the media management popup
4
 *
5
 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
6
 * @author     Andreas Gohr <[email protected]>
7
 */
8
9
use dokuwiki\ChangeLog\MediaChangeLog;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, MediaChangeLog.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
10
use dokuwiki\HTTP\DokuHTTPClient;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, DokuHTTPClient.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
11
use dokuwiki\Subscriptions\MediaSubscriptionSender;
12
use dokuwiki\Extension\Event;
13
use dokuwiki\Form\Form;
14
use dokuwiki\Utf8\Sort;
15
16
/**
17
 * Lists pages which currently use a media file selected for deletion
18
 *
19
 * References uses the same visual as search results and share
20
 * their CSS tags except pagenames won't be links.
21
 *
22
 * @author Matthias Grimm <[email protected]>
23
 *
24
 * @param array $data
25
 * @param string $id
26
 */
27
function media_filesinuse($data,$id){
28
    global $lang;
29
    echo '<h1>'.$lang['reference'].' <code>'.hsc(noNS($id)).'</code></h1>';
30
    echo '<p>'.hsc($lang['ref_inuse']).'</p>';
31
32
    $hidden=0; //count of hits without read permission
33
    foreach($data as $row){
34
        if(auth_quickaclcheck($row) >= AUTH_READ && isVisiblePage($row)){
35
            echo '<div class="search_result">';
36
            echo '<span class="mediaref_ref">'.hsc($row).'</span>';
37
            echo '</div>';
38
        }else
39
            $hidden++;
40
    }
41
    if ($hidden){
42
        print '<div class="mediaref_hidden">'.$lang['ref_hidden'].'</div>';
43
    }
44
}
45
46
/**
47
 * Handles the saving of image meta data
48
 *
49
 * @author Andreas Gohr <[email protected]>
50
 * @author Kate Arzamastseva <[email protected]>
51
 *
52
 * @param string $id media id
53
 * @param int $auth permission level
54
 * @param array $data
55
 * @return false|string
56
 */
57
function media_metasave($id,$auth,$data){
58
    if($auth < AUTH_UPLOAD) return false;
59
    if(!checkSecurityToken()) return false;
60
    global $lang;
61
    global $conf;
62
    $src = mediaFN($id);
63
64
    $meta = new JpegMeta($src);
65
    $meta->_parseAll();
66
67
    foreach($data as $key => $val){
68
        $val=trim($val);
69
        if(empty($val)){
70
            $meta->deleteField($key);
71
        }else{
72
            $meta->setField($key,$val);
73
        }
74
    }
75
76
    $old = @filemtime($src);
77
    if(!file_exists(mediaFN($id, $old)) && file_exists($src)) {
78
        // add old revision to the attic
79
        media_saveOldRevision($id);
80
    }
81
    $filesize_old = filesize($src);
82
    if($meta->save()){
83
        if($conf['fperm']) chmod($src, $conf['fperm']);
84
        @clearstatcache(true, $src);
85
        $new = @filemtime($src);
86
        $filesize_new = filesize($src);
87
        $sizechange = $filesize_new - $filesize_old;
88
89
        // add a log entry to the media changelog
90
        addMediaLogEntry($new, $id, DOKU_CHANGE_TYPE_EDIT, $lang['media_meta_edited'], '', null, $sizechange);
91
92
        msg($lang['metasaveok'],1);
93
        return $id;
94
    }else{
95
        msg($lang['metasaveerr'],-1);
96
        return false;
97
    }
98
}
99
100
/**
101
 * check if a media is external source
102
 *
103
 * @author Gerrit Uitslag <[email protected]>
104
 *
105
 * @param string $id the media ID or URL
106
 * @return bool
107
 */
108
function media_isexternal($id){
109
    if (preg_match('#^(?:https?|ftp)://#i', $id)) return true;
110
    return false;
111
}
112
113
/**
114
 * Check if a media item is public (eg, external URL or readable by @ALL)
115
 *
116
 * @author Andreas Gohr <[email protected]>
117
 *
118
 * @param string $id  the media ID or URL
119
 * @return bool
120
 */
121
function media_ispublic($id){
122
    if(media_isexternal($id)) return true;
123
    $id = cleanID($id);
124
    if(auth_aclcheck(getNS($id).':*', '', array()) >= AUTH_READ) return true;
125
    return false;
126
}
127
128
/**
129
 * Display the form to edit image meta data
130
 *
131
 * @author Andreas Gohr <[email protected]>
132
 * @author Kate Arzamastseva <[email protected]>
133
 *
134
 * @param string $id media id
135
 * @param int $auth permission level
136
 * @return bool
137
 */
138
function media_metaform($id, $auth) {
139
    global $lang;
140
141
    if ($auth < AUTH_UPLOAD) {
142
        echo '<div class="nothing">'.$lang['media_perm_upload'].'</div>'.DOKU_LF;
143
        return false;
144
    }
145
146
    // load the field descriptions
147
    static $fields = null;
148
    if ($fields === null) {
149
        $config_files = getConfigFiles('mediameta');
150
        foreach ($config_files as $config_file) {
151
            if (file_exists($config_file)) include($config_file);
152
        }
153
    }
154
155
    $src = mediaFN($id);
156
157
    // output
158
    $form = new Form([
159
            'action' => media_managerURL(['tab_details' => 'view'], '&'),
160
            'class' => 'meta'
161
    ]);
162
    $form->addTagOpen('div')->addClass('no');
163
    $form->setHiddenField('img', $id);
164
    $form->setHiddenField('mediado', 'save');
165
    foreach ($fields as $key => $field) {
0 ignored issues
show
Bug introduced by
The expression $fields of type null is not traversable.
Loading history...
166
        // get current value
167
        if (empty($field[0])) continue;
168
        $tags = array($field[0]);
169
        if (is_array($field[3])) $tags = array_merge($tags, $field[3]);
170
        $value = tpl_img_getTag($tags, '', $src);
171
        $value = cleanText($value);
172
173
        // prepare attributes
174
        $p = array(
175
            'class' => 'edit',
176
            'id'    => 'meta__'.$key,
177
            'name'  => 'meta['.$field[0].']',
178
        );
179
180
        $form->addTagOpen('div')->addClass('row');
181
        if ($field[2] == 'text') {
182
            $form->addTextInput(
183
                $p['name'],
184
                ($lang[$field[1]] ? $lang[$field[1]] : $field[1] . ':')
185
            )->id($p['id'])->addClass($p['class'])->val($value);
186
        } else {
187
            $form->addTextarea($p['name'], $lang[$field[1]])->id($p['id'])
188
                ->val(formText($value))
189
                ->addClass($p['class'])
190
                ->attr('rows', '6')->attr('cols', '50');
191
        }
192
        $form->addTagClose('div');
193
    }
194
    $form->addTagOpen('div')->addClass('buttons');
195
    $form->addButton('mediado[save]', $lang['btn_save'])->attr('type', 'submit')
196
        ->attrs(['accesskey' => 's']);
197
    $form->addTagClose('div');
198
199
    $form->addTagClose('div');
200
    echo $form->toHTML();
201
    return true;
202
}
203
204
/**
205
 * Convenience function to check if a media file is still in use
206
 *
207
 * @author Michael Klier <[email protected]>
208
 *
209
 * @param string $id media id
210
 * @return array|bool
211
 */
212
function media_inuse($id) {
213
    global $conf;
214
215
    if($conf['refcheck']){
216
        $mediareferences = ft_mediause($id,true);
217
        if(!count($mediareferences)) {
218
            return false;
219
        } else {
220
            return $mediareferences;
221
        }
222
    } else {
223
        return false;
224
    }
225
}
226
227
/**
228
 * Handles media file deletions
229
 *
230
 * If configured, checks for media references before deletion
231
 *
232
 * @author             Andreas Gohr <[email protected]>
233
 *
234
 * @param string $id media id
235
 * @param int $auth no longer used
236
 * @return int One of: 0,
237
 *                     DOKU_MEDIA_DELETED,
238
 *                     DOKU_MEDIA_DELETED | DOKU_MEDIA_EMPTY_NS,
239
 *                     DOKU_MEDIA_NOT_AUTH,
240
 *                     DOKU_MEDIA_INUSE
241
 */
242
function media_delete($id,$auth){
0 ignored issues
show
Unused Code introduced by
The parameter $auth is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
243
    global $lang;
244
    $auth = auth_quickaclcheck(ltrim(getNS($id).':*', ':'));
245
    if($auth < AUTH_DELETE) return DOKU_MEDIA_NOT_AUTH;
246
    if(media_inuse($id)) return DOKU_MEDIA_INUSE;
247
248
    $file = mediaFN($id);
249
250
    // trigger an event - MEDIA_DELETE_FILE
251
    $data = array();
252
    $data['id']   = $id;
253
    $data['name'] = \dokuwiki\Utf8\PhpString::basename($file);
254
    $data['path'] = $file;
255
    $data['size'] = (file_exists($file)) ? filesize($file) : 0;
256
257
    $data['unl'] = false;
258
    $data['del'] = false;
259
    $evt = new Event('MEDIA_DELETE_FILE',$data);
260
    if ($evt->advise_before()) {
261
        $old = @filemtime($file);
262
        if(!file_exists(mediaFN($id, $old)) && file_exists($file)) {
263
            // add old revision to the attic
264
            media_saveOldRevision($id);
265
        }
266
267
        $data['unl'] = @unlink($file);
268
        if($data['unl']) {
269
            $sizechange = 0 - $data['size'];
270
            addMediaLogEntry(time(), $id, DOKU_CHANGE_TYPE_DELETE, $lang['deleted'], '', null, $sizechange);
271
272
            $data['del'] = io_sweepNS($id, 'mediadir');
273
        }
274
    }
275
    $evt->advise_after();
276
    unset($evt);
277
278
    if($data['unl'] && $data['del']){
279
        return DOKU_MEDIA_DELETED | DOKU_MEDIA_EMPTY_NS;
280
    }
281
282
    return $data['unl'] ? DOKU_MEDIA_DELETED : 0;
283
}
284
285
/**
286
 * Handle file uploads via XMLHttpRequest
287
 *
288
 * @param string $ns   target namespace
289
 * @param int    $auth current auth check result
290
 * @return false|string false on error, id of the new file on success
291
 */
292
function media_upload_xhr($ns,$auth){
293
    if(!checkSecurityToken()) return false;
294
    global $INPUT;
295
296
    $id = $INPUT->get->str('qqfile');
297
    list($ext,$mime) = mimetype($id);
298
    $input = fopen("php://input", "r");
299
    if (!($tmp = io_mktmpdir())) return false;
300
    $path = $tmp.'/'.md5($id);
301
    $target = fopen($path, "w");
302
    $realSize = stream_copy_to_stream($input, $target);
303
    fclose($target);
304
    fclose($input);
305
    if (isset($_SERVER["CONTENT_LENGTH"]) && ($realSize != (int)$_SERVER["CONTENT_LENGTH"])){
306
        unlink($path);
307
        return false;
308
    }
309
310
    $res = media_save(
311
        array('name' => $path,
312
            'mime' => $mime,
313
            'ext'  => $ext),
314
        $ns.':'.$id,
315
        (($INPUT->get->str('ow') == 'true') ? true : false),
316
        $auth,
317
        'copy'
318
    );
319
    unlink($path);
320
    if ($tmp) io_rmdir($tmp, true);
321
    if (is_array($res)) {
322
        msg($res[0], $res[1]);
323
        return false;
324
    }
325
    return $res;
326
}
327
328
/**
329
 * Handles media file uploads
330
 *
331
 * @author Andreas Gohr <[email protected]>
332
 * @author Michael Klier <[email protected]>
333
 *
334
 * @param string     $ns    target namespace
335
 * @param int        $auth  current auth check result
336
 * @param bool|array $file  $_FILES member, $_FILES['upload'] if false
337
 * @return false|string false on error, id of the new file on success
338
 */
339
function media_upload($ns,$auth,$file=false){
340
    if(!checkSecurityToken()) return false;
341
    global $lang;
342
    global $INPUT;
343
344
    // get file and id
345
    $id   = $INPUT->post->str('mediaid');
346
    if (!$file) $file = $_FILES['upload'];
347
    if(empty($id)) $id = $file['name'];
348
349
    // check for errors (messages are done in lib/exe/mediamanager.php)
350
    if($file['error']) return false;
351
352
    // check extensions
353
    list($fext,$fmime) = mimetype($file['name']);
354
    list($iext,$imime) = mimetype($id);
355
    if($fext && !$iext){
356
        // no extension specified in id - read original one
357
        $id   .= '.'.$fext;
358
        $imime = $fmime;
359
    }elseif($fext && $fext != $iext){
360
        // extension was changed, print warning
361
        msg(sprintf($lang['mediaextchange'],$fext,$iext));
362
    }
363
364
    $res = media_save(array('name' => $file['tmp_name'],
365
                            'mime' => $imime,
366
                            'ext'  => $iext), $ns.':'.$id,
367
                      $INPUT->post->bool('ow'), $auth, 'copy_uploaded_file');
368
    if (is_array($res)) {
369
        msg($res[0], $res[1]);
370
        return false;
371
    }
372
    return $res;
373
}
374
375
/**
376
 * An alternative to move_uploaded_file that copies
377
 *
378
 * Using copy, makes sure any setgid bits on the media directory are honored
379
 *
380
 * @see   move_uploaded_file()
381
 *
382
 * @param string $from
383
 * @param string $to
384
 * @return bool
385
 */
386
function copy_uploaded_file($from, $to){
387
    if(!is_uploaded_file($from)) return false;
388
    $ok = copy($from, $to);
389
    @unlink($from);
390
    return $ok;
391
}
392
393
/**
394
 * This generates an action event and delegates to _media_upload_action().
395
 * Action plugins are allowed to pre/postprocess the uploaded file.
396
 * (The triggered event is preventable.)
397
 *
398
 * Event data:
399
 * $data[0]     fn_tmp:    the temporary file name (read from $_FILES)
400
 * $data[1]     fn:        the file name of the uploaded file
401
 * $data[2]     id:        the future directory id of the uploaded file
402
 * $data[3]     imime:     the mimetype of the uploaded file
403
 * $data[4]     overwrite: if an existing file is going to be overwritten
404
 * $data[5]     move:      name of function that performs move/copy/..
405
 *
406
 * @triggers MEDIA_UPLOAD_FINISH
407
 *
408
 * @param array  $file
409
 * @param string $id   media id
410
 * @param bool   $ow   overwrite?
411
 * @param int    $auth permission level
412
 * @param string $move name of functions that performs move/copy/..
413
 * @return false|array|string
414
 */
415
function media_save($file, $id, $ow, $auth, $move) {
416
    if($auth < AUTH_UPLOAD) {
417
        return array("You don't have permissions to upload files.", -1);
418
    }
419
420
    if (!isset($file['mime']) || !isset($file['ext'])) {
421
        list($ext, $mime) = mimetype($id);
422
        if (!isset($file['mime'])) {
423
            $file['mime'] = $mime;
424
        }
425
        if (!isset($file['ext'])) {
426
            $file['ext'] = $ext;
427
        }
428
    }
429
430
    global $lang, $conf;
431
432
    // get filename
433
    $id   = cleanID($id);
434
    $fn   = mediaFN($id);
435
436
    // get filetype regexp
437
    $types = array_keys(getMimeTypes());
438
    $types = array_map(
439
        function ($q) {
440
            return preg_quote($q, "/");
441
        },
442
        $types
443
    );
444
    $regex = join('|',$types);
445
446
    // because a temp file was created already
447
    if(!preg_match('/\.('.$regex.')$/i',$fn)) {
448
        return array($lang['uploadwrong'],-1);
449
    }
450
451
    //check for overwrite
452
    $overwrite = file_exists($fn);
453
    $auth_ow = (($conf['mediarevisions']) ? AUTH_UPLOAD : AUTH_DELETE);
454
    if($overwrite && (!$ow || $auth < $auth_ow)) {
455
        return array($lang['uploadexist'], 0);
456
    }
457
    // check for valid content
458
    $ok = media_contentcheck($file['name'], $file['mime']);
459
    if($ok == -1){
460
        return array(sprintf($lang['uploadbadcontent'],'.' . $file['ext']),-1);
461
    }elseif($ok == -2){
462
        return array($lang['uploadspam'],-1);
463
    }elseif($ok == -3){
464
        return array($lang['uploadxss'],-1);
465
    }
466
467
    // prepare event data
468
    $data = array();
469
    $data[0] = $file['name'];
470
    $data[1] = $fn;
471
    $data[2] = $id;
472
    $data[3] = $file['mime'];
473
    $data[4] = $overwrite;
474
    $data[5] = $move;
475
476
    // trigger event
477
    return Event::createAndTrigger('MEDIA_UPLOAD_FINISH', $data, '_media_upload_action', true);
478
}
479
480
/**
481
 * Callback adapter for media_upload_finish() triggered by MEDIA_UPLOAD_FINISH
482
 *
483
 * @author Michael Klier <[email protected]>
484
 *
485
 * @param array $data event data
486
 * @return false|array|string
487
 */
488
function _media_upload_action($data) {
489
    // fixme do further sanity tests of given data?
490
    if(is_array($data) && count($data)===6) {
491
        return media_upload_finish($data[0], $data[1], $data[2], $data[3], $data[4], $data[5]);
492
    } else {
493
        return false; //callback error
494
    }
495
}
496
497
/**
498
 * Saves an uploaded media file
499
 *
500
 * @author Andreas Gohr <[email protected]>
501
 * @author Michael Klier <[email protected]>
502
 * @author Kate Arzamastseva <[email protected]>
503
 *
504
 * @param string $fn_tmp
505
 * @param string $fn
506
 * @param string $id        media id
507
 * @param string $imime     mime type
508
 * @param bool   $overwrite overwrite existing?
509
 * @param string $move      function name
510
 * @return array|string
511
 */
512
function media_upload_finish($fn_tmp, $fn, $id, $imime, $overwrite, $move = 'move_uploaded_file') {
513
    global $conf;
514
    global $lang;
515
    global $REV;
516
517
    $old = @filemtime($fn);
518
    if(!file_exists(mediaFN($id, $old)) && file_exists($fn)) {
519
        // add old revision to the attic if missing
520
        media_saveOldRevision($id);
521
    }
522
523
    // prepare directory
524
    io_createNamespace($id, 'media');
525
526
    $filesize_old = file_exists($fn) ? filesize($fn) : 0;
527
528
    if($move($fn_tmp, $fn)) {
529
        @clearstatcache(true,$fn);
530
        $new = @filemtime($fn);
531
        // Set the correct permission here.
532
        // Always chmod media because they may be saved with different permissions than expected from the php umask.
533
        // (Should normally chmod to $conf['fperm'] only if $conf['fperm'] is set.)
534
        chmod($fn, $conf['fmode']);
535
        msg($lang['uploadsucc'],1);
536
        media_notify($id,$fn,$imime,$old,$new);
537
        // add a log entry to the media changelog
538
        $filesize_new = filesize($fn);
539
        $sizechange = $filesize_new - $filesize_old;
540
        if($REV) {
541
            addMediaLogEntry(
542
                $new,
543
                $id,
544
                DOKU_CHANGE_TYPE_REVERT,
545
                sprintf($lang['restored'], dformat($REV)),
546
                $REV,
547
                null,
548
                $sizechange
549
            );
550
        } elseif($overwrite) {
551
            addMediaLogEntry($new, $id, DOKU_CHANGE_TYPE_EDIT, '', '', null, $sizechange);
552
        } else {
553
            addMediaLogEntry($new, $id, DOKU_CHANGE_TYPE_CREATE, $lang['created'], '', null, $sizechange);
554
        }
555
        return $id;
556
    }else{
557
        return array($lang['uploadfail'],-1);
558
    }
559
}
560
561
/**
562
 * Moves the current version of media file to the media_attic
563
 * directory
564
 *
565
 * @author Kate Arzamastseva <[email protected]>
566
 *
567
 * @param string $id
568
 * @return int - revision date
569
 */
570
function media_saveOldRevision($id){
571
    global $conf, $lang;
572
573
    $oldf = mediaFN($id);
574
    if(!file_exists($oldf)) return '';
575
    $date = filemtime($oldf);
576
    if (!$conf['mediarevisions']) return $date;
577
578
    $medialog = new MediaChangeLog($id);
579
    if (!$medialog->getRevisionInfo($date)) {
580
        // there was an external edit,
581
        // there is no log entry for current version of file
582
        $sizechange = filesize($oldf);
583
        if(!file_exists(mediaMetaFN($id, '.changes'))) {
584
            addMediaLogEntry($date, $id, DOKU_CHANGE_TYPE_CREATE, $lang['created'], '', null, $sizechange);
585
        } else {
586
            $oldRev = $medialog->getRevisions(-1, 1); // from changelog
587
            $oldRev = (int) (empty($oldRev) ? 0 : $oldRev[0]);
588
            $filesize_old = filesize(mediaFN($id, $oldRev));
589
            $sizechange = $sizechange - $filesize_old;
590
591
            addMediaLogEntry($date, $id, DOKU_CHANGE_TYPE_EDIT, '', '', null, $sizechange);
592
        }
593
    }
594
595
    $newf = mediaFN($id,$date);
596
    io_makeFileDir($newf);
597
    if(copy($oldf, $newf)) {
598
        // Set the correct permission here.
599
        // Always chmod media because they may be saved with different permissions than expected from the php umask.
600
        // (Should normally chmod to $conf['fperm'] only if $conf['fperm'] is set.)
601
        chmod($newf, $conf['fmode']);
602
    }
603
    return $date;
604
}
605
606
/**
607
 * This function checks if the uploaded content is really what the
608
 * mimetype says it is. We also do spam checking for text types here.
609
 *
610
 * We need to do this stuff because we can not rely on the browser
611
 * to do this check correctly. Yes, IE is broken as usual.
612
 *
613
 * @author Andreas Gohr <[email protected]>
614
 * @link   http://www.splitbrain.org/blog/2007-02/12-internet_explorer_facilitates_cross_site_scripting
615
 * @fixme  check all 26 magic IE filetypes here?
616
 *
617
 * @param string $file path to file
618
 * @param string $mime mimetype
619
 * @return int
620
 */
621
function media_contentcheck($file,$mime){
622
    global $conf;
623
    if($conf['iexssprotect']){
624
        $fh = @fopen($file, 'rb');
625
        if($fh){
626
            $bytes = fread($fh, 256);
627
            fclose($fh);
628
            if(preg_match('/<(script|a|img|html|body|iframe)[\s>]/i',$bytes)){
629
                return -3; //XSS: possibly malicious content
630
            }
631
        }
632
    }
633
    if(substr($mime,0,6) == 'image/'){
634
        $info = @getimagesize($file);
635
        if($mime == 'image/gif' && $info[2] != 1){
636
            return -1; // uploaded content did not match the file extension
637
        }elseif($mime == 'image/jpeg' && $info[2] != 2){
638
            return -1;
639
        }elseif($mime == 'image/png' && $info[2] != 3){
640
            return -1;
641
        }
642
        # fixme maybe check other images types as well
643
    }elseif(substr($mime,0,5) == 'text/'){
644
        global $TEXT;
645
        $TEXT = io_readFile($file);
646
        if(checkwordblock()){
647
            return -2; //blocked by the spam blacklist
648
        }
649
    }
650
    return 0;
651
}
652
653
/**
654
 * Send a notify mail on uploads
655
 *
656
 * @author Andreas Gohr <[email protected]>
657
 *
658
 * @param string   $id      media id
659
 * @param string   $file    path to file
660
 * @param string   $mime    mime type
661
 * @param bool|int $old_rev revision timestamp or false
662
 * @return bool
663
 */
664
function media_notify($id,$file,$mime,$old_rev=false,$current_rev=false){
0 ignored issues
show
Unused Code introduced by
The parameter $file is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $mime is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
665
    global $conf;
666
    if(empty($conf['notify'])) return false; //notify enabled?
667
668
    $subscription = new MediaSubscriptionSender();
669
    return $subscription->sendMediaDiff($conf['notify'], 'uploadmail', $id, $old_rev, $current_rev);
670
}
671
672
/**
673
 * List all files in a given Media namespace
674
 *
675
 * @param string      $ns             namespace
676
 * @param null|int    $auth           permission level
677
 * @param string      $jump           id
678
 * @param bool        $fullscreenview
679
 * @param bool|string $sort           sorting order, false skips sorting
680
 */
681
function media_filelist($ns,$auth=null,$jump='',$fullscreenview=false,$sort=false){
0 ignored issues
show
Unused Code introduced by
The parameter $jump is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
682
    global $conf;
683
    global $lang;
684
    $ns = cleanID($ns);
685
686
    // check auth our self if not given (needed for ajax calls)
687
    if(is_null($auth)) $auth = auth_quickaclcheck("$ns:*");
688
689
    if (!$fullscreenview) echo '<h1 id="media__ns">:'.hsc($ns).'</h1>'.NL;
690
691
    if($auth < AUTH_READ){
692
        // FIXME: print permission warning here instead?
693
        echo '<div class="nothing">'.$lang['nothingfound'].'</div>'.NL;
694
    }else{
695
        if (!$fullscreenview) {
696
            media_uploadform($ns, $auth);
697
            media_searchform($ns);
698
        }
699
700
        $dir = utf8_encodeFN(str_replace(':','/',$ns));
701
        $data = array();
702
        search($data,$conf['mediadir'],'search_mediafiles',
703
                array('showmsg'=>true,'depth'=>1),$dir,1,$sort);
704
705
        if(!count($data)){
706
            echo '<div class="nothing">'.$lang['nothingfound'].'</div>'.NL;
707
        }else {
708
            if ($fullscreenview) {
709
                echo '<ul class="' . _media_get_list_type() . '">';
710
            }
711
            foreach($data as $item){
712
                if (!$fullscreenview) {
713
                    //FIXME old call: media_printfile($item,$auth,$jump);
714
                    $display = new \dokuwiki\Ui\Media\DisplayRow($item);
715
                    $display->show();
716
                } else {
717
                    //FIXME old call: media_printfile_thumbs($item,$auth,$jump);
718
                    echo '<li>';
719
                    $display = new \dokuwiki\Ui\Media\DisplayTile($item);
720
                    $display->show();
721
                    echo '</li>';
722
                }
723
            }
724
            if ($fullscreenview) echo '</ul>'.NL;
725
        }
726
    }
727
}
728
729
/**
730
 * Prints tabs for files list actions
731
 *
732
 * @author Kate Arzamastseva <[email protected]>
733
 * @author Adrian Lang <[email protected]>
734
 *
735
 * @param string $selected_tab - opened tab
736
 */
737
738
function media_tabs_files($selected_tab = ''){
739
    global $lang;
740
    $tabs = array();
741
    foreach(array('files'  => 'mediaselect',
742
                  'upload' => 'media_uploadtab',
743
                  'search' => 'media_searchtab') as $tab => $caption) {
744
        $tabs[$tab] = array('href'    => media_managerURL(['tab_files' => $tab], '&'),
745
                            'caption' => $lang[$caption]);
746
    }
747
748
    html_tabs($tabs, $selected_tab);
749
}
750
751
/**
752
 * Prints tabs for files details actions
753
 *
754
 * @author Kate Arzamastseva <[email protected]>
755
 * @param string $image filename of the current image
756
 * @param string $selected_tab opened tab
757
 */
758
function media_tabs_details($image, $selected_tab = '') {
759
    global $lang, $conf;
760
761
    $tabs = array();
762
    $tabs['view'] = array('href'    => media_managerURL(['tab_details' => 'view'], '&'),
763
                          'caption' => $lang['media_viewtab']);
764
765
    list(, $mime) = mimetype($image);
766
    if ($mime == 'image/jpeg' && file_exists(mediaFN($image))) {
767
        $tabs['edit'] = array('href'    => media_managerURL(['tab_details' => 'edit'], '&'),
768
                              'caption' => $lang['media_edittab']);
769
    }
770
    if ($conf['mediarevisions']) {
771
        $tabs['history'] = array('href'    => media_managerURL(['tab_details' => 'history'], '&'),
772
                                 'caption' => $lang['media_historytab']);
773
    }
774
775
    html_tabs($tabs, $selected_tab);
776
}
777
778
/**
779
 * Prints options for the tab that displays a list of all files
780
 *
781
 * @author Kate Arzamastseva <[email protected]>
782
 */
783
function media_tab_files_options() {
784
    global $lang;
785
    global $INPUT;
786
    global $ID;
787
788
    $form = new Form([
789
            'method' => 'get',
790
            'action' => wl($ID),
791
            'class' => 'options'
792
    ]);
793
    $form->addTagOpen('div')->addClass('no');
794
    $form->setHiddenField('sectok', null);
795
    $media_manager_params = media_managerURL([], '', false, true);
796
    foreach ($media_manager_params as $pKey => $pVal) {
0 ignored issues
show
Bug introduced by
The expression $media_manager_params of type string|array is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
797
        $form->setHiddenField($pKey, $pVal);
798
    }
799
    if ($INPUT->has('q')) {
800
        $form->setHiddenField('q', $INPUT->str('q'));
801
    }
802
    $form->addHTML('<ul>'.NL);
803
    foreach (array('list' => array('listType', array('thumbs', 'rows')),
804
                  'sort' => array('sortBy', array('name', 'date')))
805
            as $group => $content) {
806
        $checked = "_media_get_${group}_type";
807
        $checked = $checked();
808
809
        $form->addHTML('<li class="'. $content[0] .'">');
810
        foreach ($content[1] as $option) {
811
            $attrs = array();
812
            if ($checked == $option) {
813
                $attrs['checked'] = 'checked';
814
            }
815
            $radio = $form->addRadioButton(
816
                $group.'_dwmedia',
817
                $lang['media_'.$group.'_'.$option]
818
            )->val($option)->id($content[0].'__'.$option)->addClass($option);
819
            $radio->attrs($attrs);
820
        }
821
        $form->addHTML('</li>'.NL);
822
    }
823
    $form->addHTML('<li>');
824
    $form->addButton('', $lang['btn_apply'])->attr('type', 'submit');
825
    $form->addHTML('</li>'.NL);
826
    $form->addHTML('</ul>'.NL);
827
    $form->addTagClose('div');
828
    print $form->toHTML();
829
}
830
831
/**
832
 * Returns type of sorting for the list of files in media manager
833
 *
834
 * @author Kate Arzamastseva <[email protected]>
835
 *
836
 * @return string - sort type
837
 */
838
function _media_get_sort_type() {
839
    return _media_get_display_param('sort', array('default' => 'name', 'date'));
840
}
841
842
/**
843
 * Returns type of listing for the list of files in media manager
844
 *
845
 * @author Kate Arzamastseva <[email protected]>
846
 *
847
 * @return string - list type
848
 */
849
function _media_get_list_type() {
850
    return _media_get_display_param('list', array('default' => 'thumbs', 'rows'));
851
}
852
853
/**
854
 * Get display parameters
855
 *
856
 * @param string $param   name of parameter
857
 * @param array  $values  allowed values, where default value has index key 'default'
858
 * @return string the parameter value
859
 */
860
function _media_get_display_param($param, $values) {
861
    global $INPUT;
862
    if (in_array($INPUT->str($param), $values)) {
863
        // FIXME: Set cookie
864
        return $INPUT->str($param);
865
    } else {
866
        $val = get_doku_pref($param, $values['default']);
867
        if (!in_array($val, $values)) {
868
            $val = $values['default'];
869
        }
870
        return $val;
871
    }
872
}
873
874
/**
875
 * Prints tab that displays a list of all files
876
 *
877
 * @author Kate Arzamastseva <[email protected]>
878
 *
879
 * @param string    $ns
880
 * @param null|int  $auth permission level
881
 * @param string    $jump item id
882
 */
883
function media_tab_files($ns,$auth=null,$jump='') {
884
    global $lang;
885
    if(is_null($auth)) $auth = auth_quickaclcheck("$ns:*");
886
887
    if($auth < AUTH_READ){
888
        echo '<div class="nothing">'.$lang['media_perm_read'].'</div>'.NL;
889
    }else{
890
        media_filelist($ns,$auth,$jump,true,_media_get_sort_type());
891
    }
892
}
893
894
/**
895
 * Prints tab that displays uploading form
896
 *
897
 * @author Kate Arzamastseva <[email protected]>
898
 *
899
 * @param string   $ns
900
 * @param null|int $auth permission level
901
 * @param string   $jump item id
902
 */
903
function media_tab_upload($ns,$auth=null,$jump='') {
0 ignored issues
show
Unused Code introduced by
The parameter $jump is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
904
    global $lang;
905
    if(is_null($auth)) $auth = auth_quickaclcheck("$ns:*");
906
907
    echo '<div class="upload">'.NL;
908
    if ($auth >= AUTH_UPLOAD) {
909
        echo '<p>' . $lang['mediaupload'] . '</p>';
910
    }
911
    media_uploadform($ns, $auth, true);
912
    echo '</div>'.NL;
913
}
914
915
/**
916
 * Prints tab that displays search form
917
 *
918
 * @author Kate Arzamastseva <[email protected]>
919
 *
920
 * @param string $ns
921
 * @param null|int $auth permission level
922
 */
923
function media_tab_search($ns,$auth=null) {
924
    global $INPUT;
925
926
    $do = $INPUT->str('mediado');
927
    $query = $INPUT->str('q');
928
    echo '<div class="search">'.NL;
929
930
    media_searchform($ns, $query, true);
931
    if ($do == 'searchlist' || $query) {
932
        media_searchlist($query,$ns,$auth,true,_media_get_sort_type());
933
    }
934
    echo '</div>'.NL;
935
}
936
937
/**
938
 * Prints tab that displays mediafile details
939
 *
940
 * @author Kate Arzamastseva <[email protected]>
941
 *
942
 * @param string     $image media id
943
 * @param string     $ns
944
 * @param null|int   $auth  permission level
945
 * @param string|int $rev   revision timestamp or empty string
946
 */
947
function media_tab_view($image, $ns, $auth=null, $rev='') {
948
    global $lang;
949
    if(is_null($auth)) $auth = auth_quickaclcheck("$ns:*");
950
951
    if ($image && $auth >= AUTH_READ) {
952
        $meta = new JpegMeta(mediaFN($image, $rev));
953
        media_preview($image, $auth, $rev, $meta);
954
        media_preview_buttons($image, $auth, $rev);
955
        media_details($image, $auth, $rev, $meta);
956
957
    } else {
958
        echo '<div class="nothing">'.$lang['media_perm_read'].'</div>'.NL;
959
    }
960
}
961
962
/**
963
 * Prints tab that displays form for editing mediafile metadata
964
 *
965
 * @author Kate Arzamastseva <[email protected]>
966
 *
967
 * @param string     $image media id
968
 * @param string     $ns
969
 * @param null|int   $auth permission level
970
 */
971
function media_tab_edit($image, $ns, $auth=null) {
972
    if(is_null($auth)) $auth = auth_quickaclcheck("$ns:*");
973
974
    if ($image) {
975
        list(, $mime) = mimetype($image);
976
        if ($mime == 'image/jpeg') media_metaform($image,$auth);
977
    }
978
}
979
980
/**
981
 * Prints tab that displays mediafile revisions
982
 *
983
 * @author Kate Arzamastseva <[email protected]>
984
 *
985
 * @param string     $image media id
986
 * @param string     $ns
987
 * @param null|int   $auth permission level
988
 */
989
function media_tab_history($image, $ns, $auth=null) {
990
    global $lang;
991
    global $INPUT;
992
993
    if(is_null($auth)) $auth = auth_quickaclcheck("$ns:*");
994
    $do = $INPUT->str('mediado');
995
996
    if ($auth >= AUTH_READ && $image) {
997
        if ($do == 'diff'){
998
            media_diff($image, $ns, $auth);
999
        } else {
1000
            $first = $INPUT->int('first');
1001
            html_revisions($first, $image);
0 ignored issues
show
Deprecated Code introduced by
The function html_revisions() has been deprecated with message: 2020-07-18

This function has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed from the class and what other function to use instead.

Loading history...
1002
        }
1003
    } else {
1004
        echo '<div class="nothing">'.$lang['media_perm_read'].'</div>'.NL;
1005
    }
1006
}
1007
1008
/**
1009
 * Prints mediafile details
1010
 *
1011
 * @param string         $image media id
1012
 * @param int            $auth permission level
1013
 * @param int|string     $rev revision timestamp or empty string
1014
 * @param JpegMeta|bool  $meta
1015
 *
1016
 * @author Kate Arzamastseva <[email protected]>
1017
 */
1018
function media_preview($image, $auth, $rev='', $meta=false) {
0 ignored issues
show
Unused Code introduced by
The parameter $auth is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1019
1020
    $size = media_image_preview_size($image, $rev, $meta);
1021
1022
    if ($size) {
1023
        global $lang;
1024
        echo '<div class="image">';
1025
1026
        $more = array();
1027
        if ($rev) {
1028
            $more['rev'] = $rev;
1029
        } else {
1030
            $t = @filemtime(mediaFN($image));
1031
            $more['t'] = $t;
1032
        }
1033
1034
        $more['w'] = $size[0];
1035
        $more['h'] = $size[1];
1036
        $src = ml($image, $more);
1037
1038
        echo '<a href="'.$src.'" target="_blank" title="'.$lang['mediaview'].'">';
1039
        echo '<img src="'.$src.'" alt="" style="max-width: '.$size[0].'px;" />';
1040
        echo '</a>';
1041
1042
        echo '</div>'.NL;
1043
    }
1044
}
1045
1046
/**
1047
 * Prints mediafile action buttons
1048
 *
1049
 * @author Kate Arzamastseva <[email protected]>
1050
 *
1051
 * @param string     $image media id
1052
 * @param int        $auth  permission level
1053
 * @param string|int $rev   revision timestamp, or empty string
1054
 */
1055
function media_preview_buttons($image, $auth, $rev = '') {
1056
    global $lang, $conf;
1057
1058
    echo '<ul class="actions">'.DOKU_LF;
1059
1060
    if ($auth >= AUTH_DELETE && !$rev && file_exists(mediaFN($image))) {
1061
1062
        // delete button
1063
        $form = new Form([
1064
            'id' => 'mediamanager__btn_delete',
1065
            'action' => media_managerURL(['delete' => $image], '&'),
1066
        ]);
1067
        $form->addTagOpen('div')->addClass('no');
1068
        $form->addButton('', $lang['btn_delete'])->attr('type', 'submit');
1069
        $form->addTagClose('div');
1070
        echo '<li>';
1071
        echo $form->toHTML();
1072
        echo '</li>'.DOKU_LF;
1073
    }
1074
1075
    $auth_ow = (($conf['mediarevisions']) ? AUTH_UPLOAD : AUTH_DELETE);
1076
    if ($auth >= $auth_ow && !$rev) {
1077
1078
        // upload new version button
1079
        $form = new Form([
1080
            'id' => 'mediamanager__btn_update',
1081
            'action' => media_managerURL(['image' => $image, 'mediado' => 'update'], '&'),
1082
        ]);
1083
        $form->addTagOpen('div')->addClass('no');
1084
        $form->addButton('', $lang['media_update'])->attr('type', 'submit');
1085
        $form->addTagClose('div');
1086
        echo '<li>';
1087
        echo $form->toHTML();
1088
        echo '</li>'.DOKU_LF;
1089
    }
1090
1091
    if ($auth >= AUTH_UPLOAD && $rev && $conf['mediarevisions'] && file_exists(mediaFN($image, $rev))) {
1092
1093
        // restore button
1094
        $form = new Form([
1095
            'id' => 'mediamanager__btn_restore',
1096
            'action'=>media_managerURL(['image' => $image], '&'),
1097
        ]);
1098
        $form->addTagOpen('div')->addClass('no');
1099
        $form->setHiddenField('mediado', 'restore');
1100
        $form->setHiddenField('rev', $rev);
1101
        $form->addButton('', $lang['media_restore'])->attr('type', 'submit');
1102
        $form->addTagClose('div');
1103
        echo '<li>';
1104
        echo $form->toHTML();
1105
        echo '</li>'.DOKU_LF;
1106
    }
1107
1108
    echo '</ul>'.DOKU_LF;
1109
}
1110
1111
/**
1112
 * Returns image width and height for mediamanager preview panel
1113
 *
1114
 * @author Kate Arzamastseva <[email protected]>
1115
 * @param string         $image
1116
 * @param int|string     $rev
1117
 * @param JpegMeta|bool  $meta
1118
 * @param int            $size
1119
 * @return array|false
1120
 */
1121
function media_image_preview_size($image, $rev, $meta, $size = 500) {
1122
    if (!preg_match("/\.(jpe?g|gif|png)$/", $image) || !file_exists(mediaFN($image, $rev))) return false;
1123
1124
    $info = getimagesize(mediaFN($image, $rev));
1125
    $w = (int) $info[0];
1126
    $h = (int) $info[1];
1127
1128
    if($meta && ($w > $size || $h > $size)){
1129
        $ratio = $meta->getResizeRatio($size, $size);
0 ignored issues
show
Bug introduced by
It seems like $meta is not always an object, but can also be of type boolean. Maybe add an additional type check?

If a variable is not always an object, we recommend to add an additional type check to ensure your method call is safe:

function someFunction(A $objectMaybe = null)
{
    if ($objectMaybe instanceof A) {
        $objectMaybe->doSomething();
    }
}
Loading history...
1130
        $w = floor($w * $ratio);
1131
        $h = floor($h * $ratio);
1132
    }
1133
    return array($w, $h);
1134
}
1135
1136
/**
1137
 * Returns the requested EXIF/IPTC tag from the image meta
1138
 *
1139
 * @author Kate Arzamastseva <[email protected]>
1140
 *
1141
 * @param array    $tags array with tags, first existing is returned
1142
 * @param JpegMeta $meta
1143
 * @param string   $alt  alternative value
1144
 * @return string
1145
 */
1146
function media_getTag($tags,$meta,$alt=''){
1147
    if($meta === false) return $alt;
1148
    $info = $meta->getField($tags);
1149
    if($info == false) return $alt;
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $info of type false|array|string against false; this is ambiguous if the string can be empty. Consider using a strict comparison === instead.
Loading history...
1150
    return $info;
1151
}
1152
1153
/**
1154
 * Returns mediafile tags
1155
 *
1156
 * @author Kate Arzamastseva <[email protected]>
1157
 *
1158
 * @param JpegMeta $meta
1159
 * @return array list of tags of the mediafile
1160
 */
1161
function media_file_tags($meta) {
1162
    // load the field descriptions
1163
    static $fields = null;
1164
    if(is_null($fields)){
1165
        $config_files = getConfigFiles('mediameta');
1166
        foreach ($config_files as $config_file) {
1167
            if(file_exists($config_file)) include($config_file);
1168
        }
1169
    }
1170
1171
    $tags = array();
1172
1173
    foreach($fields as $key => $tag){
0 ignored issues
show
Bug introduced by
The expression $fields of type null is not traversable.
Loading history...
1174
        $t = array();
1175
        if (!empty($tag[0])) $t = array($tag[0]);
1176
        if(isset($tag[3]) && is_array($tag[3])) $t = array_merge($t,$tag[3]);
1177
        $value = media_getTag($t, $meta);
1178
        $tags[] = array('tag' => $tag, 'value' => $value);
1179
    }
1180
1181
    return $tags;
1182
}
1183
1184
/**
1185
 * Prints mediafile tags
1186
 *
1187
 * @author Kate Arzamastseva <[email protected]>
1188
 *
1189
 * @param string        $image image id
1190
 * @param int           $auth  permission level
1191
 * @param string|int    $rev   revision timestamp, or empty string
1192
 * @param bool|JpegMeta $meta  image object, or create one if false
1193
 */
1194
function media_details($image, $auth, $rev='', $meta=false) {
0 ignored issues
show
Unused Code introduced by
The parameter $auth is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1195
    global $lang;
1196
1197
    if (!$meta) $meta = new JpegMeta(mediaFN($image, $rev));
1198
    $tags = media_file_tags($meta);
0 ignored issues
show
Bug introduced by
It seems like $meta defined by parameter $meta on line 1194 can also be of type boolean; however, media_file_tags() does only seem to accept object<JpegMeta>, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
1199
1200
    echo '<dl>'.NL;
1201
    foreach($tags as $tag){
1202
        if ($tag['value']) {
1203
            $value = cleanText($tag['value']);
1204
            echo '<dt>'.$lang[$tag['tag'][1]].'</dt><dd>';
1205
            if ($tag['tag'][2] == 'date') echo dformat($value);
1206
            else echo hsc($value);
1207
            echo '</dd>'.NL;
1208
        }
1209
    }
1210
    echo '</dl>'.NL;
1211
    echo '<dl>'.NL;
1212
    echo '<dt>'.$lang['reference'].':</dt>';
1213
    $media_usage = ft_mediause($image,true);
1214
    if(count($media_usage) > 0){
1215
        foreach($media_usage as $path){
1216
            echo '<dd>'.html_wikilink($path).'</dd>';
1217
        }
1218
    }else{
1219
        echo '<dd>'.$lang['nothingfound'].'</dd>';
1220
    }
1221
    echo '</dl>'.NL;
1222
1223
}
1224
1225
/**
1226
 * Shows difference between two revisions of file
1227
 *
1228
 * @author Kate Arzamastseva <[email protected]>
1229
 *
1230
 * @param string $image  image id
1231
 * @param string $ns
1232
 * @param int $auth permission level
1233
 * @param bool $fromajax
1234
 * @return false|null|string
1235
 */
1236
function media_diff($image, $ns, $auth, $fromajax = false) {
1237
    global $conf;
1238
    global $INPUT;
1239
1240
    if ($auth < AUTH_READ || !$image || !$conf['mediarevisions']) return '';
1241
1242
    $rev1 = $INPUT->int('rev');
1243
1244
    $rev2 = $INPUT->ref('rev2');
1245
    if(is_array($rev2)){
1246
        $rev1 = (int) $rev2[0];
1247
        $rev2 = (int) $rev2[1];
1248
1249
        if(!$rev1){
1250
            $rev1 = $rev2;
1251
            unset($rev2);
1252
        }
1253
    }else{
1254
        $rev2 = $INPUT->int('rev2');
1255
    }
1256
1257
    if ($rev1 && !file_exists(mediaFN($image, $rev1))) $rev1 = false;
1258
    if ($rev2 && !file_exists(mediaFN($image, $rev2))) $rev2 = false;
1259
1260
    if($rev1 && $rev2){            // two specific revisions wanted
1261
        // make sure order is correct (older on the left)
1262
        if($rev1 < $rev2){
1263
            $l_rev = $rev1;
1264
            $r_rev = $rev2;
1265
        }else{
1266
            $l_rev = $rev2;
1267
            $r_rev = $rev1;
1268
        }
1269
    }elseif($rev1){                // single revision given, compare to current
1270
        $r_rev = '';
1271
        $l_rev = $rev1;
1272
    }else{                        // no revision was given, compare previous to current
1273
        $r_rev = '';
1274
        $medialog = new MediaChangeLog($image);
1275
        $revs = $medialog->getRevisions(0, 1);
1276
        if (file_exists(mediaFN($image, $revs[0]))) {
1277
            $l_rev = $revs[0];
1278
        } else {
1279
            $l_rev = '';
1280
        }
1281
    }
1282
1283
    // prepare event data
1284
    $data = array();
1285
    $data[0] = $image;
1286
    $data[1] = $l_rev;
1287
    $data[2] = $r_rev;
1288
    $data[3] = $ns;
1289
    $data[4] = $auth;
1290
    $data[5] = $fromajax;
1291
1292
    // trigger event
1293
    return Event::createAndTrigger('MEDIA_DIFF', $data, '_media_file_diff', true);
1294
}
1295
1296
/**
1297
 * Callback for media file diff
1298
 *
1299
 * @param array $data event data
1300
 * @return false|null
1301
 */
1302
function _media_file_diff($data) {
1303
    if(is_array($data) && count($data)===6) {
1304
        media_file_diff($data[0], $data[1], $data[2], $data[3], $data[4], $data[5]);
1305
    } else {
1306
        return false;
1307
    }
1308
}
1309
1310
/**
1311
 * Shows difference between two revisions of image
1312
 *
1313
 * @author Kate Arzamastseva <[email protected]>
1314
 *
1315
 * @param string $image
1316
 * @param string|int $l_rev revision timestamp, or empty string
1317
 * @param string|int $r_rev revision timestamp, or empty string
1318
 * @param string $ns
1319
 * @param int $auth permission level
1320
 * @param bool $fromajax
1321
 */
1322
function media_file_diff($image, $l_rev, $r_rev, $ns, $auth, $fromajax) {
0 ignored issues
show
Unused Code introduced by
The parameter $ns is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1323
    global $lang;
1324
    global $INPUT;
1325
1326
    $l_meta = new JpegMeta(mediaFN($image, $l_rev));
1327
    $r_meta = new JpegMeta(mediaFN($image, $r_rev));
1328
1329
    $is_img = preg_match('/\.(jpe?g|gif|png)$/', $image);
1330
    if ($is_img) {
1331
        $l_size = media_image_preview_size($image, $l_rev, $l_meta);
1332
        $r_size = media_image_preview_size($image, $r_rev, $r_meta);
1333
        $is_img = ($l_size && $r_size && ($l_size[0] >= 30 || $r_size[0] >= 30));
1334
1335
        $difftype = $INPUT->str('difftype');
1336
1337
        if (!$fromajax) {
1338
            $form = new Form([
1339
                'id' => 'mediamanager__form_diffview',
1340
                'action' => media_managerURL([], '&'),
1341
                'method' => 'get',
1342
                'class' => 'diffView',
1343
            ]);
1344
            $form->addTagOpen('div')->addClass('no');
1345
            $form->setHiddenField('sectok', null);
1346
            $form->setHiddenField('mediado', 'diff');
1347
            $form->setHiddenField('rev2[0]', $l_rev);
1348
            $form->setHiddenField('rev2[1]', $r_rev);
1349
            echo $form->toHTML();
1350
1351
            echo NL.'<div id="mediamanager__diff" >'.NL;
1352
        }
1353
1354
        if ($difftype == 'opacity' || $difftype == 'portions') {
1355
            media_image_diff($image, $l_rev, $r_rev, $l_size, $r_size, $difftype);
0 ignored issues
show
Security Bug introduced by
It seems like $l_size defined by media_image_preview_size($image, $l_rev, $l_meta) on line 1331 can also be of type false; however, media_image_diff() does only seem to accept array, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
Security Bug introduced by
It seems like $r_size defined by media_image_preview_size($image, $r_rev, $r_meta) on line 1332 can also be of type false; however, media_image_diff() does only seem to accept array, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
1356
            if (!$fromajax) echo '</div>';
1357
            return;
1358
        }
1359
    }
1360
1361
    list($l_head, $r_head) = (new dokuwiki\Ui\Diff)->diffHead($l_rev, $r_rev, $image, true);
1362
1363
    ?>
1364
    <div class="table">
1365
    <table>
1366
      <tr>
1367
        <th><?php echo $l_head; ?></th>
1368
        <th><?php echo $r_head; ?></th>
1369
      </tr>
1370
    <?php
1371
1372
    echo '<tr class="image">';
1373
    echo '<td>';
1374
    media_preview($image, $auth, $l_rev, $l_meta);
1375
    echo '</td>';
1376
1377
    echo '<td>';
1378
    media_preview($image, $auth, $r_rev, $r_meta);
1379
    echo '</td>';
1380
    echo '</tr>'.NL;
1381
1382
    echo '<tr class="actions">';
1383
    echo '<td>';
1384
    media_preview_buttons($image, $auth, $l_rev);
1385
    echo '</td>';
1386
1387
    echo '<td>';
1388
    media_preview_buttons($image, $auth, $r_rev);
1389
    echo '</td>';
1390
    echo '</tr>'.NL;
1391
1392
    $l_tags = media_file_tags($l_meta);
1393
    $r_tags = media_file_tags($r_meta);
1394
    // FIXME r_tags-only stuff
1395
    foreach ($l_tags as $key => $l_tag) {
1396
        if ($l_tag['value'] != $r_tags[$key]['value']) {
1397
            $r_tags[$key]['highlighted'] = true;
1398
            $l_tags[$key]['highlighted'] = true;
1399
        } else if (!$l_tag['value'] || !$r_tags[$key]['value']) {
1400
            unset($r_tags[$key]);
1401
            unset($l_tags[$key]);
1402
        }
1403
    }
1404
1405
    echo '<tr>';
1406
    foreach(array($l_tags,$r_tags) as $tags){
1407
        echo '<td>'.NL;
1408
1409
        echo '<dl class="img_tags">';
1410
        foreach($tags as $tag){
1411
            $value = cleanText($tag['value']);
1412
            if (!$value) $value = '-';
1413
            echo '<dt>'.$lang[$tag['tag'][1]].'</dt>';
1414
            echo '<dd>';
1415
            if ($tag['highlighted']) {
1416
                echo '<strong>';
1417
            }
1418
            if ($tag['tag'][2] == 'date') echo dformat($value);
1419
            else echo hsc($value);
1420
            if ($tag['highlighted']) {
1421
                echo '</strong>';
1422
            }
1423
            echo '</dd>';
1424
        }
1425
        echo '</dl>'.NL;
1426
1427
        echo '</td>';
1428
    }
1429
    echo '</tr>'.NL;
1430
1431
    echo '</table>'.NL;
1432
    echo '</div>'.NL;
1433
1434
    if ($is_img && !$fromajax) echo '</div>';
1435
}
1436
1437
/**
1438
 * Prints two images side by side
1439
 * and slider
1440
 *
1441
 * @author Kate Arzamastseva <[email protected]>
1442
 *
1443
 * @param string $image   image id
1444
 * @param int    $l_rev   revision timestamp, or empty string
1445
 * @param int    $r_rev   revision timestamp, or empty string
1446
 * @param array  $l_size  array with width and height
1447
 * @param array  $r_size  array with width and height
1448
 * @param string $type
1449
 */
1450
function media_image_diff($image, $l_rev, $r_rev, $l_size, $r_size, $type) {
1451
    if ($l_size != $r_size) {
1452
        if ($r_size[0] > $l_size[0]) {
1453
            $l_size = $r_size;
1454
        }
1455
    }
1456
1457
    $l_more = array('rev' => $l_rev, 'h' => $l_size[1], 'w' => $l_size[0]);
1458
    $r_more = array('rev' => $r_rev, 'h' => $l_size[1], 'w' => $l_size[0]);
1459
1460
    $l_src = ml($image, $l_more);
1461
    $r_src = ml($image, $r_more);
1462
1463
    // slider
1464
    echo '<div class="slider" style="max-width: '.($l_size[0]-20).'px;" ></div>'.NL;
1465
1466
    // two images in divs
1467
    echo '<div class="imageDiff ' . $type . '">'.NL;
1468
    echo '<div class="image1" style="max-width: '.$l_size[0].'px;">';
1469
    echo '<img src="'.$l_src.'" alt="" />';
1470
    echo '</div>'.NL;
1471
    echo '<div class="image2" style="max-width: '.$l_size[0].'px;">';
1472
    echo '<img src="'.$r_src.'" alt="" />';
1473
    echo '</div>'.NL;
1474
    echo '</div>'.NL;
1475
}
1476
1477
/**
1478
 * Restores an old revision of a media file
1479
 *
1480
 * @param string $image media id
1481
 * @param int    $rev   revision timestamp or empty string
1482
 * @param int    $auth
1483
 * @return string - file's id
1484
 *
1485
 * @author Kate Arzamastseva <[email protected]>
1486
 */
1487
function media_restore($image, $rev, $auth){
1488
    global $conf;
1489
    if ($auth < AUTH_UPLOAD || !$conf['mediarevisions']) return false;
1490
    $removed = (!file_exists(mediaFN($image)) && file_exists(mediaMetaFN($image, '.changes')));
1491
    if (!$image || (!file_exists(mediaFN($image)) && !$removed)) return false;
1492
    if (!$rev || !file_exists(mediaFN($image, $rev))) return false;
1493
    list(,$imime,) = mimetype($image);
1494
    $res = media_upload_finish(mediaFN($image, $rev),
1495
        mediaFN($image),
1496
        $image,
1497
        $imime,
1498
        true,
1499
        'copy');
1500
    if (is_array($res)) {
1501
        msg($res[0], $res[1]);
1502
        return false;
1503
    }
1504
    return $res;
1505
}
1506
1507
/**
1508
 * List all files found by the search request
1509
 *
1510
 * @author Tobias Sarnowski <[email protected]>
1511
 * @author Andreas Gohr <[email protected]>
1512
 * @author Kate Arzamastseva <[email protected]>
1513
 * @triggers MEDIA_SEARCH
1514
 *
1515
 * @param string $query
1516
 * @param string $ns
1517
 * @param null|int $auth
1518
 * @param bool $fullscreen
1519
 * @param string $sort
1520
 */
1521
function media_searchlist($query,$ns,$auth=null,$fullscreen=false,$sort='natural'){
0 ignored issues
show
Unused Code introduced by
The parameter $auth is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1522
    global $conf;
1523
    global $lang;
1524
1525
    $ns = cleanID($ns);
1526
    $evdata = array(
1527
        'ns'    => $ns,
1528
        'data'  => array(),
1529
        'query' => $query
1530
    );
1531
    if (!blank($query)) {
1532
        $evt = new Event('MEDIA_SEARCH', $evdata);
1533
        if ($evt->advise_before()) {
1534
            $dir = utf8_encodeFN(str_replace(':','/',$evdata['ns']));
1535
            $quoted = preg_quote($evdata['query'],'/');
1536
            //apply globbing
1537
            $quoted = str_replace(array('\*', '\?'), array('.*', '.'), $quoted, $count);
1538
1539
            //if we use globbing file name must match entirely but may be preceded by arbitrary namespace
1540
            if ($count > 0) $quoted = '^([^:]*:)*'.$quoted.'$';
1541
1542
            $pattern = '/'.$quoted.'/i';
1543
            search($evdata['data'],
1544
                    $conf['mediadir'],
1545
                    'search_mediafiles',
1546
                    array('showmsg'=>false,'pattern'=>$pattern),
1547
                    $dir,
1548
                    1,
1549
                    $sort);
1550
        }
1551
        $evt->advise_after();
1552
        unset($evt);
1553
    }
1554
1555
    if (!$fullscreen) {
1556
        echo '<h1 id="media__ns">'.sprintf($lang['searchmedia_in'],hsc($ns).':*').'</h1>'.NL;
1557
        media_searchform($ns,$query);
1558
    }
1559
1560
    if(!count($evdata['data'])){
1561
        echo '<div class="nothing">'.$lang['nothingfound'].'</div>'.NL;
1562
    }else {
1563
        if ($fullscreen) {
1564
            echo '<ul class="' . _media_get_list_type() . '">';
1565
        }
1566
        foreach($evdata['data'] as $item){
1567
            if (!$fullscreen) {
1568
                // FIXME old call: media_printfile($item,$item['perm'],'',true);
1569
                // FIXME we actually want the namespace here -> needs fixing
1570
                $display = new \dokuwiki\Ui\Media\DisplayRow($item);
1571
                $display->show();
1572
            } else {
1573
                // FIXME old call: media_printfile_thumbs($item,$item['perm'],false,true);
1574
                // FIXME we actually want the namespace here -> needs fixing
1575
                $display = new \dokuwiki\Ui\Media\DisplayTile($item);
1576
                echo '<li>';
1577
                $display->show();
1578
                echo '</li>';
1579
            }
1580
        }
1581
        if ($fullscreen) echo '</ul>'.NL;
1582
    }
1583
}
1584
1585
/**
1586
 * Formats and prints one file in the list
1587
 *
1588
 * @param array     $item
1589
 * @param int       $auth              permission level
1590
 * @param string    $jump              item id
1591
 * @param bool      $display_namespace
1592
 */
1593
function media_printfile($item,$auth,$jump,$display_namespace=false){
1594
    global $lang;
1595
1596
    // Prepare zebra coloring
1597
    // I always wanted to use this variable name :-D
1598
    static $twibble = 1;
1599
    $twibble *= -1;
1600
    $zebra = ($twibble == -1) ? 'odd' : 'even';
1601
1602
    // Automatically jump to recent action
1603
    if($jump == $item['id']) {
1604
        $jump = ' id="scroll__here" ';
1605
    }else{
1606
        $jump = '';
1607
    }
1608
1609
    // Prepare fileicons
1610
    list($ext) = mimetype($item['file'],false);
1611
    $class = preg_replace('/[^_\-a-z0-9]+/i','_',$ext);
1612
    $class = 'select mediafile mf_'.$class;
1613
1614
    // Prepare filename
1615
    $file = utf8_decodeFN($item['file']);
1616
1617
    // Prepare info
1618
    $info = '';
1619
    if($item['isimg']){
1620
        $info .= (int) $item['meta']->getField('File.Width');
1621
        $info .= '&#215;';
1622
        $info .= (int) $item['meta']->getField('File.Height');
1623
        $info .= ' ';
1624
    }
1625
    $info .= '<i>'.dformat($item['mtime']).'</i>';
1626
    $info .= ' ';
1627
    $info .= filesize_h($item['size']);
1628
1629
    // output
1630
    echo '<div class="'.$zebra.'"'.$jump.' title="'.hsc($item['id']).'">'.NL;
1631
    if (!$display_namespace) {
1632
        echo '<a id="h_:'.$item['id'].'" class="'.$class.'">'.hsc($file).'</a> ';
0 ignored issues
show
Security Bug introduced by
It seems like $file defined by utf8_decodeFN($item['file']) on line 1615 can also be of type false; however, hsc() does only seem to accept string, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
1633
    } else {
1634
        echo '<a id="h_:'.$item['id'].'" class="'.$class.'">'.hsc($item['id']).'</a><br/>';
1635
    }
1636
    echo '<span class="info">('.$info.')</span>'.NL;
1637
1638
    // view button
1639
    $link = ml($item['id'],'',true);
1640
    echo ' <a href="'.$link.'" target="_blank"><img src="'.DOKU_BASE.'lib/images/magnifier.png" '.
1641
        'alt="'.$lang['mediaview'].'" title="'.$lang['mediaview'].'" class="btn" /></a>';
1642
1643
    // mediamanager button
1644
    $link = wl('',array('do'=>'media','image'=>$item['id'],'ns'=>getNS($item['id'])));
1645
    echo ' <a href="'.$link.'" target="_blank"><img src="'.DOKU_BASE.'lib/images/mediamanager.png" '.
1646
        'alt="'.$lang['btn_media'].'" title="'.$lang['btn_media'].'" class="btn" /></a>';
1647
1648
    // delete button
1649
    if($item['writable'] && $auth >= AUTH_DELETE){
1650
        $link = DOKU_BASE.'lib/exe/mediamanager.php?delete='.rawurlencode($item['id']).
1651
            '&amp;sectok='.getSecurityToken();
1652
        echo ' <a href="'.$link.'" class="btn_media_delete" title="'.$item['id'].'">'.
1653
            '<img src="'.DOKU_BASE.'lib/images/trash.png" alt="'.$lang['btn_delete'].'" '.
1654
            'title="'.$lang['btn_delete'].'" class="btn" /></a>';
1655
    }
1656
1657
    echo '<div class="example" id="ex_'.str_replace(':','_',$item['id']).'">';
1658
    echo $lang['mediausage'].' <code>{{:'.$item['id'].'}}</code>';
1659
    echo '</div>';
1660
    if($item['isimg']) media_printimgdetail($item);
1661
    echo '<div class="clearer"></div>'.NL;
1662
    echo '</div>'.NL;
1663
}
1664
1665
/**
1666
 * Display a media icon
1667
 *
1668
 * @param string $filename media id
1669
 * @param string $size     the size subfolder, if not specified 16x16 is used
1670
 * @return string html
1671
 */
1672
function media_printicon($filename, $size=''){
1673
    list($ext) = mimetype(mediaFN($filename),false);
1674
1675
    if (file_exists(DOKU_INC.'lib/images/fileicons/'.$size.'/'.$ext.'.png')) {
1676
        $icon = DOKU_BASE.'lib/images/fileicons/'.$size.'/'.$ext.'.png';
1677
    } else {
1678
        $icon = DOKU_BASE.'lib/images/fileicons/'.$size.'/file.png';
1679
    }
1680
1681
    return '<img src="'.$icon.'" alt="'.$filename.'" class="icon" />';
1682
}
1683
1684
/**
1685
 * Formats and prints one file in the list in the thumbnails view
1686
 *
1687
 * @author Kate Arzamastseva <[email protected]>
1688
 *
1689
 * @param array       $item
1690
 * @param int         $auth              permission level
1691
 * @param bool|string $jump              item id
1692
 * @param bool        $display_namespace
1693
 */
1694
function media_printfile_thumbs($item,$auth,$jump=false,$display_namespace=false){
0 ignored issues
show
Unused Code introduced by
The parameter $auth is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $jump is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1695
1696
    // Prepare filename
1697
    $file = utf8_decodeFN($item['file']);
1698
1699
    // output
1700
    echo '<li><dl title="'.hsc($item['id']).'">'.NL;
1701
1702
        echo '<dt>';
1703
    if($item['isimg']) {
1704
        media_printimgdetail($item, true);
1705
1706
    } else {
1707
        echo '<a id="d_:'.$item['id'].'" class="image" title="'.$item['id'].'" href="'.
1708
            media_managerURL(['image' => hsc($item['id']), 'ns' => getNS($item['id']),
1709
            'tab_details' => 'view']).'">';
1710
        echo media_printicon($item['id'], '32x32');
1711
        echo '</a>';
1712
    }
1713
    echo '</dt>'.NL;
1714
    if (!$display_namespace) {
1715
        $name = hsc($file);
0 ignored issues
show
Security Bug introduced by
It seems like $file defined by utf8_decodeFN($item['file']) on line 1697 can also be of type false; however, hsc() does only seem to accept string, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
1716
    } else {
1717
        $name = hsc($item['id']);
1718
    }
1719
    echo '<dd class="name"><a href="'.media_managerURL(['image' => hsc($item['id']), 'ns' => getNS($item['id']),
1720
        'tab_details' => 'view']).'" id="h_:'.$item['id'].'">'.$name.'</a></dd>'.NL;
1721
1722
    if($item['isimg']){
1723
        $size = '';
1724
        $size .= (int) $item['meta']->getField('File.Width');
1725
        $size .= '&#215;';
1726
        $size .= (int) $item['meta']->getField('File.Height');
1727
        echo '<dd class="size">'.$size.'</dd>'.NL;
1728
    } else {
1729
        echo '<dd class="size">&#160;</dd>'.NL;
1730
    }
1731
    $date = dformat($item['mtime']);
1732
    echo '<dd class="date">'.$date.'</dd>'.NL;
1733
    $filesize = filesize_h($item['size']);
1734
    echo '<dd class="filesize">'.$filesize.'</dd>'.NL;
1735
    echo '</dl></li>'.NL;
1736
}
1737
1738
/**
1739
 * Prints a thumbnail and metainfo
1740
 *
1741
 * @param array $item
1742
 * @param bool  $fullscreen
1743
 */
1744
function media_printimgdetail($item, $fullscreen=false){
1745
    // prepare thumbnail
1746
    $size = $fullscreen ? 90 : 120;
1747
1748
    $w = (int) $item['meta']->getField('File.Width');
1749
    $h = (int) $item['meta']->getField('File.Height');
1750
    if($w>$size || $h>$size){
1751
        if (!$fullscreen) {
1752
            $ratio = $item['meta']->getResizeRatio($size);
1753
        } else {
1754
            $ratio = $item['meta']->getResizeRatio($size,$size);
1755
        }
1756
        $w = floor($w * $ratio);
1757
        $h = floor($h * $ratio);
1758
    }
1759
    $src = ml($item['id'],array('w'=>$w,'h'=>$h,'t'=>$item['mtime']));
1760
    $p = array();
1761
    if (!$fullscreen) {
1762
        // In fullscreen mediamanager view, image resizing is done via CSS.
1763
        $p['width']  = $w;
1764
        $p['height'] = $h;
1765
    }
1766
    $p['alt']    = $item['id'];
1767
    $att = buildAttributes($p);
1768
1769
    // output
1770
    if ($fullscreen) {
1771
        echo '<a id="l_:'.$item['id'].'" class="image thumb" href="'.
1772
            media_managerURL(['image' => hsc($item['id']), 'ns' => getNS($item['id']), 'tab_details' => 'view']).'">';
1773
        echo '<img src="'.$src.'" '.$att.' />';
1774
        echo '</a>';
1775
    }
1776
1777
    if ($fullscreen) return;
1778
1779
    echo '<div class="detail">';
1780
    echo '<div class="thumb">';
1781
    echo '<a id="d_:'.$item['id'].'" class="select">';
1782
    echo '<img src="'.$src.'" '.$att.' />';
1783
    echo '</a>';
1784
    echo '</div>';
1785
1786
    // read EXIF/IPTC data
1787
    $t = $item['meta']->getField(array('IPTC.Headline','xmp.dc:title'));
1788
    $d = $item['meta']->getField(array('IPTC.Caption','EXIF.UserComment',
1789
                'EXIF.TIFFImageDescription',
1790
                'EXIF.TIFFUserComment'));
1791
    if(\dokuwiki\Utf8\PhpString::strlen($d) > 250) $d = \dokuwiki\Utf8\PhpString::substr($d,0,250).'...';
1792
    $k = $item['meta']->getField(array('IPTC.Keywords','IPTC.Category','xmp.dc:subject'));
1793
1794
    // print EXIF/IPTC data
1795
    if($t || $d || $k ){
1796
        echo '<p>';
1797
        if($t) echo '<strong>'.hsc($t).'</strong><br />';
1798
        if($d) echo hsc($d).'<br />';
1799
        if($t) echo '<em>'.hsc($k).'</em>';
1800
        echo '</p>';
1801
    }
1802
    echo '</div>';
1803
}
1804
1805
/**
1806
 * Build link based on the current, adding/rewriting parameters
1807
 *
1808
 * @author Kate Arzamastseva <[email protected]>
1809
 *
1810
 * @param array|bool $params
1811
 * @param string     $amp           separator
1812
 * @param bool       $abs           absolute url?
1813
 * @param bool       $params_array  return the parmeters array?
1814
 * @return string|array - link or link parameters
1815
 */
1816
function media_managerURL($params = false, $amp = '&amp;', $abs = false, $params_array = false) {
1817
    global $ID;
1818
    global $INPUT;
1819
1820
    $gets = array('do' => 'media');
1821
    $media_manager_params = array('tab_files', 'tab_details', 'image', 'ns', 'list', 'sort');
1822
    foreach ($media_manager_params as $x) {
1823
        if ($INPUT->has($x)) $gets[$x] = $INPUT->str($x);
1824
    }
1825
1826
    if ($params) {
1827
        $gets = $params + $gets;
1828
    }
1829
    unset($gets['id']);
1830
    if (isset($gets['delete'])) {
1831
        unset($gets['image']);
1832
        unset($gets['tab_details']);
1833
    }
1834
1835
    if ($params_array) return $gets;
1836
1837
    return wl($ID,$gets,$abs,$amp);
1838
}
1839
1840
/**
1841
 * Print the media upload form if permissions are correct
1842
 *
1843
 * @author Andreas Gohr <[email protected]>
1844
 * @author Kate Arzamastseva <[email protected]>
1845
 *
1846
 * @param string $ns
1847
 * @param int    $auth permission level
1848
 * @param bool  $fullscreen
1849
 */
1850
function media_uploadform($ns, $auth, $fullscreen = false) {
1851
    global $lang;
1852
    global $conf;
1853
    global $INPUT;
1854
1855
    if ($auth < AUTH_UPLOAD) {
1856
        echo '<div class="nothing">'.$lang['media_perm_upload'].'</div>'.NL;
1857
        return;
1858
    }
1859
    $auth_ow = (($conf['mediarevisions']) ? AUTH_UPLOAD : AUTH_DELETE);
1860
1861
    $update = false;
1862
    $id = '';
1863
    if ($auth >= $auth_ow && $fullscreen && $INPUT->str('mediado') == 'update') {
1864
        $update = true;
1865
        $id = cleanID($INPUT->str('image'));
1866
    }
1867
1868
    // The default HTML upload form
1869
    $form = new Form([
1870
        'id' => 'dw__upload',
1871
        'enctype' => 'multipart/form-data',
1872
        'action' => ($fullscreen)
1873
                    ? media_managerURL(['tab_files' => 'files', 'tab_details' => 'view'], '&')
1874
                    : DOKU_BASE.'lib/exe/mediamanager.php',
1875
    ]);
1876
    $form->addTagOpen('div')->addClass('no');
1877
    $form->setHiddenField('ns', hsc($ns));  // FIXME hsc required?
1878
    $form->addTagOpen('p');
1879
    $form->addTextInput('upload', $lang['txt_upload'])->id('upload__file')
1880
            ->attrs(['type' => 'file']);
1881
    $form->addTagClose('p');
1882
    $form->addTagOpen('p');
1883
    $form->addTextInput('mediaid', $lang['txt_filename'])->id('upload__name')
1884
            ->val(noNS($id));
1885
    $form->addButton('', $lang['btn_upload'])->attr('type', 'submit');
1886
    $form->addTagClose('p');
1887
    if ($auth >= $auth_ow){
1888
        $form->addTagOpen('p');
1889
        $attrs = array();
1890
        if ($update) $attrs['checked'] = 'checked';
1891
        $form->addCheckbox('ow', $lang['txt_overwrt'])->id('dw__ow')->val('1')
1892
            ->addClass('check')->attrs($attrs);
1893
        $form->addTagClose('p');
1894
    }
1895
    $form->addTagClose('div');
1896
1897
    if (!$fullscreen) {
1898
        echo '<div class="upload">'. $lang['mediaupload'] .'</div>'.DOKU_LF;
1899
    } else {
1900
        echo DOKU_LF;
1901
    }
1902
1903
    echo '<div id="mediamanager__uploader">'.DOKU_LF;
1904
    echo $form->toHTML('Upload');
1905
    echo '</div>'.DOKU_LF;
1906
1907
    echo '<p class="maxsize">';
1908
    printf($lang['maxuploadsize'], filesize_h(media_getuploadsize()));
1909
    echo ' <a class="allowedmime" href="#">'. $lang['allowedmime'] .'</a>';
1910
    echo ' <span>'. implode(', ', array_keys(getMimeTypes())) .'</span>';
1911
    echo '</p>'.DOKU_LF;
1912
}
1913
1914
/**
1915
 * Returns the size uploaded files may have
1916
 *
1917
 * This uses a conservative approach using the lowest number found
1918
 * in any of the limiting ini settings
1919
 *
1920
 * @returns int size in bytes
1921
 */
1922
function media_getuploadsize(){
1923
    $okay = 0;
1924
1925
    $post = (int) php_to_byte(@ini_get('post_max_size'));
1926
    $suho = (int) php_to_byte(@ini_get('suhosin.post.max_value_length'));
1927
    $upld = (int) php_to_byte(@ini_get('upload_max_filesize'));
1928
1929
    if($post && ($post < $okay || $okay == 0)) $okay = $post;
1930
    if($suho && ($suho < $okay || $okay == 0)) $okay = $suho;
1931
    if($upld && ($upld < $okay || $okay == 0)) $okay = $upld;
1932
1933
    return $okay;
1934
}
1935
1936
/**
1937
 * Print the search field form
1938
 *
1939
 * @author Tobias Sarnowski <[email protected]>
1940
 * @author Kate Arzamastseva <[email protected]>
1941
 *
1942
 * @param string $ns
1943
 * @param string $query
1944
 * @param bool $fullscreen
1945
 */
1946
function media_searchform($ns, $query = '', $fullscreen = false) {
1947
    global $lang;
1948
1949
    // The default HTML search form
1950
    $form = new Form([
1951
        'id'     => 'dw__mediasearch',
1952
        'action' => ($fullscreen)
1953
                    ? media_managerURL([], '&')
1954
                    : DOKU_BASE.'lib/exe/mediamanager.php',
1955
    ]);
1956
    $form->addTagOpen('div')->addClass('no');
1957
    $form->setHiddenField('ns', $ns);
1958
    $form->setHiddenField($fullscreen ? 'mediado' : 'do', 'searchlist');
1959
1960
    $form->addTagOpen('p');
1961
    $form->addTextInput('q', $lang['searchmedia'])
1962
            ->attr('title', sprintf($lang['searchmedia_in'], hsc($ns) .':*'))
1963
            ->val($query);
1964
    $form->addHTML(' ');
1965
    $form->addButton('', $lang['btn_search'])->attr('type', 'submit');
1966
    $form->addTagClose('p');
1967
    $form->addTagClose('div');
1968
    print $form->toHTML('SearchMedia');
1969
}
1970
1971
/**
1972
 * Build a tree outline of available media namespaces
1973
 *
1974
 * @author Andreas Gohr <[email protected]>
1975
 *
1976
 * @param string $ns
1977
 */
1978
function media_nstree($ns){
1979
    global $conf;
1980
    global $lang;
1981
1982
    // currently selected namespace
1983
    $ns  = cleanID($ns);
1984
    if(empty($ns)){
1985
        global $ID;
1986
        $ns = (string)getNS($ID);
1987
    }
1988
1989
    $ns_dir  = utf8_encodeFN(str_replace(':','/',$ns));
1990
1991
    $data = array();
1992
    search($data,$conf['mediadir'],'search_index',array('ns' => $ns_dir, 'nofiles' => true));
1993
1994
    // wrap a list with the root level around the other namespaces
1995
    array_unshift($data, array('level' => 0, 'id' => '', 'open' =>'true',
1996
                               'label' => '['.$lang['mediaroot'].']'));
1997
1998
    // insert the current ns into the hierarchy if it isn't already part of it
1999
    $ns_parts = explode(':', $ns);
2000
    $tmp_ns = '';
2001
    $pos = 0;
2002
    foreach ($ns_parts as $level => $part) {
2003
        if ($tmp_ns) $tmp_ns .= ':'.$part;
2004
        else $tmp_ns = $part;
2005
2006
        // find the namespace parts or insert them
2007
        while ($data[$pos]['id'] != $tmp_ns) {
2008
            if (
2009
                $pos >= count($data) ||
2010
                ($data[$pos]['level'] <= $level+1 && Sort::strcmp($data[$pos]['id'], $tmp_ns) > 0)
2011
            ) {
2012
                array_splice($data, $pos, 0, array(array('level' => $level+1, 'id' => $tmp_ns, 'open' => 'true')));
2013
                break;
2014
            }
2015
            ++$pos;
2016
        }
2017
    }
2018
2019
    echo html_buildlist($data,'idx','media_nstree_item','media_nstree_li');
2020
}
2021
2022
/**
2023
 * Userfunction for html_buildlist
2024
 *
2025
 * Prints a media namespace tree item
2026
 *
2027
 * @author Andreas Gohr <[email protected]>
2028
 *
2029
 * @param array $item
2030
 * @return string html
2031
 */
2032
function media_nstree_item($item){
2033
    global $INPUT;
2034
    $pos   = strrpos($item['id'], ':');
2035
    $label = substr($item['id'], $pos > 0 ? $pos + 1 : 0);
2036
    if(empty($item['label'])) $item['label'] = $label;
2037
2038
    $ret  = '';
2039
    if (!($INPUT->str('do') == 'media'))
2040
    $ret .= '<a href="'.DOKU_BASE.'lib/exe/mediamanager.php?ns='.idfilter($item['id']).'" class="idx_dir">';
2041
    else $ret .= '<a href="'.media_managerURL(['ns' => idfilter($item['id'], false), 'tab_files' => 'files'])
2042
        .'" class="idx_dir">';
2043
    $ret .= $item['label'];
2044
    $ret .= '</a>';
2045
    return $ret;
2046
}
2047
2048
/**
2049
 * Userfunction for html_buildlist
2050
 *
2051
 * Prints a media namespace tree item opener
2052
 *
2053
 * @author Andreas Gohr <[email protected]>
2054
 *
2055
 * @param array $item
2056
 * @return string html
2057
 */
2058
function media_nstree_li($item){
2059
    $class='media level'.$item['level'];
2060
    if($item['open']){
2061
        $class .= ' open';
2062
        $img   = DOKU_BASE.'lib/images/minus.gif';
2063
        $alt   = '−';
2064
    }else{
2065
        $class .= ' closed';
2066
        $img   = DOKU_BASE.'lib/images/plus.gif';
2067
        $alt   = '+';
2068
    }
2069
    // TODO: only deliver an image if it actually has a subtree...
2070
    return '<li class="'.$class.'">'.
2071
        '<img src="'.$img.'" alt="'.$alt.'" />';
2072
}
2073
2074
/**
2075
 * Resizes the given image to the given size
2076
 *
2077
 * @author  Andreas Gohr <[email protected]>
2078
 *
2079
 * @param string $file filename, path to file
2080
 * @param string $ext  extension
2081
 * @param int    $w    desired width
2082
 * @param int    $h    desired height
2083
 * @return string path to resized or original size if failed
2084
 */
2085
function media_resize_image($file, $ext, $w, $h=0){
2086
    global $conf;
2087
    if(!$h) $h = $w;
2088
    // we wont scale up to infinity
2089
    if($w > 2000 || $h > 2000) return $file;
2090
2091
    //cache
2092
    $local = getCacheName($file,'.media.'.$w.'x'.$h.'.'.$ext);
2093
    $mtime = (int) @filemtime($local); // 0 if not exists
2094
2095
    $options = [
2096
        'quality' => $conf['jpg_quality'],
2097
        'imconvert' => $conf['im_convert'],
2098
    ];
2099
2100
    if( $mtime <= (int) @filemtime($file) ) {
2101
        try {
2102
            \splitbrain\slika\Slika::run($file, $options)
2103
                                   ->autorotate()
2104
                                   ->resize($w, $h)
2105
                                   ->save($local, $ext);
2106
            if($conf['fperm']) @chmod($local, $conf['fperm']);
2107
        } catch (\splitbrain\slika\Exception $e) {
2108
            dbglog($e->getMessage());
0 ignored issues
show
Deprecated Code introduced by
The function dbglog() has been deprecated with message: 2020-08-13

This function has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed from the class and what other function to use instead.

Loading history...
2109
            return $file;
2110
        }
2111
    }
2112
2113
    return $local;
2114
}
2115
2116
/**
2117
 * Center crops the given image to the wanted size
2118
 *
2119
 * @author  Andreas Gohr <[email protected]>
2120
 *
2121
 * @param string $file filename, path to file
2122
 * @param string $ext  extension
2123
 * @param int    $w    desired width
2124
 * @param int    $h    desired height
2125
 * @return string path to resized or original size if failed
2126
 */
2127
function media_crop_image($file, $ext, $w, $h=0){
2128
    global $conf;
2129
    if(!$h) $h = $w;
2130
    // we wont scale up to infinity
2131
    if($w > 2000 || $h > 2000) return $file;
2132
2133
    //cache
2134
    $local = getCacheName($file,'.media.'.$w.'x'.$h.'.crop.'.$ext);
2135
    $mtime = (int) @filemtime($local); // 0 if not exists
2136
2137
    $options = [
2138
        'quality' => $conf['jpg_quality'],
2139
        'imconvert' => $conf['im_convert'],
2140
    ];
2141
2142
    if( $mtime <= (int) @filemtime($file) ) {
2143
        try {
2144
            \splitbrain\slika\Slika::run($file, $options)
2145
                                   ->autorotate()
2146
                                    ->crop($w, $h)
2147
                                    ->save($local, $ext);
2148
            if($conf['fperm']) @chmod($local, $conf['fperm']);
2149
        } catch (\splitbrain\slika\Exception $e) {
2150
            dbglog($e->getMessage());
0 ignored issues
show
Deprecated Code introduced by
The function dbglog() has been deprecated with message: 2020-08-13

This function has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed from the class and what other function to use instead.

Loading history...
2151
            return $file;
2152
        }
2153
    }
2154
2155
    return $local;
2156
}
2157
2158
/**
2159
 * Calculate a token to be used to verify fetch requests for resized or
2160
 * cropped images have been internally generated - and prevent external
2161
 * DDOS attacks via fetch
2162
 *
2163
 * @author Christopher Smith <[email protected]>
2164
 *
2165
 * @param string  $id    id of the image
2166
 * @param int     $w     resize/crop width
2167
 * @param int     $h     resize/crop height
2168
 * @return string token or empty string if no token required
2169
 */
2170
function media_get_token($id,$w,$h){
2171
    // token is only required for modified images
2172
    if ($w || $h || media_isexternal($id)) {
2173
        $token = $id;
2174
        if ($w) $token .= '.'.$w;
2175
        if ($h) $token .= '.'.$h;
2176
2177
        return substr(\dokuwiki\PassHash::hmac('md5', $token, auth_cookiesalt()),0,6);
0 ignored issues
show
Bug introduced by
It seems like auth_cookiesalt() can also be of type boolean; however, dokuwiki\PassHash::hmac() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
2178
    }
2179
2180
    return '';
2181
}
2182
2183
/**
2184
 * Download a remote file and return local filename
2185
 *
2186
 * returns false if download fails. Uses cached file if available and
2187
 * wanted
2188
 *
2189
 * @author  Andreas Gohr <[email protected]>
2190
 * @author  Pavel Vitis <[email protected]>
2191
 *
2192
 * @param string $url
2193
 * @param string $ext   extension
2194
 * @param int    $cache cachetime in seconds
2195
 * @return false|string path to cached file
2196
 */
2197
function media_get_from_URL($url,$ext,$cache){
2198
    global $conf;
2199
2200
    // if no cache or fetchsize just redirect
2201
    if ($cache==0)           return false;
2202
    if (!$conf['fetchsize']) return false;
2203
2204
    $local = getCacheName(strtolower($url),".media.$ext");
2205
    $mtime = @filemtime($local); // 0 if not exists
2206
2207
    //decide if download needed:
2208
    if(($mtime == 0) || // cache does not exist
2209
        ($cache != -1 && $mtime < time() - $cache) // 'recache' and cache has expired
2210
    ) {
2211
        if(media_image_download($url, $local)) {
2212
            return $local;
2213
        } else {
2214
            return false;
2215
        }
2216
    }
2217
2218
    //if cache exists use it else
2219
    if($mtime) return $local;
2220
2221
    //else return false
2222
    return false;
2223
}
2224
2225
/**
2226
 * Download image files
2227
 *
2228
 * @author Andreas Gohr <[email protected]>
2229
 *
2230
 * @param string $url
2231
 * @param string $file path to file in which to put the downloaded content
2232
 * @return bool
2233
 */
2234
function media_image_download($url,$file){
2235
    global $conf;
2236
    $http = new DokuHTTPClient();
2237
    $http->keep_alive = false; // we do single ops here, no need for keep-alive
2238
2239
    $http->max_bodysize = $conf['fetchsize'];
2240
    $http->timeout = 25; //max. 25 sec
2241
    $http->header_regexp = '!\r\nContent-Type: image/(jpe?g|gif|png)!i';
2242
2243
    $data = $http->get($url);
2244
    if(!$data) return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression $data of type false|string is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
2245
2246
    $fileexists = file_exists($file);
2247
    $fp = @fopen($file,"w");
2248
    if(!$fp) return false;
2249
    fwrite($fp,$data);
2250
    fclose($fp);
2251
    if(!$fileexists and $conf['fperm']) chmod($file, $conf['fperm']);
2252
2253
    // check if it is really an image
2254
    $info = @getimagesize($file);
2255
    if(!$info){
2256
        @unlink($file);
2257
        return false;
2258
    }
2259
2260
    return true;
2261
}
2262
2263
/**
2264
 * resize images using external ImageMagick convert program
2265
 *
2266
 * @author Pavel Vitis <[email protected]>
2267
 * @author Andreas Gohr <[email protected]>
2268
 *
2269
 * @param string $ext     extension
2270
 * @param string $from    filename path to file
2271
 * @param int    $from_w  original width
2272
 * @param int    $from_h  original height
2273
 * @param string $to      path to resized file
2274
 * @param int    $to_w    desired width
2275
 * @param int    $to_h    desired height
2276
 * @return bool
2277
 */
2278
function media_resize_imageIM($ext,$from,$from_w,$from_h,$to,$to_w,$to_h){
0 ignored issues
show
Unused Code introduced by
The parameter $from_w is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $from_h is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
2279
    global $conf;
2280
2281
    // check if convert is configured
2282
    if(!$conf['im_convert']) return false;
2283
2284
    // prepare command
2285
    $cmd  = $conf['im_convert'];
2286
    $cmd .= ' -resize '.$to_w.'x'.$to_h.'!';
2287
    if ($ext == 'jpg' || $ext == 'jpeg') {
2288
        $cmd .= ' -quality '.$conf['jpg_quality'];
2289
    }
2290
    $cmd .= " $from $to";
2291
2292
    @exec($cmd,$out,$retval);
2293
    if ($retval == 0) return true;
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $retval of type integer|null to 0; this is ambiguous as not only 0 == 0 is true, but null == 0 is true, too. Consider using a strict comparison ===.
Loading history...
2294
    return false;
2295
}
2296
2297
/**
2298
 * crop images using external ImageMagick convert program
2299
 *
2300
 * @author Andreas Gohr <[email protected]>
2301
 *
2302
 * @param string $ext     extension
2303
 * @param string $from    filename path to file
2304
 * @param int    $from_w  original width
2305
 * @param int    $from_h  original height
2306
 * @param string $to      path to resized file
2307
 * @param int    $to_w    desired width
2308
 * @param int    $to_h    desired height
2309
 * @param int    $ofs_x   offset of crop centre
2310
 * @param int    $ofs_y   offset of crop centre
2311
 * @return bool
2312
 * @deprecated 2020-09-01
2313
 */
2314
function media_crop_imageIM($ext,$from,$from_w,$from_h,$to,$to_w,$to_h,$ofs_x,$ofs_y){
0 ignored issues
show
Unused Code introduced by
The parameter $from_w is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $from_h is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
2315
    global $conf;
2316
    dbg_deprecated('splitbrain\\Slika');
2317
2318
    // check if convert is configured
2319
    if(!$conf['im_convert']) return false;
2320
2321
    // prepare command
2322
    $cmd  = $conf['im_convert'];
2323
    $cmd .= ' -crop '.$to_w.'x'.$to_h.'+'.$ofs_x.'+'.$ofs_y;
2324
    if ($ext == 'jpg' || $ext == 'jpeg') {
2325
        $cmd .= ' -quality '.$conf['jpg_quality'];
2326
    }
2327
    $cmd .= " $from $to";
2328
2329
    @exec($cmd,$out,$retval);
2330
    if ($retval == 0) return true;
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $retval of type integer|null to 0; this is ambiguous as not only 0 == 0 is true, but null == 0 is true, too. Consider using a strict comparison ===.
Loading history...
2331
    return false;
2332
}
2333
2334
/**
2335
 * resize or crop images using PHP's libGD support
2336
 *
2337
 * @author Andreas Gohr <[email protected]>
2338
 * @author Sebastian Wienecke <[email protected]>
2339
 *
2340
 * @param string $ext     extension
2341
 * @param string $from    filename path to file
2342
 * @param int    $from_w  original width
2343
 * @param int    $from_h  original height
2344
 * @param string $to      path to resized file
2345
 * @param int    $to_w    desired width
2346
 * @param int    $to_h    desired height
2347
 * @param int    $ofs_x   offset of crop centre
2348
 * @param int    $ofs_y   offset of crop centre
2349
 * @return bool
2350
 * @deprecated 2020-09-01
2351
 */
2352
function media_resize_imageGD($ext,$from,$from_w,$from_h,$to,$to_w,$to_h,$ofs_x=0,$ofs_y=0){
2353
    global $conf;
2354
    dbg_deprecated('splitbrain\\Slika');
2355
2356
    if($conf['gdlib'] < 1) return false; //no GDlib available or wanted
2357
2358
    // check available memory
2359
    if(!is_mem_available(($from_w * $from_h * 4) + ($to_w * $to_h * 4))){
2360
        return false;
2361
    }
2362
2363
    // create an image of the given filetype
2364
    $image = false;
2365
    if ($ext == 'jpg' || $ext == 'jpeg'){
2366
        if(!function_exists("imagecreatefromjpeg")) return false;
2367
        $image = @imagecreatefromjpeg($from);
2368
    }elseif($ext == 'png') {
2369
        if(!function_exists("imagecreatefrompng")) return false;
2370
        $image = @imagecreatefrompng($from);
2371
2372
    }elseif($ext == 'gif') {
2373
        if(!function_exists("imagecreatefromgif")) return false;
2374
        $image = @imagecreatefromgif($from);
2375
    }
2376
    if(!$image) return false;
2377
2378
    $newimg = false;
2379
    if(($conf['gdlib']>1) && function_exists("imagecreatetruecolor") && $ext != 'gif'){
2380
        $newimg = @imagecreatetruecolor ($to_w, $to_h);
2381
    }
2382
    if(!$newimg) $newimg = @imagecreate($to_w, $to_h);
2383
    if(!$newimg){
2384
        imagedestroy($image);
2385
        return false;
2386
    }
2387
2388
    //keep png alpha channel if possible
2389
    if($ext == 'png' && $conf['gdlib']>1 && function_exists('imagesavealpha')){
2390
        imagealphablending($newimg, false);
2391
        imagesavealpha($newimg,true);
2392
    }
2393
2394
    //keep gif transparent color if possible
2395
    if($ext == 'gif' && function_exists('imagefill') && function_exists('imagecolorallocate')) {
2396
        if(function_exists('imagecolorsforindex') && function_exists('imagecolortransparent')) {
2397
            $transcolorindex = @imagecolortransparent($image);
2398
            if($transcolorindex >= 0 ) { //transparent color exists
2399
                $transcolor = @imagecolorsforindex($image, $transcolorindex);
2400
                $transcolorindex = @imagecolorallocate(
2401
                    $newimg,
2402
                    $transcolor['red'],
2403
                    $transcolor['green'],
2404
                    $transcolor['blue']
2405
                );
2406
                @imagefill($newimg, 0, 0, $transcolorindex);
2407
                @imagecolortransparent($newimg, $transcolorindex);
2408
            }else{ //filling with white
2409
                $whitecolorindex = @imagecolorallocate($newimg, 255, 255, 255);
2410
                @imagefill($newimg, 0, 0, $whitecolorindex);
2411
            }
2412
        }else{ //filling with white
2413
            $whitecolorindex = @imagecolorallocate($newimg, 255, 255, 255);
2414
            @imagefill($newimg, 0, 0, $whitecolorindex);
2415
        }
2416
    }
2417
2418
    //try resampling first
2419
    if(function_exists("imagecopyresampled")){
2420
        if(!@imagecopyresampled($newimg, $image, 0, 0, $ofs_x, $ofs_y, $to_w, $to_h, $from_w, $from_h)) {
2421
            imagecopyresized($newimg, $image, 0, 0, $ofs_x, $ofs_y, $to_w, $to_h, $from_w, $from_h);
2422
        }
2423
    }else{
2424
        imagecopyresized($newimg, $image, 0, 0, $ofs_x, $ofs_y, $to_w, $to_h, $from_w, $from_h);
2425
    }
2426
2427
    $okay = false;
2428
    if ($ext == 'jpg' || $ext == 'jpeg'){
2429
        if(!function_exists('imagejpeg')){
2430
            $okay = false;
2431
        }else{
2432
            $okay = imagejpeg($newimg, $to, $conf['jpg_quality']);
2433
        }
2434
    }elseif($ext == 'png') {
2435
        if(!function_exists('imagepng')){
2436
            $okay = false;
2437
        }else{
2438
            $okay =  imagepng($newimg, $to);
2439
        }
2440
    }elseif($ext == 'gif') {
2441
        if(!function_exists('imagegif')){
2442
            $okay = false;
2443
        }else{
2444
            $okay = imagegif($newimg, $to);
2445
        }
2446
    }
2447
2448
    // destroy GD image ressources
2449
    if($image) imagedestroy($image);
2450
    if($newimg) imagedestroy($newimg);
2451
2452
    return $okay;
2453
}
2454
2455
/**
2456
 * Return other media files with the same base name
2457
 * but different extensions.
2458
 *
2459
 * @param string   $src     - ID of media file
2460
 * @param string[] $exts    - alternative extensions to find other files for
2461
 * @return array            - array(mime type => file ID)
2462
 *
2463
 * @author Anika Henke <[email protected]>
2464
 */
2465
function media_alternativefiles($src, $exts){
2466
2467
    $files = array();
2468
    list($srcExt, /* $srcMime */) = mimetype($src);
2469
    $filebase = substr($src, 0, -1 * (strlen($srcExt)+1));
2470
2471
    foreach($exts as $ext) {
2472
        $fileid = $filebase.'.'.$ext;
2473
        $file = mediaFN($fileid);
2474
        if(file_exists($file)) {
2475
            list(/* $fileExt */, $fileMime) = mimetype($file);
2476
            $files[$fileMime] = $fileid;
2477
        }
2478
    }
2479
    return $files;
2480
}
2481
2482
/**
2483
 * Check if video/audio is supported to be embedded.
2484
 *
2485
 * @param string $mime      - mimetype of media file
2486
 * @param string $type      - type of media files to check ('video', 'audio', or null for all)
2487
 * @return boolean
2488
 *
2489
 * @author Anika Henke <[email protected]>
2490
 */
2491
function media_supportedav($mime, $type=NULL){
2492
    $supportedAudio = array(
2493
        'ogg' => 'audio/ogg',
2494
        'mp3' => 'audio/mpeg',
2495
        'wav' => 'audio/wav',
2496
    );
2497
    $supportedVideo = array(
2498
        'webm' => 'video/webm',
2499
        'ogv' => 'video/ogg',
2500
        'mp4' => 'video/mp4',
2501
    );
2502
    if ($type == 'audio') {
2503
        $supportedAv = $supportedAudio;
2504
    } elseif ($type == 'video') {
2505
        $supportedAv = $supportedVideo;
2506
    } else {
2507
        $supportedAv = array_merge($supportedAudio, $supportedVideo);
2508
    }
2509
    return in_array($mime, $supportedAv);
2510
}
2511
2512
/**
2513
 * Return track media files with the same base name
2514
 * but extensions that indicate kind and lang.
2515
 * ie for foo.webm search foo.sub.lang.vtt, foo.cap.lang.vtt...
2516
 *
2517
 * @param string   $src     - ID of media file
2518
 * @return array            - array(mediaID => array( kind, srclang ))
2519
 *
2520
 * @author Schplurtz le Déboulonné <[email protected]>
2521
 */
2522
function media_trackfiles($src){
2523
    $kinds=array(
2524
        'sub' => 'subtitles',
2525
        'cap' => 'captions',
2526
        'des' => 'descriptions',
2527
        'cha' => 'chapters',
2528
        'met' => 'metadata'
2529
    );
2530
2531
    $files = array();
2532
    $re='/\\.(sub|cap|des|cha|met)\\.([^.]+)\\.vtt$/';
2533
    $baseid=pathinfo($src, PATHINFO_FILENAME);
2534
    $pattern=mediaFN($baseid).'.*.*.vtt';
2535
    $list=glob($pattern);
2536
    foreach($list as $track) {
2537
        if(preg_match($re, $track, $matches)){
2538
            $files[$baseid.'.'.$matches[1].'.'.$matches[2].'.vtt']=array(
2539
                $kinds[$matches[1]],
2540
                $matches[2],
2541
            );
2542
        }
2543
    }
2544
    return $files;
2545
}
2546
2547
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
2548