Completed
Push — slika ( 514bb6 )
by Andreas
06:08 queued 03:24
created

media.php ➔ media_resize_image()   B

Complexity

Conditions 7
Paths 14

Size

Total Lines 30

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
nc 14
nop 4
dl 0
loc 30
rs 8.5066
c 0
b 0
f 0
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
14
/**
15
 * Lists pages which currently use a media file selected for deletion
16
 *
17
 * References uses the same visual as search results and share
18
 * their CSS tags except pagenames won't be links.
19
 *
20
 * @author Matthias Grimm <[email protected]>
21
 *
22
 * @param array $data
23
 * @param string $id
24
 */
25
function media_filesinuse($data,$id){
26
    global $lang;
27
    echo '<h1>'.$lang['reference'].' <code>'.hsc(noNS($id)).'</code></h1>';
28
    echo '<p>'.hsc($lang['ref_inuse']).'</p>';
29
30
    $hidden=0; //count of hits without read permission
31
    foreach($data as $row){
32
        if(auth_quickaclcheck($row) >= AUTH_READ && isVisiblePage($row)){
33
            echo '<div class="search_result">';
34
            echo '<span class="mediaref_ref">'.hsc($row).'</span>';
35
            echo '</div>';
36
        }else
37
            $hidden++;
38
    }
39
    if ($hidden){
40
        print '<div class="mediaref_hidden">'.$lang['ref_hidden'].'</div>';
41
    }
42
}
43
44
/**
45
 * Handles the saving of image meta data
46
 *
47
 * @author Andreas Gohr <[email protected]>
48
 * @author Kate Arzamastseva <[email protected]>
49
 *
50
 * @param string $id media id
51
 * @param int $auth permission level
52
 * @param array $data
53
 * @return false|string
54
 */
55
function media_metasave($id,$auth,$data){
56
    if($auth < AUTH_UPLOAD) return false;
57
    if(!checkSecurityToken()) return false;
58
    global $lang;
59
    global $conf;
60
    $src = mediaFN($id);
61
62
    $meta = new JpegMeta($src);
63
    $meta->_parseAll();
64
65
    foreach($data as $key => $val){
66
        $val=trim($val);
67
        if(empty($val)){
68
            $meta->deleteField($key);
69
        }else{
70
            $meta->setField($key,$val);
71
        }
72
    }
73
74
    $old = @filemtime($src);
75
    if(!file_exists(mediaFN($id, $old)) && file_exists($src)) {
76
        // add old revision to the attic
77
        media_saveOldRevision($id);
78
    }
79
    $filesize_old = filesize($src);
80
    if($meta->save()){
81
        if($conf['fperm']) chmod($src, $conf['fperm']);
82
        @clearstatcache(true, $src);
83
        $new = @filemtime($src);
84
        $filesize_new = filesize($src);
85
        $sizechange = $filesize_new - $filesize_old;
86
87
        // add a log entry to the media changelog
88
        addMediaLogEntry($new, $id, DOKU_CHANGE_TYPE_EDIT, $lang['media_meta_edited'], '', null, $sizechange);
89
90
        msg($lang['metasaveok'],1);
91
        return $id;
92
    }else{
93
        msg($lang['metasaveerr'],-1);
94
        return false;
95
    }
96
}
97
98
/**
99
 * check if a media is external source
100
 *
101
 * @author Gerrit Uitslag <[email protected]>
102
 *
103
 * @param string $id the media ID or URL
104
 * @return bool
105
 */
106
function media_isexternal($id){
107
    if (preg_match('#^(?:https?|ftp)://#i', $id)) return true;
108
    return false;
109
}
110
111
/**
112
 * Check if a media item is public (eg, external URL or readable by @ALL)
113
 *
114
 * @author Andreas Gohr <[email protected]>
115
 *
116
 * @param string $id  the media ID or URL
117
 * @return bool
118
 */
119
function media_ispublic($id){
120
    if(media_isexternal($id)) return true;
121
    $id = cleanID($id);
122
    if(auth_aclcheck(getNS($id).':*', '', array()) >= AUTH_READ) return true;
123
    return false;
124
}
125
126
/**
127
 * Display the form to edit image meta data
128
 *
129
 * @author Andreas Gohr <[email protected]>
130
 * @author Kate Arzamastseva <[email protected]>
131
 *
132
 * @param string $id media id
133
 * @param int $auth permission level
134
 * @return bool
135
 */
136
function media_metaform($id,$auth){
137
    global $lang;
138
139
    if($auth < AUTH_UPLOAD) {
140
        echo '<div class="nothing">'.$lang['media_perm_upload'].'</div>'.NL;
141
        return false;
142
    }
143
144
    // load the field descriptions
145
    static $fields = null;
146
    if(is_null($fields)){
147
        $config_files = getConfigFiles('mediameta');
148
        foreach ($config_files as $config_file) {
149
            if(file_exists($config_file)) include($config_file);
150
        }
151
    }
152
153
    $src = mediaFN($id);
154
155
    // output
156
    $form = new Doku_Form(array('action' => media_managerURL(array('tab_details' => 'view'), '&'),
0 ignored issues
show
Deprecated Code introduced by
The class Doku_Form has been deprecated with message: 2019-07-14

This class, trait or interface 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 type will be removed from the class and what other constant to use instead.

Loading history...
157
                                'class' => 'meta'));
158
    $form->addHidden('img', $id);
159
    $form->addHidden('mediado', 'save');
160
    foreach($fields as $key => $field){
0 ignored issues
show
Bug introduced by
The expression $fields of type null is not traversable.
Loading history...
161
        // get current value
162
        if (empty($field[0])) continue;
163
        $tags = array($field[0]);
164
        if(is_array($field[3])) $tags = array_merge($tags,$field[3]);
165
        $value = tpl_img_getTag($tags,'',$src);
166
        $value = cleanText($value);
167
168
        // prepare attributes
169
        $p = array();
170
        $p['class'] = 'edit';
171
        $p['id']    = 'meta__'.$key;
172
        $p['name']  = 'meta['.$field[0].']';
173
        $p_attrs    = array('class' => 'edit');
174
175
        $form->addElement('<div class="row">');
176
        if($field[2] == 'text'){
177
            $form->addElement(
178
                form_makeField(
179
                    'text',
180
                    $p['name'],
181
                    $value,
182
                    ($lang[$field[1]]) ? $lang[$field[1]] : $field[1] . ':',
183
                    $p['id'],
184
                    $p['class'],
185
                    $p_attrs
186
                )
187
            );
188
        }else{
189
            $att = buildAttributes($p);
190
            $form->addElement('<label for="meta__'.$key.'">'.$lang[$field[1]].'</label>');
191
            $form->addElement("<textarea $att rows=\"6\" cols=\"50\">".formText($value).'</textarea>');
192
        }
193
        $form->addElement('</div>'.NL);
194
    }
195
    $form->addElement('<div class="buttons">');
196
    $form->addElement(
197
        form_makeButton(
198
            'submit',
199
            '',
200
            $lang['btn_save'],
201
            array('accesskey' => 's', 'name' => 'mediado[save]')
202
        )
203
    );
204
    $form->addElement('</div>'.NL);
205
    $form->printForm();
206
207
    return true;
208
}
209
210
/**
211
 * Convenience function to check if a media file is still in use
212
 *
213
 * @author Michael Klier <[email protected]>
214
 *
215
 * @param string $id media id
216
 * @return array|bool
217
 */
218
function media_inuse($id) {
219
    global $conf;
220
221
    if($conf['refcheck']){
222
        $mediareferences = ft_mediause($id,true);
223
        if(!count($mediareferences)) {
224
            return false;
225
        } else {
226
            return $mediareferences;
227
        }
228
    } else {
229
        return false;
230
    }
231
}
232
233
define('DOKU_MEDIA_DELETED', 1);
234
define('DOKU_MEDIA_NOT_AUTH', 2);
235
define('DOKU_MEDIA_INUSE', 4);
236
define('DOKU_MEDIA_EMPTY_NS', 8);
237
238
/**
239
 * Handles media file deletions
240
 *
241
 * If configured, checks for media references before deletion
242
 *
243
 * @author             Andreas Gohr <[email protected]>
244
 *
245
 * @param string $id media id
246
 * @param int $auth no longer used
247
 * @return int One of: 0,
248
 *                     DOKU_MEDIA_DELETED,
249
 *                     DOKU_MEDIA_DELETED | DOKU_MEDIA_EMPTY_NS,
250
 *                     DOKU_MEDIA_NOT_AUTH,
251
 *                     DOKU_MEDIA_INUSE
252
 */
253
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...
254
    global $lang;
255
    $auth = auth_quickaclcheck(ltrim(getNS($id).':*', ':'));
256
    if($auth < AUTH_DELETE) return DOKU_MEDIA_NOT_AUTH;
257
    if(media_inuse($id)) return DOKU_MEDIA_INUSE;
258
259
    $file = mediaFN($id);
260
261
    // trigger an event - MEDIA_DELETE_FILE
262
    $data = array();
263
    $data['id']   = $id;
264
    $data['name'] = \dokuwiki\Utf8\PhpString::basename($file);
265
    $data['path'] = $file;
266
    $data['size'] = (file_exists($file)) ? filesize($file) : 0;
267
268
    $data['unl'] = false;
269
    $data['del'] = false;
270
    $evt = new Event('MEDIA_DELETE_FILE',$data);
271
    if ($evt->advise_before()) {
272
        $old = @filemtime($file);
273
        if(!file_exists(mediaFN($id, $old)) && file_exists($file)) {
274
            // add old revision to the attic
275
            media_saveOldRevision($id);
276
        }
277
278
        $data['unl'] = @unlink($file);
279
        if($data['unl']) {
280
            $sizechange = 0 - $data['size'];
281
            addMediaLogEntry(time(), $id, DOKU_CHANGE_TYPE_DELETE, $lang['deleted'], '', null, $sizechange);
282
283
            $data['del'] = io_sweepNS($id, 'mediadir');
284
        }
285
    }
286
    $evt->advise_after();
287
    unset($evt);
288
289
    if($data['unl'] && $data['del']){
290
        return DOKU_MEDIA_DELETED | DOKU_MEDIA_EMPTY_NS;
291
    }
292
293
    return $data['unl'] ? DOKU_MEDIA_DELETED : 0;
294
}
295
296
/**
297
 * Handle file uploads via XMLHttpRequest
298
 *
299
 * @param string $ns   target namespace
300
 * @param int    $auth current auth check result
301
 * @return false|string false on error, id of the new file on success
302
 */
303
function media_upload_xhr($ns,$auth){
304
    if(!checkSecurityToken()) return false;
305
    global $INPUT;
306
307
    $id = $INPUT->get->str('qqfile');
308
    list($ext,$mime) = mimetype($id);
309
    $input = fopen("php://input", "r");
310
    if (!($tmp = io_mktmpdir())) return false;
311
    $path = $tmp.'/'.md5($id);
312
    $target = fopen($path, "w");
313
    $realSize = stream_copy_to_stream($input, $target);
314
    fclose($target);
315
    fclose($input);
316
    if (isset($_SERVER["CONTENT_LENGTH"]) && ($realSize != (int)$_SERVER["CONTENT_LENGTH"])){
317
        unlink($path);
318
        return false;
319
    }
320
321
    $res = media_save(
322
        array('name' => $path,
323
            'mime' => $mime,
324
            'ext'  => $ext),
325
        $ns.':'.$id,
326
        (($INPUT->get->str('ow') == 'true') ? true : false),
327
        $auth,
328
        'copy'
329
    );
330
    unlink($path);
331
    if ($tmp) io_rmdir($tmp, true);
332
    if (is_array($res)) {
333
        msg($res[0], $res[1]);
334
        return false;
335
    }
336
    return $res;
337
}
338
339
/**
340
 * Handles media file uploads
341
 *
342
 * @author Andreas Gohr <[email protected]>
343
 * @author Michael Klier <[email protected]>
344
 *
345
 * @param string     $ns    target namespace
346
 * @param int        $auth  current auth check result
347
 * @param bool|array $file  $_FILES member, $_FILES['upload'] if false
348
 * @return false|string false on error, id of the new file on success
349
 */
350
function media_upload($ns,$auth,$file=false){
351
    if(!checkSecurityToken()) return false;
352
    global $lang;
353
    global $INPUT;
354
355
    // get file and id
356
    $id   = $INPUT->post->str('mediaid');
357
    if (!$file) $file = $_FILES['upload'];
358
    if(empty($id)) $id = $file['name'];
359
360
    // check for errors (messages are done in lib/exe/mediamanager.php)
361
    if($file['error']) return false;
362
363
    // check extensions
364
    list($fext,$fmime) = mimetype($file['name']);
365
    list($iext,$imime) = mimetype($id);
366
    if($fext && !$iext){
367
        // no extension specified in id - read original one
368
        $id   .= '.'.$fext;
369
        $imime = $fmime;
370
    }elseif($fext && $fext != $iext){
371
        // extension was changed, print warning
372
        msg(sprintf($lang['mediaextchange'],$fext,$iext));
373
    }
374
375
    $res = media_save(array('name' => $file['tmp_name'],
376
                            'mime' => $imime,
377
                            'ext'  => $iext), $ns.':'.$id,
378
                      $INPUT->post->bool('ow'), $auth, 'copy_uploaded_file');
379
    if (is_array($res)) {
380
        msg($res[0], $res[1]);
381
        return false;
382
    }
383
    return $res;
384
}
385
386
/**
387
 * An alternative to move_uploaded_file that copies
388
 *
389
 * Using copy, makes sure any setgid bits on the media directory are honored
390
 *
391
 * @see   move_uploaded_file()
392
 *
393
 * @param string $from
394
 * @param string $to
395
 * @return bool
396
 */
397
function copy_uploaded_file($from, $to){
398
    if(!is_uploaded_file($from)) return false;
399
    $ok = copy($from, $to);
400
    @unlink($from);
401
    return $ok;
402
}
403
404
/**
405
 * This generates an action event and delegates to _media_upload_action().
406
 * Action plugins are allowed to pre/postprocess the uploaded file.
407
 * (The triggered event is preventable.)
408
 *
409
 * Event data:
410
 * $data[0]     fn_tmp:    the temporary file name (read from $_FILES)
411
 * $data[1]     fn:        the file name of the uploaded file
412
 * $data[2]     id:        the future directory id of the uploaded file
413
 * $data[3]     imime:     the mimetype of the uploaded file
414
 * $data[4]     overwrite: if an existing file is going to be overwritten
415
 * $data[5]     move:      name of function that performs move/copy/..
416
 *
417
 * @triggers MEDIA_UPLOAD_FINISH
418
 *
419
 * @param array  $file
420
 * @param string $id   media id
421
 * @param bool   $ow   overwrite?
422
 * @param int    $auth permission level
423
 * @param string $move name of functions that performs move/copy/..
424
 * @return false|array|string
425
 */
426
function media_save($file, $id, $ow, $auth, $move) {
427
    if($auth < AUTH_UPLOAD) {
428
        return array("You don't have permissions to upload files.", -1);
429
    }
430
431
    if (!isset($file['mime']) || !isset($file['ext'])) {
432
        list($ext, $mime) = mimetype($id);
433
        if (!isset($file['mime'])) {
434
            $file['mime'] = $mime;
435
        }
436
        if (!isset($file['ext'])) {
437
            $file['ext'] = $ext;
438
        }
439
    }
440
441
    global $lang, $conf;
442
443
    // get filename
444
    $id   = cleanID($id);
445
    $fn   = mediaFN($id);
446
447
    // get filetype regexp
448
    $types = array_keys(getMimeTypes());
449
    $types = array_map(
450
        function ($q) {
451
            return preg_quote($q, "/");
452
        },
453
        $types
454
    );
455
    $regex = join('|',$types);
456
457
    // because a temp file was created already
458
    if(!preg_match('/\.('.$regex.')$/i',$fn)) {
459
        return array($lang['uploadwrong'],-1);
460
    }
461
462
    //check for overwrite
463
    $overwrite = file_exists($fn);
464
    $auth_ow = (($conf['mediarevisions']) ? AUTH_UPLOAD : AUTH_DELETE);
465
    if($overwrite && (!$ow || $auth < $auth_ow)) {
466
        return array($lang['uploadexist'], 0);
467
    }
468
    // check for valid content
469
    $ok = media_contentcheck($file['name'], $file['mime']);
470
    if($ok == -1){
471
        return array(sprintf($lang['uploadbadcontent'],'.' . $file['ext']),-1);
472
    }elseif($ok == -2){
473
        return array($lang['uploadspam'],-1);
474
    }elseif($ok == -3){
475
        return array($lang['uploadxss'],-1);
476
    }
477
478
    // prepare event data
479
    $data = array();
480
    $data[0] = $file['name'];
481
    $data[1] = $fn;
482
    $data[2] = $id;
483
    $data[3] = $file['mime'];
484
    $data[4] = $overwrite;
485
    $data[5] = $move;
486
487
    // trigger event
488
    return Event::createAndTrigger('MEDIA_UPLOAD_FINISH', $data, '_media_upload_action', true);
489
}
490
491
/**
492
 * Callback adapter for media_upload_finish() triggered by MEDIA_UPLOAD_FINISH
493
 *
494
 * @author Michael Klier <[email protected]>
495
 *
496
 * @param array $data event data
497
 * @return false|array|string
498
 */
499
function _media_upload_action($data) {
500
    // fixme do further sanity tests of given data?
501
    if(is_array($data) && count($data)===6) {
502
        return media_upload_finish($data[0], $data[1], $data[2], $data[3], $data[4], $data[5]);
503
    } else {
504
        return false; //callback error
505
    }
506
}
507
508
/**
509
 * Saves an uploaded media file
510
 *
511
 * @author Andreas Gohr <[email protected]>
512
 * @author Michael Klier <[email protected]>
513
 * @author Kate Arzamastseva <[email protected]>
514
 *
515
 * @param string $fn_tmp
516
 * @param string $fn
517
 * @param string $id        media id
518
 * @param string $imime     mime type
519
 * @param bool   $overwrite overwrite existing?
520
 * @param string $move      function name
521
 * @return array|string
522
 */
523
function media_upload_finish($fn_tmp, $fn, $id, $imime, $overwrite, $move = 'move_uploaded_file') {
524
    global $conf;
525
    global $lang;
526
    global $REV;
527
528
    $old = @filemtime($fn);
529
    if(!file_exists(mediaFN($id, $old)) && file_exists($fn)) {
530
        // add old revision to the attic if missing
531
        media_saveOldRevision($id);
532
    }
533
534
    // prepare directory
535
    io_createNamespace($id, 'media');
536
537
    $filesize_old = file_exists($fn) ? filesize($fn) : 0;
538
539
    if($move($fn_tmp, $fn)) {
540
        @clearstatcache(true,$fn);
541
        $new = @filemtime($fn);
542
        // Set the correct permission here.
543
        // Always chmod media because they may be saved with different permissions than expected from the php umask.
544
        // (Should normally chmod to $conf['fperm'] only if $conf['fperm'] is set.)
545
        chmod($fn, $conf['fmode']);
546
        msg($lang['uploadsucc'],1);
547
        media_notify($id,$fn,$imime,$old,$new);
548
        // add a log entry to the media changelog
549
        $filesize_new = filesize($fn);
550
        $sizechange = $filesize_new - $filesize_old;
551
        if($REV) {
552
            addMediaLogEntry(
553
                $new,
554
                $id,
555
                DOKU_CHANGE_TYPE_REVERT,
556
                sprintf($lang['restored'], dformat($REV)),
557
                $REV,
558
                null,
559
                $sizechange
560
            );
561
        } elseif($overwrite) {
562
            addMediaLogEntry($new, $id, DOKU_CHANGE_TYPE_EDIT, '', '', null, $sizechange);
563
        } else {
564
            addMediaLogEntry($new, $id, DOKU_CHANGE_TYPE_CREATE, $lang['created'], '', null, $sizechange);
565
        }
566
        return $id;
567
    }else{
568
        return array($lang['uploadfail'],-1);
569
    }
570
}
571
572
/**
573
 * Moves the current version of media file to the media_attic
574
 * directory
575
 *
576
 * @author Kate Arzamastseva <[email protected]>
577
 *
578
 * @param string $id
579
 * @return int - revision date
580
 */
581
function media_saveOldRevision($id){
582
    global $conf, $lang;
583
584
    $oldf = mediaFN($id);
585
    if(!file_exists($oldf)) return '';
586
    $date = filemtime($oldf);
587
    if (!$conf['mediarevisions']) return $date;
588
589
    $medialog = new MediaChangeLog($id);
590
    if (!$medialog->getRevisionInfo($date)) {
591
        // there was an external edit,
592
        // there is no log entry for current version of file
593
        $sizechange = filesize($oldf);
594
        if(!file_exists(mediaMetaFN($id, '.changes'))) {
595
            addMediaLogEntry($date, $id, DOKU_CHANGE_TYPE_CREATE, $lang['created'], '', null, $sizechange);
596
        } else {
597
            $oldRev = $medialog->getRevisions(-1, 1); // from changelog
598
            $oldRev = (int) (empty($oldRev) ? 0 : $oldRev[0]);
599
            $filesize_old = filesize(mediaFN($id, $oldRev));
600
            $sizechange = $sizechange - $filesize_old;
601
602
            addMediaLogEntry($date, $id, DOKU_CHANGE_TYPE_EDIT, '', '', null, $sizechange);
603
        }
604
    }
605
606
    $newf = mediaFN($id,$date);
607
    io_makeFileDir($newf);
608
    if(copy($oldf, $newf)) {
609
        // Set the correct permission here.
610
        // Always chmod media because they may be saved with different permissions than expected from the php umask.
611
        // (Should normally chmod to $conf['fperm'] only if $conf['fperm'] is set.)
612
        chmod($newf, $conf['fmode']);
613
    }
614
    return $date;
615
}
616
617
/**
618
 * This function checks if the uploaded content is really what the
619
 * mimetype says it is. We also do spam checking for text types here.
620
 *
621
 * We need to do this stuff because we can not rely on the browser
622
 * to do this check correctly. Yes, IE is broken as usual.
623
 *
624
 * @author Andreas Gohr <[email protected]>
625
 * @link   http://www.splitbrain.org/blog/2007-02/12-internet_explorer_facilitates_cross_site_scripting
626
 * @fixme  check all 26 magic IE filetypes here?
627
 *
628
 * @param string $file path to file
629
 * @param string $mime mimetype
630
 * @return int
631
 */
632
function media_contentcheck($file,$mime){
633
    global $conf;
634
    if($conf['iexssprotect']){
635
        $fh = @fopen($file, 'rb');
636
        if($fh){
637
            $bytes = fread($fh, 256);
638
            fclose($fh);
639
            if(preg_match('/<(script|a|img|html|body|iframe)[\s>]/i',$bytes)){
640
                return -3; //XSS: possibly malicious content
641
            }
642
        }
643
    }
644
    if(substr($mime,0,6) == 'image/'){
645
        $info = @getimagesize($file);
646
        if($mime == 'image/gif' && $info[2] != 1){
647
            return -1; // uploaded content did not match the file extension
648
        }elseif($mime == 'image/jpeg' && $info[2] != 2){
649
            return -1;
650
        }elseif($mime == 'image/png' && $info[2] != 3){
651
            return -1;
652
        }
653
        # fixme maybe check other images types as well
654
    }elseif(substr($mime,0,5) == 'text/'){
655
        global $TEXT;
656
        $TEXT = io_readFile($file);
657
        if(checkwordblock()){
658
            return -2; //blocked by the spam blacklist
659
        }
660
    }
661
    return 0;
662
}
663
664
/**
665
 * Send a notify mail on uploads
666
 *
667
 * @author Andreas Gohr <[email protected]>
668
 *
669
 * @param string   $id      media id
670
 * @param string   $file    path to file
671
 * @param string   $mime    mime type
672
 * @param bool|int $old_rev revision timestamp or false
673
 * @return bool
674
 */
675
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...
676
    global $conf;
677
    if(empty($conf['notify'])) return false; //notify enabled?
678
679
    $subscription = new MediaSubscriptionSender();
680
    return $subscription->sendMediaDiff($conf['notify'], 'uploadmail', $id, $old_rev, $current_rev);
681
}
682
683
/**
684
 * List all files in a given Media namespace
685
 *
686
 * @param string      $ns             namespace
687
 * @param null|int    $auth           permission level
688
 * @param string      $jump           id
689
 * @param bool        $fullscreenview
690
 * @param bool|string $sort           sorting order, false skips sorting
691
 */
692
function media_filelist($ns,$auth=null,$jump='',$fullscreenview=false,$sort=false){
693
    global $conf;
694
    global $lang;
695
    $ns = cleanID($ns);
696
697
    // check auth our self if not given (needed for ajax calls)
698
    if(is_null($auth)) $auth = auth_quickaclcheck("$ns:*");
699
700
    if (!$fullscreenview) echo '<h1 id="media__ns">:'.hsc($ns).'</h1>'.NL;
701
702
    if($auth < AUTH_READ){
703
        // FIXME: print permission warning here instead?
704
        echo '<div class="nothing">'.$lang['nothingfound'].'</div>'.NL;
705
    }else{
706
        if (!$fullscreenview) {
707
            media_uploadform($ns, $auth);
708
            media_searchform($ns);
709
        }
710
711
        $dir = utf8_encodeFN(str_replace(':','/',$ns));
712
        $data = array();
713
        search($data,$conf['mediadir'],'search_media',
714
                array('showmsg'=>true,'depth'=>1),$dir,1,$sort);
715
716
        if(!count($data)){
717
            echo '<div class="nothing">'.$lang['nothingfound'].'</div>'.NL;
718
        }else {
719
            if ($fullscreenview) {
720
                echo '<ul class="' . _media_get_list_type() . '">';
721
            }
722
            foreach($data as $item){
723
                if (!$fullscreenview) {
724
                    media_printfile($item,$auth,$jump);
725
                } else {
726
                    media_printfile_thumbs($item,$auth,$jump);
727
                }
728
            }
729
            if ($fullscreenview) echo '</ul>'.NL;
730
        }
731
    }
732
}
733
734
/**
735
 * Prints tabs for files list actions
736
 *
737
 * @author Kate Arzamastseva <[email protected]>
738
 * @author Adrian Lang <[email protected]>
739
 *
740
 * @param string $selected_tab - opened tab
741
 */
742
743
function media_tabs_files($selected_tab = ''){
744
    global $lang;
745
    $tabs = array();
746
    foreach(array('files'  => 'mediaselect',
747
                  'upload' => 'media_uploadtab',
748
                  'search' => 'media_searchtab') as $tab => $caption) {
749
        $tabs[$tab] = array('href'    => media_managerURL(array('tab_files' => $tab), '&'),
750
                            'caption' => $lang[$caption]);
751
    }
752
753
    html_tabs($tabs, $selected_tab);
754
}
755
756
/**
757
 * Prints tabs for files details actions
758
 *
759
 * @author Kate Arzamastseva <[email protected]>
760
 * @param string $image filename of the current image
761
 * @param string $selected_tab opened tab
762
 */
763
function media_tabs_details($image, $selected_tab = ''){
764
    global $lang, $conf;
765
766
    $tabs = array();
767
    $tabs['view'] = array('href'    => media_managerURL(array('tab_details' => 'view'), '&'),
768
                          'caption' => $lang['media_viewtab']);
769
770
    list(, $mime) = mimetype($image);
771
    if ($mime == 'image/jpeg' && file_exists(mediaFN($image))) {
772
        $tabs['edit'] = array('href'    => media_managerURL(array('tab_details' => 'edit'), '&'),
773
                              'caption' => $lang['media_edittab']);
774
    }
775
    if ($conf['mediarevisions']) {
776
        $tabs['history'] = array('href'    => media_managerURL(array('tab_details' => 'history'), '&'),
777
                                 'caption' => $lang['media_historytab']);
778
    }
779
780
    html_tabs($tabs, $selected_tab);
781
}
782
783
/**
784
 * Prints options for the tab that displays a list of all files
785
 *
786
 * @author Kate Arzamastseva <[email protected]>
787
 */
788
function media_tab_files_options(){
789
    global $lang;
790
    global $INPUT;
791
    global $ID;
792
    $form = new Doku_Form(array('class' => 'options', 'method' => 'get',
0 ignored issues
show
Deprecated Code introduced by
The class Doku_Form has been deprecated with message: 2019-07-14

This class, trait or interface 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 type will be removed from the class and what other constant to use instead.

Loading history...
793
                                'action' => wl($ID)));
794
    $media_manager_params = media_managerURL(array(), '', false, true);
795
    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...
796
        $form->addHidden($pKey, $pVal);
797
    }
798
    $form->addHidden('sectok', null);
799
    if ($INPUT->has('q')) {
800
        $form->addHidden('q', $INPUT->str('q'));
801
    }
802
    $form->addElement('<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->addElement('<li class="' . $content[0] . '">');
810
        foreach($content[1] as $option) {
811
            $attrs = array();
812
            if ($checked == $option) {
813
                $attrs['checked'] = 'checked';
814
            }
815
            $form->addElement(form_makeRadioField($group . '_dwmedia', $option,
816
                                       $lang['media_' . $group . '_' . $option],
817
                                                  $content[0] . '__' . $option,
818
                                                  $option, $attrs));
819
        }
820
        $form->addElement('</li>'.NL);
821
    }
822
    $form->addElement('<li>');
823
    $form->addElement(form_makeButton('submit', '', $lang['btn_apply']));
824
    $form->addElement('</li>'.NL);
825
    $form->addElement('</ul>'.NL);
826
    $form->printForm();
827
}
828
829
/**
830
 * Returns type of sorting for the list of files in media manager
831
 *
832
 * @author Kate Arzamastseva <[email protected]>
833
 *
834
 * @return string - sort type
835
 */
836
function _media_get_sort_type() {
837
    return _media_get_display_param('sort', array('default' => 'name', 'date'));
838
}
839
840
/**
841
 * Returns type of listing for the list of files in media manager
842
 *
843
 * @author Kate Arzamastseva <[email protected]>
844
 *
845
 * @return string - list type
846
 */
847
function _media_get_list_type() {
848
    return _media_get_display_param('list', array('default' => 'thumbs', 'rows'));
849
}
850
851
/**
852
 * Get display parameters
853
 *
854
 * @param string $param   name of parameter
855
 * @param array  $values  allowed values, where default value has index key 'default'
856
 * @return string the parameter value
857
 */
858
function _media_get_display_param($param, $values) {
859
    global $INPUT;
860
    if (in_array($INPUT->str($param), $values)) {
861
        // FIXME: Set cookie
862
        return $INPUT->str($param);
863
    } else {
864
        $val = get_doku_pref($param, $values['default']);
865
        if (!in_array($val, $values)) {
866
            $val = $values['default'];
867
        }
868
        return $val;
869
    }
870
}
871
872
/**
873
 * Prints tab that displays a list of all files
874
 *
875
 * @author Kate Arzamastseva <[email protected]>
876
 *
877
 * @param string    $ns
878
 * @param null|int  $auth permission level
879
 * @param string    $jump item id
880
 */
881
function media_tab_files($ns,$auth=null,$jump='') {
882
    global $lang;
883
    if(is_null($auth)) $auth = auth_quickaclcheck("$ns:*");
884
885
    if($auth < AUTH_READ){
886
        echo '<div class="nothing">'.$lang['media_perm_read'].'</div>'.NL;
887
    }else{
888
        media_filelist($ns,$auth,$jump,true,_media_get_sort_type());
889
    }
890
}
891
892
/**
893
 * Prints tab that displays uploading form
894
 *
895
 * @author Kate Arzamastseva <[email protected]>
896
 *
897
 * @param string   $ns
898
 * @param null|int $auth permission level
899
 * @param string   $jump item id
900
 */
901
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...
902
    global $lang;
903
    if(is_null($auth)) $auth = auth_quickaclcheck("$ns:*");
904
905
    echo '<div class="upload">'.NL;
906
    if ($auth >= AUTH_UPLOAD) {
907
        echo '<p>' . $lang['mediaupload'] . '</p>';
908
    }
909
    media_uploadform($ns, $auth, true);
910
    echo '</div>'.NL;
911
}
912
913
/**
914
 * Prints tab that displays search form
915
 *
916
 * @author Kate Arzamastseva <[email protected]>
917
 *
918
 * @param string $ns
919
 * @param null|int $auth permission level
920
 */
921
function media_tab_search($ns,$auth=null) {
922
    global $INPUT;
923
924
    $do = $INPUT->str('mediado');
925
    $query = $INPUT->str('q');
926
    echo '<div class="search">'.NL;
927
928
    media_searchform($ns, $query, true);
929
    if ($do == 'searchlist' || $query) {
930
        media_searchlist($query,$ns,$auth,true,_media_get_sort_type());
931
    }
932
    echo '</div>'.NL;
933
}
934
935
/**
936
 * Prints tab that displays mediafile details
937
 *
938
 * @author Kate Arzamastseva <[email protected]>
939
 *
940
 * @param string     $image media id
941
 * @param string     $ns
942
 * @param null|int   $auth  permission level
943
 * @param string|int $rev   revision timestamp or empty string
944
 */
945
function media_tab_view($image, $ns, $auth=null, $rev='') {
946
    global $lang;
947
    if(is_null($auth)) $auth = auth_quickaclcheck("$ns:*");
948
949
    if ($image && $auth >= AUTH_READ) {
950
        $meta = new JpegMeta(mediaFN($image, $rev));
951
        media_preview($image, $auth, $rev, $meta);
952
        media_preview_buttons($image, $auth, $rev);
953
        media_details($image, $auth, $rev, $meta);
954
955
    } else {
956
        echo '<div class="nothing">'.$lang['media_perm_read'].'</div>'.NL;
957
    }
958
}
959
960
/**
961
 * Prints tab that displays form for editing mediafile metadata
962
 *
963
 * @author Kate Arzamastseva <[email protected]>
964
 *
965
 * @param string     $image media id
966
 * @param string     $ns
967
 * @param null|int   $auth permission level
968
 */
969
function media_tab_edit($image, $ns, $auth=null) {
970
    if(is_null($auth)) $auth = auth_quickaclcheck("$ns:*");
971
972
    if ($image) {
973
        list(, $mime) = mimetype($image);
974
        if ($mime == 'image/jpeg') media_metaform($image,$auth);
975
    }
976
}
977
978
/**
979
 * Prints tab that displays mediafile revisions
980
 *
981
 * @author Kate Arzamastseva <[email protected]>
982
 *
983
 * @param string     $image media id
984
 * @param string     $ns
985
 * @param null|int   $auth permission level
986
 */
987
function media_tab_history($image, $ns, $auth=null) {
988
    global $lang;
989
    global $INPUT;
990
991
    if(is_null($auth)) $auth = auth_quickaclcheck("$ns:*");
992
    $do = $INPUT->str('mediado');
993
994
    if ($auth >= AUTH_READ && $image) {
995
        if ($do == 'diff'){
996
            media_diff($image, $ns, $auth);
997
        } else {
998
            $first = $INPUT->int('first');
999
            html_revisions($first, $image);
1000
        }
1001
    } else {
1002
        echo '<div class="nothing">'.$lang['media_perm_read'].'</div>'.NL;
1003
    }
1004
}
1005
1006
/**
1007
 * Prints mediafile details
1008
 *
1009
 * @param string         $image media id
1010
 * @param int            $auth permission level
1011
 * @param int|string     $rev revision timestamp or empty string
1012
 * @param JpegMeta|bool  $meta
1013
 *
1014
 * @author Kate Arzamastseva <[email protected]>
1015
 */
1016
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...
1017
1018
    $size = media_image_preview_size($image, $rev, $meta);
1019
1020
    if ($size) {
1021
        global $lang;
1022
        echo '<div class="image">';
1023
1024
        $more = array();
1025
        if ($rev) {
1026
            $more['rev'] = $rev;
1027
        } else {
1028
            $t = @filemtime(mediaFN($image));
1029
            $more['t'] = $t;
1030
        }
1031
1032
        $more['w'] = $size[0];
1033
        $more['h'] = $size[1];
1034
        $src = ml($image, $more);
1035
1036
        echo '<a href="'.$src.'" target="_blank" title="'.$lang['mediaview'].'">';
1037
        echo '<img src="'.$src.'" alt="" style="max-width: '.$size[0].'px;" />';
1038
        echo '</a>';
1039
1040
        echo '</div>'.NL;
1041
    }
1042
}
1043
1044
/**
1045
 * Prints mediafile action buttons
1046
 *
1047
 * @author Kate Arzamastseva <[email protected]>
1048
 *
1049
 * @param string     $image media id
1050
 * @param int        $auth  permission level
1051
 * @param string|int $rev   revision timestamp, or empty string
1052
 */
1053
function media_preview_buttons($image, $auth, $rev='') {
1054
    global $lang, $conf;
1055
1056
    echo '<ul class="actions">'.NL;
1057
1058
    if($auth >= AUTH_DELETE && !$rev && file_exists(mediaFN($image))){
1059
1060
        // delete button
1061
        $form = new Doku_Form(array('id' => 'mediamanager__btn_delete',
0 ignored issues
show
Deprecated Code introduced by
The class Doku_Form has been deprecated with message: 2019-07-14

This class, trait or interface 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 type will be removed from the class and what other constant to use instead.

Loading history...
1062
            'action'=>media_managerURL(array('delete' => $image), '&')));
1063
        $form->addElement(form_makeButton('submit','',$lang['btn_delete']));
1064
        echo '<li>';
1065
        $form->printForm();
1066
        echo '</li>'.NL;
1067
    }
1068
1069
    $auth_ow = (($conf['mediarevisions']) ? AUTH_UPLOAD : AUTH_DELETE);
1070
    if($auth >= $auth_ow && !$rev){
1071
1072
        // upload new version button
1073
        $form = new Doku_Form(array('id' => 'mediamanager__btn_update',
0 ignored issues
show
Deprecated Code introduced by
The class Doku_Form has been deprecated with message: 2019-07-14

This class, trait or interface 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 type will be removed from the class and what other constant to use instead.

Loading history...
1074
            'action'=>media_managerURL(array('image' => $image, 'mediado' => 'update'), '&')));
1075
        $form->addElement(form_makeButton('submit','',$lang['media_update']));
1076
        echo '<li>';
1077
        $form->printForm();
1078
        echo '</li>'.NL;
1079
    }
1080
1081
    if($auth >= AUTH_UPLOAD && $rev && $conf['mediarevisions'] && file_exists(mediaFN($image, $rev))){
1082
1083
        // restore button
1084
        $form = new Doku_Form(array('id' => 'mediamanager__btn_restore',
0 ignored issues
show
Deprecated Code introduced by
The class Doku_Form has been deprecated with message: 2019-07-14

This class, trait or interface 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 type will be removed from the class and what other constant to use instead.

Loading history...
1085
            'action'=>media_managerURL(array('image' => $image), '&')));
1086
        $form->addHidden('mediado','restore');
1087
        $form->addHidden('rev',$rev);
1088
        $form->addElement(form_makeButton('submit','',$lang['media_restore']));
1089
        echo '<li>';
1090
        $form->printForm();
1091
        echo '</li>'.NL;
1092
    }
1093
1094
    echo '</ul>'.NL;
1095
}
1096
1097
/**
1098
 * Returns image width and height for mediamanager preview panel
1099
 *
1100
 * @author Kate Arzamastseva <[email protected]>
1101
 * @param string         $image
1102
 * @param int|string     $rev
1103
 * @param JpegMeta|bool  $meta
1104
 * @param int            $size
1105
 * @return array|false
1106
 */
1107
function media_image_preview_size($image, $rev, $meta, $size = 500) {
1108
    if (!preg_match("/\.(jpe?g|gif|png)$/", $image) || !file_exists(mediaFN($image, $rev))) return false;
1109
1110
    $info = getimagesize(mediaFN($image, $rev));
1111
    $w = (int) $info[0];
1112
    $h = (int) $info[1];
1113
1114
    if($meta && ($w > $size || $h > $size)){
1115
        $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...
1116
        $w = floor($w * $ratio);
1117
        $h = floor($h * $ratio);
1118
    }
1119
    return array($w, $h);
1120
}
1121
1122
/**
1123
 * Returns the requested EXIF/IPTC tag from the image meta
1124
 *
1125
 * @author Kate Arzamastseva <[email protected]>
1126
 *
1127
 * @param array    $tags array with tags, first existing is returned
1128
 * @param JpegMeta $meta
1129
 * @param string   $alt  alternative value
1130
 * @return string
1131
 */
1132
function media_getTag($tags,$meta,$alt=''){
1133
    if($meta === false) return $alt;
1134
    $info = $meta->getField($tags);
1135
    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...
1136
    return $info;
1137
}
1138
1139
/**
1140
 * Returns mediafile tags
1141
 *
1142
 * @author Kate Arzamastseva <[email protected]>
1143
 *
1144
 * @param JpegMeta $meta
1145
 * @return array list of tags of the mediafile
1146
 */
1147
function media_file_tags($meta) {
1148
    // load the field descriptions
1149
    static $fields = null;
1150
    if(is_null($fields)){
1151
        $config_files = getConfigFiles('mediameta');
1152
        foreach ($config_files as $config_file) {
1153
            if(file_exists($config_file)) include($config_file);
1154
        }
1155
    }
1156
1157
    $tags = array();
1158
1159
    foreach($fields as $key => $tag){
0 ignored issues
show
Bug introduced by
The expression $fields of type null is not traversable.
Loading history...
1160
        $t = array();
1161
        if (!empty($tag[0])) $t = array($tag[0]);
1162
        if(isset($tag[3]) && is_array($tag[3])) $t = array_merge($t,$tag[3]);
1163
        $value = media_getTag($t, $meta);
1164
        $tags[] = array('tag' => $tag, 'value' => $value);
1165
    }
1166
1167
    return $tags;
1168
}
1169
1170
/**
1171
 * Prints mediafile tags
1172
 *
1173
 * @author Kate Arzamastseva <[email protected]>
1174
 *
1175
 * @param string        $image image id
1176
 * @param int           $auth  permission level
1177
 * @param string|int    $rev   revision timestamp, or empty string
1178
 * @param bool|JpegMeta $meta  image object, or create one if false
1179
 */
1180
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...
1181
    global $lang;
1182
1183
    if (!$meta) $meta = new JpegMeta(mediaFN($image, $rev));
1184
    $tags = media_file_tags($meta);
0 ignored issues
show
Bug introduced by
It seems like $meta defined by parameter $meta on line 1180 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...
1185
1186
    echo '<dl>'.NL;
1187
    foreach($tags as $tag){
1188
        if ($tag['value']) {
1189
            $value = cleanText($tag['value']);
1190
            echo '<dt>'.$lang[$tag['tag'][1]].'</dt><dd>';
1191
            if ($tag['tag'][2] == 'date') echo dformat($value);
1192
            else echo hsc($value);
1193
            echo '</dd>'.NL;
1194
        }
1195
    }
1196
    echo '</dl>'.NL;
1197
    echo '<dl>'.NL;
1198
    echo '<dt>'.$lang['reference'].':</dt>';
1199
    $media_usage = ft_mediause($image,true);
1200
    if(count($media_usage) > 0){
1201
        foreach($media_usage as $path){
1202
            echo '<dd>'.html_wikilink($path).'</dd>';
1203
        }
1204
    }else{
1205
        echo '<dd>'.$lang['nothingfound'].'</dd>';
1206
    }
1207
    echo '</dl>'.NL;
1208
1209
}
1210
1211
/**
1212
 * Shows difference between two revisions of file
1213
 *
1214
 * @author Kate Arzamastseva <[email protected]>
1215
 *
1216
 * @param string $image  image id
1217
 * @param string $ns
1218
 * @param int $auth permission level
1219
 * @param bool $fromajax
1220
 * @return false|null|string
1221
 */
1222
function media_diff($image, $ns, $auth, $fromajax = false) {
1223
    global $conf;
1224
    global $INPUT;
1225
1226
    if ($auth < AUTH_READ || !$image || !$conf['mediarevisions']) return '';
1227
1228
    $rev1 = $INPUT->int('rev');
1229
1230
    $rev2 = $INPUT->ref('rev2');
1231
    if(is_array($rev2)){
1232
        $rev1 = (int) $rev2[0];
1233
        $rev2 = (int) $rev2[1];
1234
1235
        if(!$rev1){
1236
            $rev1 = $rev2;
1237
            unset($rev2);
1238
        }
1239
    }else{
1240
        $rev2 = $INPUT->int('rev2');
1241
    }
1242
1243
    if ($rev1 && !file_exists(mediaFN($image, $rev1))) $rev1 = false;
1244
    if ($rev2 && !file_exists(mediaFN($image, $rev2))) $rev2 = false;
1245
1246
    if($rev1 && $rev2){            // two specific revisions wanted
1247
        // make sure order is correct (older on the left)
1248
        if($rev1 < $rev2){
1249
            $l_rev = $rev1;
1250
            $r_rev = $rev2;
1251
        }else{
1252
            $l_rev = $rev2;
1253
            $r_rev = $rev1;
1254
        }
1255
    }elseif($rev1){                // single revision given, compare to current
1256
        $r_rev = '';
1257
        $l_rev = $rev1;
1258
    }else{                        // no revision was given, compare previous to current
1259
        $r_rev = '';
1260
        $medialog = new MediaChangeLog($image);
1261
        $revs = $medialog->getRevisions(0, 1);
1262
        if (file_exists(mediaFN($image, $revs[0]))) {
1263
            $l_rev = $revs[0];
1264
        } else {
1265
            $l_rev = '';
1266
        }
1267
    }
1268
1269
    // prepare event data
1270
    $data = array();
1271
    $data[0] = $image;
1272
    $data[1] = $l_rev;
1273
    $data[2] = $r_rev;
1274
    $data[3] = $ns;
1275
    $data[4] = $auth;
1276
    $data[5] = $fromajax;
1277
1278
    // trigger event
1279
    return Event::createAndTrigger('MEDIA_DIFF', $data, '_media_file_diff', true);
1280
}
1281
1282
/**
1283
 * Callback for media file diff
1284
 *
1285
 * @param array $data event data
1286
 * @return false|null
1287
 */
1288
function _media_file_diff($data) {
1289
    if(is_array($data) && count($data)===6) {
1290
        media_file_diff($data[0], $data[1], $data[2], $data[3], $data[4], $data[5]);
1291
    } else {
1292
        return false;
1293
    }
1294
}
1295
1296
/**
1297
 * Shows difference between two revisions of image
1298
 *
1299
 * @author Kate Arzamastseva <[email protected]>
1300
 *
1301
 * @param string $image
1302
 * @param string|int $l_rev revision timestamp, or empty string
1303
 * @param string|int $r_rev revision timestamp, or empty string
1304
 * @param string $ns
1305
 * @param int $auth permission level
1306
 * @param bool $fromajax
1307
 */
1308
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...
1309
    global $lang;
1310
    global $INPUT;
1311
1312
    $l_meta = new JpegMeta(mediaFN($image, $l_rev));
1313
    $r_meta = new JpegMeta(mediaFN($image, $r_rev));
1314
1315
    $is_img = preg_match('/\.(jpe?g|gif|png)$/', $image);
1316
    if ($is_img) {
1317
        $l_size = media_image_preview_size($image, $l_rev, $l_meta);
1318
        $r_size = media_image_preview_size($image, $r_rev, $r_meta);
1319
        $is_img = ($l_size && $r_size && ($l_size[0] >= 30 || $r_size[0] >= 30));
1320
1321
        $difftype = $INPUT->str('difftype');
1322
1323
        if (!$fromajax) {
1324
            $form = new Doku_Form(array(
0 ignored issues
show
Deprecated Code introduced by
The class Doku_Form has been deprecated with message: 2019-07-14

This class, trait or interface 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 type will be removed from the class and what other constant to use instead.

Loading history...
1325
                'action' => media_managerURL(array(), '&'),
1326
                'method' => 'get',
1327
                'id' => 'mediamanager__form_diffview',
1328
                'class' => 'diffView'
1329
            ));
1330
            $form->addHidden('sectok', null);
1331
            $form->addElement('<input type="hidden" name="rev2[]" value="'.$l_rev.'" ></input>');
1332
            $form->addElement('<input type="hidden" name="rev2[]" value="'.$r_rev.'" ></input>');
1333
            $form->addHidden('mediado', 'diff');
1334
            $form->printForm();
1335
1336
            echo NL.'<div id="mediamanager__diff" >'.NL;
1337
        }
1338
1339
        if ($difftype == 'opacity' || $difftype == 'portions') {
1340
            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 1317 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 1318 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...
1341
            if (!$fromajax) echo '</div>';
1342
            return;
1343
        }
1344
    }
1345
1346
    list($l_head, $r_head) = html_diff_head($l_rev, $r_rev, $image, true);
1347
1348
    ?>
1349
    <div class="table">
1350
    <table>
1351
      <tr>
1352
        <th><?php echo $l_head; ?></th>
1353
        <th><?php echo $r_head; ?></th>
1354
      </tr>
1355
    <?php
1356
1357
    echo '<tr class="image">';
1358
    echo '<td>';
1359
    media_preview($image, $auth, $l_rev, $l_meta);
1360
    echo '</td>';
1361
1362
    echo '<td>';
1363
    media_preview($image, $auth, $r_rev, $r_meta);
1364
    echo '</td>';
1365
    echo '</tr>'.NL;
1366
1367
    echo '<tr class="actions">';
1368
    echo '<td>';
1369
    media_preview_buttons($image, $auth, $l_rev);
1370
    echo '</td>';
1371
1372
    echo '<td>';
1373
    media_preview_buttons($image, $auth, $r_rev);
1374
    echo '</td>';
1375
    echo '</tr>'.NL;
1376
1377
    $l_tags = media_file_tags($l_meta);
1378
    $r_tags = media_file_tags($r_meta);
1379
    // FIXME r_tags-only stuff
1380
    foreach ($l_tags as $key => $l_tag) {
1381
        if ($l_tag['value'] != $r_tags[$key]['value']) {
1382
            $r_tags[$key]['highlighted'] = true;
1383
            $l_tags[$key]['highlighted'] = true;
1384
        } else if (!$l_tag['value'] || !$r_tags[$key]['value']) {
1385
            unset($r_tags[$key]);
1386
            unset($l_tags[$key]);
1387
        }
1388
    }
1389
1390
    echo '<tr>';
1391
    foreach(array($l_tags,$r_tags) as $tags){
1392
        echo '<td>'.NL;
1393
1394
        echo '<dl class="img_tags">';
1395
        foreach($tags as $tag){
1396
            $value = cleanText($tag['value']);
1397
            if (!$value) $value = '-';
1398
            echo '<dt>'.$lang[$tag['tag'][1]].'</dt>';
1399
            echo '<dd>';
1400
            if ($tag['highlighted']) {
1401
                echo '<strong>';
1402
            }
1403
            if ($tag['tag'][2] == 'date') echo dformat($value);
1404
            else echo hsc($value);
1405
            if ($tag['highlighted']) {
1406
                echo '</strong>';
1407
            }
1408
            echo '</dd>';
1409
        }
1410
        echo '</dl>'.NL;
1411
1412
        echo '</td>';
1413
    }
1414
    echo '</tr>'.NL;
1415
1416
    echo '</table>'.NL;
1417
    echo '</div>'.NL;
1418
1419
    if ($is_img && !$fromajax) echo '</div>';
1420
}
1421
1422
/**
1423
 * Prints two images side by side
1424
 * and slider
1425
 *
1426
 * @author Kate Arzamastseva <[email protected]>
1427
 *
1428
 * @param string $image   image id
1429
 * @param int    $l_rev   revision timestamp, or empty string
1430
 * @param int    $r_rev   revision timestamp, or empty string
1431
 * @param array  $l_size  array with width and height
1432
 * @param array  $r_size  array with width and height
1433
 * @param string $type
1434
 */
1435
function media_image_diff($image, $l_rev, $r_rev, $l_size, $r_size, $type) {
1436
    if ($l_size != $r_size) {
1437
        if ($r_size[0] > $l_size[0]) {
1438
            $l_size = $r_size;
1439
        }
1440
    }
1441
1442
    $l_more = array('rev' => $l_rev, 'h' => $l_size[1], 'w' => $l_size[0]);
1443
    $r_more = array('rev' => $r_rev, 'h' => $l_size[1], 'w' => $l_size[0]);
1444
1445
    $l_src = ml($image, $l_more);
1446
    $r_src = ml($image, $r_more);
1447
1448
    // slider
1449
    echo '<div class="slider" style="max-width: '.($l_size[0]-20).'px;" ></div>'.NL;
1450
1451
    // two images in divs
1452
    echo '<div class="imageDiff ' . $type . '">'.NL;
1453
    echo '<div class="image1" style="max-width: '.$l_size[0].'px;">';
1454
    echo '<img src="'.$l_src.'" alt="" />';
1455
    echo '</div>'.NL;
1456
    echo '<div class="image2" style="max-width: '.$l_size[0].'px;">';
1457
    echo '<img src="'.$r_src.'" alt="" />';
1458
    echo '</div>'.NL;
1459
    echo '</div>'.NL;
1460
}
1461
1462
/**
1463
 * Restores an old revision of a media file
1464
 *
1465
 * @param string $image media id
1466
 * @param int    $rev   revision timestamp or empty string
1467
 * @param int    $auth
1468
 * @return string - file's id
1469
 *
1470
 * @author Kate Arzamastseva <[email protected]>
1471
 */
1472
function media_restore($image, $rev, $auth){
1473
    global $conf;
1474
    if ($auth < AUTH_UPLOAD || !$conf['mediarevisions']) return false;
1475
    $removed = (!file_exists(mediaFN($image)) && file_exists(mediaMetaFN($image, '.changes')));
1476
    if (!$image || (!file_exists(mediaFN($image)) && !$removed)) return false;
1477
    if (!$rev || !file_exists(mediaFN($image, $rev))) return false;
1478
    list(,$imime,) = mimetype($image);
1479
    $res = media_upload_finish(mediaFN($image, $rev),
1480
        mediaFN($image),
1481
        $image,
1482
        $imime,
1483
        true,
1484
        'copy');
1485
    if (is_array($res)) {
1486
        msg($res[0], $res[1]);
1487
        return false;
1488
    }
1489
    return $res;
1490
}
1491
1492
/**
1493
 * List all files found by the search request
1494
 *
1495
 * @author Tobias Sarnowski <[email protected]>
1496
 * @author Andreas Gohr <[email protected]>
1497
 * @author Kate Arzamastseva <[email protected]>
1498
 * @triggers MEDIA_SEARCH
1499
 *
1500
 * @param string $query
1501
 * @param string $ns
1502
 * @param null|int $auth
1503
 * @param bool $fullscreen
1504
 * @param string $sort
1505
 */
1506
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...
1507
    global $conf;
1508
    global $lang;
1509
1510
    $ns = cleanID($ns);
1511
    $evdata = array(
1512
        'ns'    => $ns,
1513
        'data'  => array(),
1514
        'query' => $query
1515
    );
1516
    if (!blank($query)) {
1517
        $evt = new Event('MEDIA_SEARCH', $evdata);
1518
        if ($evt->advise_before()) {
1519
            $dir = utf8_encodeFN(str_replace(':','/',$evdata['ns']));
1520
            $quoted = preg_quote($evdata['query'],'/');
1521
            //apply globbing
1522
            $quoted = str_replace(array('\*', '\?'), array('.*', '.'), $quoted, $count);
1523
1524
            //if we use globbing file name must match entirely but may be preceded by arbitrary namespace
1525
            if ($count > 0) $quoted = '^([^:]*:)*'.$quoted.'$';
1526
1527
            $pattern = '/'.$quoted.'/i';
1528
            search($evdata['data'],
1529
                    $conf['mediadir'],
1530
                    'search_media',
1531
                    array('showmsg'=>false,'pattern'=>$pattern),
1532
                    $dir,
1533
                    1,
1534
                    $sort);
1535
        }
1536
        $evt->advise_after();
1537
        unset($evt);
1538
    }
1539
1540
    if (!$fullscreen) {
1541
        echo '<h1 id="media__ns">'.sprintf($lang['searchmedia_in'],hsc($ns).':*').'</h1>'.NL;
1542
        media_searchform($ns,$query);
1543
    }
1544
1545
    if(!count($evdata['data'])){
1546
        echo '<div class="nothing">'.$lang['nothingfound'].'</div>'.NL;
1547
    }else {
1548
        if ($fullscreen) {
1549
            echo '<ul class="' . _media_get_list_type() . '">';
1550
        }
1551
        foreach($evdata['data'] as $item){
1552
            if (!$fullscreen) media_printfile($item,$item['perm'],'',true);
1553
            else media_printfile_thumbs($item,$item['perm'],false,true);
1554
        }
1555
        if ($fullscreen) echo '</ul>'.NL;
1556
    }
1557
}
1558
1559
/**
1560
 * Formats and prints one file in the list
1561
 *
1562
 * @param array     $item
1563
 * @param int       $auth              permission level
1564
 * @param string    $jump              item id
1565
 * @param bool      $display_namespace
1566
 */
1567
function media_printfile($item,$auth,$jump,$display_namespace=false){
1568
    global $lang;
1569
1570
    // Prepare zebra coloring
1571
    // I always wanted to use this variable name :-D
1572
    static $twibble = 1;
1573
    $twibble *= -1;
1574
    $zebra = ($twibble == -1) ? 'odd' : 'even';
1575
1576
    // Automatically jump to recent action
1577
    if($jump == $item['id']) {
1578
        $jump = ' id="scroll__here" ';
1579
    }else{
1580
        $jump = '';
1581
    }
1582
1583
    // Prepare fileicons
1584
    list($ext) = mimetype($item['file'],false);
1585
    $class = preg_replace('/[^_\-a-z0-9]+/i','_',$ext);
1586
    $class = 'select mediafile mf_'.$class;
1587
1588
    // Prepare filename
1589
    $file = utf8_decodeFN($item['file']);
1590
1591
    // Prepare info
1592
    $info = '';
1593
    if($item['isimg']){
1594
        $info .= (int) $item['meta']->getField('File.Width');
1595
        $info .= '&#215;';
1596
        $info .= (int) $item['meta']->getField('File.Height');
1597
        $info .= ' ';
1598
    }
1599
    $info .= '<i>'.dformat($item['mtime']).'</i>';
1600
    $info .= ' ';
1601
    $info .= filesize_h($item['size']);
1602
1603
    // output
1604
    echo '<div class="'.$zebra.'"'.$jump.' title="'.hsc($item['id']).'">'.NL;
1605
    if (!$display_namespace) {
1606
        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 1589 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...
1607
    } else {
1608
        echo '<a id="h_:'.$item['id'].'" class="'.$class.'">'.hsc($item['id']).'</a><br/>';
1609
    }
1610
    echo '<span class="info">('.$info.')</span>'.NL;
1611
1612
    // view button
1613
    $link = ml($item['id'],'',true);
1614
    echo ' <a href="'.$link.'" target="_blank"><img src="'.DOKU_BASE.'lib/images/magnifier.png" '.
1615
        'alt="'.$lang['mediaview'].'" title="'.$lang['mediaview'].'" class="btn" /></a>';
1616
1617
    // mediamanager button
1618
    $link = wl('',array('do'=>'media','image'=>$item['id'],'ns'=>getNS($item['id'])));
1619
    echo ' <a href="'.$link.'" target="_blank"><img src="'.DOKU_BASE.'lib/images/mediamanager.png" '.
1620
        'alt="'.$lang['btn_media'].'" title="'.$lang['btn_media'].'" class="btn" /></a>';
1621
1622
    // delete button
1623
    if($item['writable'] && $auth >= AUTH_DELETE){
1624
        $link = DOKU_BASE.'lib/exe/mediamanager.php?delete='.rawurlencode($item['id']).
1625
            '&amp;sectok='.getSecurityToken();
1626
        echo ' <a href="'.$link.'" class="btn_media_delete" title="'.$item['id'].'">'.
1627
            '<img src="'.DOKU_BASE.'lib/images/trash.png" alt="'.$lang['btn_delete'].'" '.
1628
            'title="'.$lang['btn_delete'].'" class="btn" /></a>';
1629
    }
1630
1631
    echo '<div class="example" id="ex_'.str_replace(':','_',$item['id']).'">';
1632
    echo $lang['mediausage'].' <code>{{:'.$item['id'].'}}</code>';
1633
    echo '</div>';
1634
    if($item['isimg']) media_printimgdetail($item);
1635
    echo '<div class="clearer"></div>'.NL;
1636
    echo '</div>'.NL;
1637
}
1638
1639
/**
1640
 * Display a media icon
1641
 *
1642
 * @param string $filename media id
1643
 * @param string $size     the size subfolder, if not specified 16x16 is used
1644
 * @return string html
1645
 */
1646
function media_printicon($filename, $size=''){
1647
    list($ext) = mimetype(mediaFN($filename),false);
1648
1649
    if (file_exists(DOKU_INC.'lib/images/fileicons/'.$size.'/'.$ext.'.png')) {
1650
        $icon = DOKU_BASE.'lib/images/fileicons/'.$size.'/'.$ext.'.png';
1651
    } else {
1652
        $icon = DOKU_BASE.'lib/images/fileicons/'.$size.'/file.png';
1653
    }
1654
1655
    return '<img src="'.$icon.'" alt="'.$filename.'" class="icon" />';
1656
}
1657
1658
/**
1659
 * Formats and prints one file in the list in the thumbnails view
1660
 *
1661
 * @author Kate Arzamastseva <[email protected]>
1662
 *
1663
 * @param array       $item
1664
 * @param int         $auth              permission level
1665
 * @param bool|string $jump              item id
1666
 * @param bool        $display_namespace
1667
 */
1668
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...
1669
1670
    // Prepare filename
1671
    $file = utf8_decodeFN($item['file']);
1672
1673
    // output
1674
    echo '<li><dl title="'.hsc($item['id']).'">'.NL;
1675
1676
        echo '<dt>';
1677
    if($item['isimg']) {
1678
        media_printimgdetail($item, true);
1679
1680
    } else {
1681
        echo '<a id="d_:'.$item['id'].'" class="image" title="'.$item['id'].'" href="'.
1682
            media_managerURL(array('image' => hsc($item['id']), 'ns' => getNS($item['id']),
1683
            'tab_details' => 'view')).'">';
1684
        echo media_printicon($item['id'], '32x32');
1685
        echo '</a>';
1686
    }
1687
    echo '</dt>'.NL;
1688
    if (!$display_namespace) {
1689
        $name = hsc($file);
0 ignored issues
show
Security Bug introduced by
It seems like $file defined by utf8_decodeFN($item['file']) on line 1671 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...
1690
    } else {
1691
        $name = hsc($item['id']);
1692
    }
1693
    echo '<dd class="name"><a href="'.media_managerURL(array('image' => hsc($item['id']), 'ns' => getNS($item['id']),
1694
        'tab_details' => 'view')).'" id="h_:'.$item['id'].'">'.$name.'</a></dd>'.NL;
1695
1696
    if($item['isimg']){
1697
        $size = '';
1698
        $size .= (int) $item['meta']->getField('File.Width');
1699
        $size .= '&#215;';
1700
        $size .= (int) $item['meta']->getField('File.Height');
1701
        echo '<dd class="size">'.$size.'</dd>'.NL;
1702
    } else {
1703
        echo '<dd class="size">&#160;</dd>'.NL;
1704
    }
1705
    $date = dformat($item['mtime']);
1706
    echo '<dd class="date">'.$date.'</dd>'.NL;
1707
    $filesize = filesize_h($item['size']);
1708
    echo '<dd class="filesize">'.$filesize.'</dd>'.NL;
1709
    echo '</dl></li>'.NL;
1710
}
1711
1712
/**
1713
 * Prints a thumbnail and metainfo
1714
 *
1715
 * @param array $item
1716
 * @param bool  $fullscreen
1717
 */
1718
function media_printimgdetail($item, $fullscreen=false){
1719
    // prepare thumbnail
1720
    $size = $fullscreen ? 90 : 120;
1721
1722
    $w = (int) $item['meta']->getField('File.Width');
1723
    $h = (int) $item['meta']->getField('File.Height');
1724
    if($w>$size || $h>$size){
1725
        if (!$fullscreen) {
1726
            $ratio = $item['meta']->getResizeRatio($size);
1727
        } else {
1728
            $ratio = $item['meta']->getResizeRatio($size,$size);
1729
        }
1730
        $w = floor($w * $ratio);
1731
        $h = floor($h * $ratio);
1732
    }
1733
    $src = ml($item['id'],array('w'=>$w,'h'=>$h,'t'=>$item['mtime']));
1734
    $p = array();
1735
    if (!$fullscreen) {
1736
        // In fullscreen mediamanager view, image resizing is done via CSS.
1737
        $p['width']  = $w;
1738
        $p['height'] = $h;
1739
    }
1740
    $p['alt']    = $item['id'];
1741
    $att = buildAttributes($p);
1742
1743
    // output
1744
    if ($fullscreen) {
1745
        echo '<a id="l_:'.$item['id'].'" class="image thumb" href="'.
1746
            media_managerURL(['image' => hsc($item['id']), 'ns' => getNS($item['id']), 'tab_details' => 'view']).'">';
1747
        echo '<img src="'.$src.'" '.$att.' />';
1748
        echo '</a>';
1749
    }
1750
1751
    if ($fullscreen) return;
1752
1753
    echo '<div class="detail">';
1754
    echo '<div class="thumb">';
1755
    echo '<a id="d_:'.$item['id'].'" class="select">';
1756
    echo '<img src="'.$src.'" '.$att.' />';
1757
    echo '</a>';
1758
    echo '</div>';
1759
1760
    // read EXIF/IPTC data
1761
    $t = $item['meta']->getField(array('IPTC.Headline','xmp.dc:title'));
1762
    $d = $item['meta']->getField(array('IPTC.Caption','EXIF.UserComment',
1763
                'EXIF.TIFFImageDescription',
1764
                'EXIF.TIFFUserComment'));
1765
    if(\dokuwiki\Utf8\PhpString::strlen($d) > 250) $d = \dokuwiki\Utf8\PhpString::substr($d,0,250).'...';
1766
    $k = $item['meta']->getField(array('IPTC.Keywords','IPTC.Category','xmp.dc:subject'));
1767
1768
    // print EXIF/IPTC data
1769
    if($t || $d || $k ){
1770
        echo '<p>';
1771
        if($t) echo '<strong>'.hsc($t).'</strong><br />';
1772
        if($d) echo hsc($d).'<br />';
1773
        if($t) echo '<em>'.hsc($k).'</em>';
1774
        echo '</p>';
1775
    }
1776
    echo '</div>';
1777
}
1778
1779
/**
1780
 * Build link based on the current, adding/rewriting parameters
1781
 *
1782
 * @author Kate Arzamastseva <[email protected]>
1783
 *
1784
 * @param array|bool $params
1785
 * @param string     $amp           separator
1786
 * @param bool       $abs           absolute url?
1787
 * @param bool       $params_array  return the parmeters array?
1788
 * @return string|array - link or link parameters
1789
 */
1790
function media_managerURL($params=false, $amp='&amp;', $abs=false, $params_array=false) {
1791
    global $ID;
1792
    global $INPUT;
1793
1794
    $gets = array('do' => 'media');
1795
    $media_manager_params = array('tab_files', 'tab_details', 'image', 'ns', 'list', 'sort');
1796
    foreach ($media_manager_params as $x) {
1797
        if ($INPUT->has($x)) $gets[$x] = $INPUT->str($x);
1798
    }
1799
1800
    if ($params) {
1801
        $gets = $params + $gets;
1802
    }
1803
    unset($gets['id']);
1804
    if (isset($gets['delete'])) {
1805
        unset($gets['image']);
1806
        unset($gets['tab_details']);
1807
    }
1808
1809
    if ($params_array) return $gets;
1810
1811
    return wl($ID,$gets,$abs,$amp);
1812
}
1813
1814
/**
1815
 * Print the media upload form if permissions are correct
1816
 *
1817
 * @author Andreas Gohr <[email protected]>
1818
 * @author Kate Arzamastseva <[email protected]>
1819
 *
1820
 * @param string $ns
1821
 * @param int    $auth permission level
1822
 * @param bool  $fullscreen
1823
 */
1824
function media_uploadform($ns, $auth, $fullscreen = false){
1825
    global $lang;
1826
    global $conf;
1827
    global $INPUT;
1828
1829
    if($auth < AUTH_UPLOAD) {
1830
        echo '<div class="nothing">'.$lang['media_perm_upload'].'</div>'.NL;
1831
        return;
1832
    }
1833
    $auth_ow = (($conf['mediarevisions']) ? AUTH_UPLOAD : AUTH_DELETE);
1834
1835
    $update = false;
1836
    $id = '';
1837
    if ($auth >= $auth_ow && $fullscreen && $INPUT->str('mediado') == 'update') {
1838
        $update = true;
1839
        $id = cleanID($INPUT->str('image'));
1840
    }
1841
1842
    // The default HTML upload form
1843
    $params = array('id'      => 'dw__upload',
1844
                    'enctype' => 'multipart/form-data');
1845
    if (!$fullscreen) {
1846
        $params['action'] = DOKU_BASE.'lib/exe/mediamanager.php';
1847
    } else {
1848
        $params['action'] = media_managerURL(array('tab_files' => 'files',
1849
            'tab_details' => 'view'), '&');
1850
    }
1851
1852
    $form = new Doku_Form($params);
0 ignored issues
show
Deprecated Code introduced by
The class Doku_Form has been deprecated with message: 2019-07-14

This class, trait or interface 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 type will be removed from the class and what other constant to use instead.

Loading history...
1853
    if (!$fullscreen) echo '<div class="upload">' . $lang['mediaupload'] . '</div>';
1854
    $form->addElement(formSecurityToken());
1855
    $form->addHidden('ns', hsc($ns));
1856
    $form->addElement(form_makeOpenTag('p'));
1857
    $form->addElement(form_makeFileField('upload', $lang['txt_upload'], 'upload__file'));
1858
    $form->addElement(form_makeCloseTag('p'));
1859
    $form->addElement(form_makeOpenTag('p'));
1860
    $form->addElement(form_makeTextField('mediaid', noNS($id), $lang['txt_filename'], 'upload__name'));
1861
    $form->addElement(form_makeButton('submit', '', $lang['btn_upload']));
1862
    $form->addElement(form_makeCloseTag('p'));
1863
1864
    if($auth >= $auth_ow){
1865
        $form->addElement(form_makeOpenTag('p'));
1866
        $attrs = array();
1867
        if ($update) $attrs['checked'] = 'checked';
1868
        $form->addElement(form_makeCheckboxField('ow', 1, $lang['txt_overwrt'], 'dw__ow', 'check', $attrs));
1869
        $form->addElement(form_makeCloseTag('p'));
1870
    }
1871
1872
    echo NL.'<div id="mediamanager__uploader">'.NL;
1873
    html_form('upload', $form);
1874
1875
    echo '</div>'.NL;
1876
1877
    echo '<p class="maxsize">';
1878
    printf($lang['maxuploadsize'],filesize_h(media_getuploadsize()));
1879
    echo '</p>'.NL;
1880
1881
}
1882
1883
/**
1884
 * Returns the size uploaded files may have
1885
 *
1886
 * This uses a conservative approach using the lowest number found
1887
 * in any of the limiting ini settings
1888
 *
1889
 * @returns int size in bytes
1890
 */
1891
function media_getuploadsize(){
1892
    $okay = 0;
1893
1894
    $post = (int) php_to_byte(@ini_get('post_max_size'));
1895
    $suho = (int) php_to_byte(@ini_get('suhosin.post.max_value_length'));
1896
    $upld = (int) php_to_byte(@ini_get('upload_max_filesize'));
1897
1898
    if($post && ($post < $okay || $okay == 0)) $okay = $post;
1899
    if($suho && ($suho < $okay || $okay == 0)) $okay = $suho;
1900
    if($upld && ($upld < $okay || $okay == 0)) $okay = $upld;
1901
1902
    return $okay;
1903
}
1904
1905
/**
1906
 * Print the search field form
1907
 *
1908
 * @author Tobias Sarnowski <[email protected]>
1909
 * @author Kate Arzamastseva <[email protected]>
1910
 *
1911
 * @param string $ns
1912
 * @param string $query
1913
 * @param bool $fullscreen
1914
 */
1915
function media_searchform($ns,$query='',$fullscreen=false){
1916
    global $lang;
1917
1918
    // The default HTML search form
1919
    $params = array('id' => 'dw__mediasearch');
1920
    if (!$fullscreen) {
1921
        $params['action'] = DOKU_BASE.'lib/exe/mediamanager.php';
1922
    } else {
1923
        $params['action'] = media_managerURL(array(), '&');
1924
    }
1925
    $form = new Doku_Form($params);
0 ignored issues
show
Deprecated Code introduced by
The class Doku_Form has been deprecated with message: 2019-07-14

This class, trait or interface 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 type will be removed from the class and what other constant to use instead.

Loading history...
1926
    $form->addHidden('ns', $ns);
1927
    $form->addHidden($fullscreen ? 'mediado' : 'do', 'searchlist');
1928
1929
    $form->addElement(form_makeOpenTag('p'));
1930
    $form->addElement(
1931
        form_makeTextField(
1932
            'q',
1933
            $query,
1934
            $lang['searchmedia'],
1935
            '',
1936
            '',
1937
            array('title' => sprintf($lang['searchmedia_in'], hsc($ns) . ':*'))
1938
        )
1939
    );
1940
    $form->addElement(form_makeButton('submit', '', $lang['btn_search']));
1941
    $form->addElement(form_makeCloseTag('p'));
1942
    html_form('searchmedia', $form);
1943
}
1944
1945
/**
1946
 * Build a tree outline of available media namespaces
1947
 *
1948
 * @author Andreas Gohr <[email protected]>
1949
 *
1950
 * @param string $ns
1951
 */
1952
function media_nstree($ns){
1953
    global $conf;
1954
    global $lang;
1955
1956
    // currently selected namespace
1957
    $ns  = cleanID($ns);
1958
    if(empty($ns)){
1959
        global $ID;
1960
        $ns = (string)getNS($ID);
1961
    }
1962
1963
    $ns_dir  = utf8_encodeFN(str_replace(':','/',$ns));
1964
1965
    $data = array();
1966
    search($data,$conf['mediadir'],'search_index',array('ns' => $ns_dir, 'nofiles' => true));
1967
1968
    // wrap a list with the root level around the other namespaces
1969
    array_unshift($data, array('level' => 0, 'id' => '', 'open' =>'true',
1970
                               'label' => '['.$lang['mediaroot'].']'));
1971
1972
    // insert the current ns into the hierarchy if it isn't already part of it
1973
    $ns_parts = explode(':', $ns);
1974
    $tmp_ns = '';
1975
    $pos = 0;
1976
    foreach ($ns_parts as $level => $part) {
1977
        if ($tmp_ns) $tmp_ns .= ':'.$part;
1978
        else $tmp_ns = $part;
1979
1980
        // find the namespace parts or insert them
1981
        while ($data[$pos]['id'] != $tmp_ns) {
1982
            if (
1983
                $pos >= count($data) ||
1984
                (
1985
                    $data[$pos]['level'] <= $level+1 &&
1986
                    strnatcmp(utf8_encodeFN($data[$pos]['id']), utf8_encodeFN($tmp_ns)) > 0
1987
                )
1988
            ) {
1989
                array_splice($data, $pos, 0, array(array('level' => $level+1, 'id' => $tmp_ns, 'open' => 'true')));
1990
                break;
1991
            }
1992
            ++$pos;
1993
        }
1994
    }
1995
1996
    echo html_buildlist($data,'idx','media_nstree_item','media_nstree_li');
1997
}
1998
1999
/**
2000
 * Userfunction for html_buildlist
2001
 *
2002
 * Prints a media namespace tree item
2003
 *
2004
 * @author Andreas Gohr <[email protected]>
2005
 *
2006
 * @param array $item
2007
 * @return string html
2008
 */
2009
function media_nstree_item($item){
2010
    global $INPUT;
2011
    $pos   = strrpos($item['id'], ':');
2012
    $label = substr($item['id'], $pos > 0 ? $pos + 1 : 0);
2013
    if(empty($item['label'])) $item['label'] = $label;
2014
2015
    $ret  = '';
2016
    if (!($INPUT->str('do') == 'media'))
2017
    $ret .= '<a href="'.DOKU_BASE.'lib/exe/mediamanager.php?ns='.idfilter($item['id']).'" class="idx_dir">';
2018
    else $ret .= '<a href="'.media_managerURL(array('ns' => idfilter($item['id'], false), 'tab_files' => 'files'))
2019
        .'" class="idx_dir">';
2020
    $ret .= $item['label'];
2021
    $ret .= '</a>';
2022
    return $ret;
2023
}
2024
2025
/**
2026
 * Userfunction for html_buildlist
2027
 *
2028
 * Prints a media namespace tree item opener
2029
 *
2030
 * @author Andreas Gohr <[email protected]>
2031
 *
2032
 * @param array $item
2033
 * @return string html
2034
 */
2035
function media_nstree_li($item){
2036
    $class='media level'.$item['level'];
2037
    if($item['open']){
2038
        $class .= ' open';
2039
        $img   = DOKU_BASE.'lib/images/minus.gif';
2040
        $alt   = '−';
2041
    }else{
2042
        $class .= ' closed';
2043
        $img   = DOKU_BASE.'lib/images/plus.gif';
2044
        $alt   = '+';
2045
    }
2046
    // TODO: only deliver an image if it actually has a subtree...
2047
    return '<li class="'.$class.'">'.
2048
        '<img src="'.$img.'" alt="'.$alt.'" />';
2049
}
2050
2051
/**
2052
 * Resizes the given image to the given size
2053
 *
2054
 * @author  Andreas Gohr <[email protected]>
2055
 *
2056
 * @param string $file filename, path to file
2057
 * @param string $ext  extension
2058
 * @param int    $w    desired width
2059
 * @param int    $h    desired height
2060
 * @return string path to resized or original size if failed
2061
 */
2062
function media_resize_image($file, $ext, $w, $h=0){
2063
    global $conf;
2064
    if(!$h) $h = $w;
2065
    // we wont scale up to infinity
2066
    if($w > 2000 || $h > 2000) return $file;
2067
2068
    //cache
2069
    $local = getCacheName($file,'.media.'.$w.'x'.$h.'.'.$ext);
2070
    $mtime = @filemtime($local); // 0 if not exists
2071
2072
    $options = [
2073
        'quality' => $conf['jpg_quality'],
2074
        'imconvert' => $conf['im_convert'],
2075
    ];
2076
2077
    if( $mtime > @filemtime($file) ) {
2078
        try {
2079
            \splitbrain\slika\Slika::run($file, $options)
2080
                                   ->autorotate()
2081
                                   ->resize($w, $h)
2082
                                   ->save($local, $ext);
2083
            if($conf['fperm']) @chmod($local, $conf['fperm']);
2084
        } catch (\splitbrain\slika\Exception $e) {
2085
            dbglog($e->getMessage());
2086
            return $file;
2087
        }
2088
    }
2089
2090
    return $local;
2091
}
2092
2093
/**
2094
 * Center crops the given image to the wanted size
2095
 *
2096
 * @author  Andreas Gohr <[email protected]>
2097
 *
2098
 * @param string $file filename, path to file
2099
 * @param string $ext  extension
2100
 * @param int    $w    desired width
2101
 * @param int    $h    desired height
2102
 * @return string path to resized or original size if failed
2103
 */
2104
function media_crop_image($file, $ext, $w, $h=0){
2105
    global $conf;
2106
    if(!$h) $h = $w;
2107
    // we wont scale up to infinity
2108
    if($w > 2000 || $h > 2000) return $file;
2109
2110
    //cache
2111
    $local = getCacheName($file,'.media.'.$w.'x'.$h.'.crop.'.$ext);
2112
    $mtime = (int) @filemtime($local); // 0 if not exists
2113
2114
    $options = [
2115
        'quality' => $conf['jpg_quality'],
2116
        'imconvert' => $conf['im_convert'],
2117
    ];
2118
2119
    if( $mtime <= (int) @filemtime($file) ) {
2120
        try {
2121
            \splitbrain\slika\Slika::run($file, $options)
2122
                                   ->autorotate()
2123
                                    ->crop($w, $h)
2124
                                    ->save($local, $ext);
2125
            if($conf['fperm']) @chmod($local, $conf['fperm']);
2126
        } catch (\splitbrain\slika\Exception $e) {
2127
            dbglog($e->getMessage());
2128
            return $file;
2129
        }
2130
    }
2131
2132
    return $local;
2133
}
2134
2135
/**
2136
 * Calculate a token to be used to verify fetch requests for resized or
2137
 * cropped images have been internally generated - and prevent external
2138
 * DDOS attacks via fetch
2139
 *
2140
 * @author Christopher Smith <[email protected]>
2141
 *
2142
 * @param string  $id    id of the image
2143
 * @param int     $w     resize/crop width
2144
 * @param int     $h     resize/crop height
2145
 * @return string token or empty string if no token required
2146
 */
2147
function media_get_token($id,$w,$h){
2148
    // token is only required for modified images
2149
    if ($w || $h || media_isexternal($id)) {
2150
        $token = $id;
2151
        if ($w) $token .= '.'.$w;
2152
        if ($h) $token .= '.'.$h;
2153
2154
        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...
2155
    }
2156
2157
    return '';
2158
}
2159
2160
/**
2161
 * Download a remote file and return local filename
2162
 *
2163
 * returns false if download fails. Uses cached file if available and
2164
 * wanted
2165
 *
2166
 * @author  Andreas Gohr <[email protected]>
2167
 * @author  Pavel Vitis <[email protected]>
2168
 *
2169
 * @param string $url
2170
 * @param string $ext   extension
2171
 * @param int    $cache cachetime in seconds
2172
 * @return false|string path to cached file
2173
 */
2174
function media_get_from_URL($url,$ext,$cache){
2175
    global $conf;
2176
2177
    // if no cache or fetchsize just redirect
2178
    if ($cache==0)           return false;
2179
    if (!$conf['fetchsize']) return false;
2180
2181
    $local = getCacheName(strtolower($url),".media.$ext");
2182
    $mtime = @filemtime($local); // 0 if not exists
2183
2184
    //decide if download needed:
2185
    if(($mtime == 0) || // cache does not exist
2186
        ($cache != -1 && $mtime < time() - $cache) // 'recache' and cache has expired
2187
    ) {
2188
        if(media_image_download($url, $local)) {
2189
            return $local;
2190
        } else {
2191
            return false;
2192
        }
2193
    }
2194
2195
    //if cache exists use it else
2196
    if($mtime) return $local;
2197
2198
    //else return false
2199
    return false;
2200
}
2201
2202
/**
2203
 * Download image files
2204
 *
2205
 * @author Andreas Gohr <[email protected]>
2206
 *
2207
 * @param string $url
2208
 * @param string $file path to file in which to put the downloaded content
2209
 * @return bool
2210
 */
2211
function media_image_download($url,$file){
2212
    global $conf;
2213
    $http = new DokuHTTPClient();
2214
    $http->keep_alive = false; // we do single ops here, no need for keep-alive
2215
2216
    $http->max_bodysize = $conf['fetchsize'];
2217
    $http->timeout = 25; //max. 25 sec
2218
    $http->header_regexp = '!\r\nContent-Type: image/(jpe?g|gif|png)!i';
2219
2220
    $data = $http->get($url);
2221
    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...
2222
2223
    $fileexists = file_exists($file);
2224
    $fp = @fopen($file,"w");
2225
    if(!$fp) return false;
2226
    fwrite($fp,$data);
2227
    fclose($fp);
2228
    if(!$fileexists and $conf['fperm']) chmod($file, $conf['fperm']);
2229
2230
    // check if it is really an image
2231
    $info = @getimagesize($file);
2232
    if(!$info){
2233
        @unlink($file);
2234
        return false;
2235
    }
2236
2237
    return true;
2238
}
2239
2240
/**
2241
 * resize images using external ImageMagick convert program
2242
 *
2243
 * @author Pavel Vitis <[email protected]>
2244
 * @author Andreas Gohr <[email protected]>
2245
 *
2246
 * @param string $ext     extension
2247
 * @param string $from    filename path to file
2248
 * @param int    $from_w  original width
2249
 * @param int    $from_h  original height
2250
 * @param string $to      path to resized file
2251
 * @param int    $to_w    desired width
2252
 * @param int    $to_h    desired height
2253
 * @return bool
2254
 */
2255
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...
2256
    global $conf;
2257
2258
    // check if convert is configured
2259
    if(!$conf['im_convert']) return false;
2260
2261
    // prepare command
2262
    $cmd  = $conf['im_convert'];
2263
    $cmd .= ' -resize '.$to_w.'x'.$to_h.'!';
2264
    if ($ext == 'jpg' || $ext == 'jpeg') {
2265
        $cmd .= ' -quality '.$conf['jpg_quality'];
2266
    }
2267
    $cmd .= " $from $to";
2268
2269
    @exec($cmd,$out,$retval);
2270
    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...
2271
    return false;
2272
}
2273
2274
/**
2275
 * crop images using external ImageMagick convert program
2276
 *
2277
 * @author Andreas Gohr <[email protected]>
2278
 *
2279
 * @param string $ext     extension
2280
 * @param string $from    filename path to file
2281
 * @param int    $from_w  original width
2282
 * @param int    $from_h  original height
2283
 * @param string $to      path to resized file
2284
 * @param int    $to_w    desired width
2285
 * @param int    $to_h    desired height
2286
 * @param int    $ofs_x   offset of crop centre
2287
 * @param int    $ofs_y   offset of crop centre
2288
 * @return bool
2289
 * @deprecated 2020-09-01
2290
 */
2291
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...
2292
    global $conf;
2293
    dbg_deprecated('splitbrain\\Slika');
2294
2295
    // check if convert is configured
2296
    if(!$conf['im_convert']) return false;
2297
2298
    // prepare command
2299
    $cmd  = $conf['im_convert'];
2300
    $cmd .= ' -crop '.$to_w.'x'.$to_h.'+'.$ofs_x.'+'.$ofs_y;
2301
    if ($ext == 'jpg' || $ext == 'jpeg') {
2302
        $cmd .= ' -quality '.$conf['jpg_quality'];
2303
    }
2304
    $cmd .= " $from $to";
2305
2306
    @exec($cmd,$out,$retval);
2307
    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...
2308
    return false;
2309
}
2310
2311
/**
2312
 * resize or crop images using PHP's libGD support
2313
 *
2314
 * @author Andreas Gohr <[email protected]>
2315
 * @author Sebastian Wienecke <[email protected]>
2316
 *
2317
 * @param string $ext     extension
2318
 * @param string $from    filename path to file
2319
 * @param int    $from_w  original width
2320
 * @param int    $from_h  original height
2321
 * @param string $to      path to resized file
2322
 * @param int    $to_w    desired width
2323
 * @param int    $to_h    desired height
2324
 * @param int    $ofs_x   offset of crop centre
2325
 * @param int    $ofs_y   offset of crop centre
2326
 * @return bool
2327
 * @deprecated 2020-09-01
2328
 */
2329
function media_resize_imageGD($ext,$from,$from_w,$from_h,$to,$to_w,$to_h,$ofs_x=0,$ofs_y=0){
2330
    global $conf;
2331
    dbg_deprecated('splitbrain\\Slika');
2332
2333
    if($conf['gdlib'] < 1) return false; //no GDlib available or wanted
2334
2335
    // check available memory
2336
    if(!is_mem_available(($from_w * $from_h * 4) + ($to_w * $to_h * 4))){
2337
        return false;
2338
    }
2339
2340
    // create an image of the given filetype
2341
    $image = false;
2342
    if ($ext == 'jpg' || $ext == 'jpeg'){
2343
        if(!function_exists("imagecreatefromjpeg")) return false;
2344
        $image = @imagecreatefromjpeg($from);
2345
    }elseif($ext == 'png') {
2346
        if(!function_exists("imagecreatefrompng")) return false;
2347
        $image = @imagecreatefrompng($from);
2348
2349
    }elseif($ext == 'gif') {
2350
        if(!function_exists("imagecreatefromgif")) return false;
2351
        $image = @imagecreatefromgif($from);
2352
    }
2353
    if(!$image) return false;
2354
2355
    $newimg = false;
2356
    if(($conf['gdlib']>1) && function_exists("imagecreatetruecolor") && $ext != 'gif'){
2357
        $newimg = @imagecreatetruecolor ($to_w, $to_h);
2358
    }
2359
    if(!$newimg) $newimg = @imagecreate($to_w, $to_h);
2360
    if(!$newimg){
2361
        imagedestroy($image);
2362
        return false;
2363
    }
2364
2365
    //keep png alpha channel if possible
2366
    if($ext == 'png' && $conf['gdlib']>1 && function_exists('imagesavealpha')){
2367
        imagealphablending($newimg, false);
2368
        imagesavealpha($newimg,true);
2369
    }
2370
2371
    //keep gif transparent color if possible
2372
    if($ext == 'gif' && function_exists('imagefill') && function_exists('imagecolorallocate')) {
2373
        if(function_exists('imagecolorsforindex') && function_exists('imagecolortransparent')) {
2374
            $transcolorindex = @imagecolortransparent($image);
2375
            if($transcolorindex >= 0 ) { //transparent color exists
2376
                $transcolor = @imagecolorsforindex($image, $transcolorindex);
2377
                $transcolorindex = @imagecolorallocate(
2378
                    $newimg,
2379
                    $transcolor['red'],
2380
                    $transcolor['green'],
2381
                    $transcolor['blue']
2382
                );
2383
                @imagefill($newimg, 0, 0, $transcolorindex);
2384
                @imagecolortransparent($newimg, $transcolorindex);
2385
            }else{ //filling with white
2386
                $whitecolorindex = @imagecolorallocate($newimg, 255, 255, 255);
2387
                @imagefill($newimg, 0, 0, $whitecolorindex);
2388
            }
2389
        }else{ //filling with white
2390
            $whitecolorindex = @imagecolorallocate($newimg, 255, 255, 255);
2391
            @imagefill($newimg, 0, 0, $whitecolorindex);
2392
        }
2393
    }
2394
2395
    //try resampling first
2396
    if(function_exists("imagecopyresampled")){
2397
        if(!@imagecopyresampled($newimg, $image, 0, 0, $ofs_x, $ofs_y, $to_w, $to_h, $from_w, $from_h)) {
2398
            imagecopyresized($newimg, $image, 0, 0, $ofs_x, $ofs_y, $to_w, $to_h, $from_w, $from_h);
2399
        }
2400
    }else{
2401
        imagecopyresized($newimg, $image, 0, 0, $ofs_x, $ofs_y, $to_w, $to_h, $from_w, $from_h);
2402
    }
2403
2404
    $okay = false;
2405
    if ($ext == 'jpg' || $ext == 'jpeg'){
2406
        if(!function_exists('imagejpeg')){
2407
            $okay = false;
2408
        }else{
2409
            $okay = imagejpeg($newimg, $to, $conf['jpg_quality']);
2410
        }
2411
    }elseif($ext == 'png') {
2412
        if(!function_exists('imagepng')){
2413
            $okay = false;
2414
        }else{
2415
            $okay =  imagepng($newimg, $to);
2416
        }
2417
    }elseif($ext == 'gif') {
2418
        if(!function_exists('imagegif')){
2419
            $okay = false;
2420
        }else{
2421
            $okay = imagegif($newimg, $to);
2422
        }
2423
    }
2424
2425
    // destroy GD image ressources
2426
    if($image) imagedestroy($image);
2427
    if($newimg) imagedestroy($newimg);
2428
2429
    return $okay;
2430
}
2431
2432
/**
2433
 * Return other media files with the same base name
2434
 * but different extensions.
2435
 *
2436
 * @param string   $src     - ID of media file
2437
 * @param string[] $exts    - alternative extensions to find other files for
2438
 * @return array            - array(mime type => file ID)
2439
 *
2440
 * @author Anika Henke <[email protected]>
2441
 */
2442
function media_alternativefiles($src, $exts){
2443
2444
    $files = array();
2445
    list($srcExt, /* $srcMime */) = mimetype($src);
2446
    $filebase = substr($src, 0, -1 * (strlen($srcExt)+1));
2447
2448
    foreach($exts as $ext) {
2449
        $fileid = $filebase.'.'.$ext;
2450
        $file = mediaFN($fileid);
2451
        if(file_exists($file)) {
2452
            list(/* $fileExt */, $fileMime) = mimetype($file);
2453
            $files[$fileMime] = $fileid;
2454
        }
2455
    }
2456
    return $files;
2457
}
2458
2459
/**
2460
 * Check if video/audio is supported to be embedded.
2461
 *
2462
 * @param string $mime      - mimetype of media file
2463
 * @param string $type      - type of media files to check ('video', 'audio', or null for all)
2464
 * @return boolean
2465
 *
2466
 * @author Anika Henke <[email protected]>
2467
 */
2468
function media_supportedav($mime, $type=NULL){
2469
    $supportedAudio = array(
2470
        'ogg' => 'audio/ogg',
2471
        'mp3' => 'audio/mpeg',
2472
        'wav' => 'audio/wav',
2473
    );
2474
    $supportedVideo = array(
2475
        'webm' => 'video/webm',
2476
        'ogv' => 'video/ogg',
2477
        'mp4' => 'video/mp4',
2478
    );
2479
    if ($type == 'audio') {
2480
        $supportedAv = $supportedAudio;
2481
    } elseif ($type == 'video') {
2482
        $supportedAv = $supportedVideo;
2483
    } else {
2484
        $supportedAv = array_merge($supportedAudio, $supportedVideo);
2485
    }
2486
    return in_array($mime, $supportedAv);
2487
}
2488
2489
/**
2490
 * Return track media files with the same base name
2491
 * but extensions that indicate kind and lang.
2492
 * ie for foo.webm search foo.sub.lang.vtt, foo.cap.lang.vtt...
2493
 *
2494
 * @param string   $src     - ID of media file
2495
 * @return array            - array(mediaID => array( kind, srclang ))
2496
 *
2497
 * @author Schplurtz le Déboulonné <[email protected]>
2498
 */
2499
function media_trackfiles($src){
2500
    $kinds=array(
2501
        'sub' => 'subtitles',
2502
        'cap' => 'captions',
2503
        'des' => 'descriptions',
2504
        'cha' => 'chapters',
2505
        'met' => 'metadata'
2506
    );
2507
2508
    $files = array();
2509
    $re='/\\.(sub|cap|des|cha|met)\\.([^.]+)\\.vtt$/';
2510
    $baseid=pathinfo($src, PATHINFO_FILENAME);
2511
    $pattern=mediaFN($baseid).'.*.*.vtt';
2512
    $list=glob($pattern);
2513
    foreach($list as $track) {
2514
        if(preg_match($re, $track, $matches)){
2515
            $files[$baseid.'.'.$matches[1].'.'.$matches[2].'.vtt']=array(
2516
                $kinds[$matches[1]],
2517
                $matches[2],
2518
            );
2519
        }
2520
    }
2521
    return $files;
2522
}
2523
2524
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
2525