Failed Conditions
Pull Request — master (#3198)
by
unknown
03:13
created

media.php ➔ media_preview_buttons()   C

Complexity

Conditions 11
Paths 16

Size

Total Lines 55

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 11
nc 16
nop 3
dl 0
loc 55
rs 6.8351
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

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

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

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

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

// Bar.php
namespace OtherDir;

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

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

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

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

// Bar.php
namespace OtherDir;

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

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

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

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

// Bar.php
namespace OtherDir;

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

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

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

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

// Bar.php
namespace OtherDir;

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

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
182
                $p['name'],
183
                ($lang[$field[1]] ? $lang[$field[1]] : $field[1] . ':')
184
            )->id($p['id'])->addClass($p['class'])->val($value);
185
        } else {
186
            $form->addTextarea($p['name'], $lang[$field[1]])->id($p['id'])
187
                ->val(formText($value))
188
                ->addClass($p['class'])
189
                ->attr('rows', '6')->attr('cols', '50');
190
        }
191
        $form->addTagClose('div');
192
    }
193
    $form->addTagOpen('div')->addClass('buttons');
194
    $form->addButton('mediado[save]', $lang['btn_save'])->attr('type', 'submit')
195
        ->attrs(['accesskey' => 's']);
196
    $form->addTagClose('div');
197
198
    $form->addTagClose('div');
199
    echo $form->toHTML();
200
    return true;
201
}
202
203
/**
204
 * Convenience function to check if a media file is still in use
205
 *
206
 * @author Michael Klier <[email protected]>
207
 *
208
 * @param string $id media id
209
 * @return array|bool
210
 */
211
function media_inuse($id) {
212
    global $conf;
213
214
    if($conf['refcheck']){
215
        $mediareferences = ft_mediause($id,true);
216
        if(!count($mediareferences)) {
217
            return false;
218
        } else {
219
            return $mediareferences;
220
        }
221
    } else {
222
        return false;
223
    }
224
}
225
226
/**
227
 * Handles media file deletions
228
 *
229
 * If configured, checks for media references before deletion
230
 *
231
 * @author             Andreas Gohr <[email protected]>
232
 *
233
 * @param string $id media id
234
 * @param int $auth no longer used
235
 * @return int One of: 0,
236
 *                     DOKU_MEDIA_DELETED,
237
 *                     DOKU_MEDIA_DELETED | DOKU_MEDIA_EMPTY_NS,
238
 *                     DOKU_MEDIA_NOT_AUTH,
239
 *                     DOKU_MEDIA_INUSE
240
 */
241
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...
242
    global $lang;
243
    $auth = auth_quickaclcheck(ltrim(getNS($id).':*', ':'));
244
    if($auth < AUTH_DELETE) return DOKU_MEDIA_NOT_AUTH;
245
    if(media_inuse($id)) return DOKU_MEDIA_INUSE;
246
247
    $file = mediaFN($id);
248
249
    // trigger an event - MEDIA_DELETE_FILE
250
    $data = array();
251
    $data['id']   = $id;
252
    $data['name'] = \dokuwiki\Utf8\PhpString::basename($file);
253
    $data['path'] = $file;
254
    $data['size'] = (file_exists($file)) ? filesize($file) : 0;
255
256
    $data['unl'] = false;
257
    $data['del'] = false;
258
    $evt = new Event('MEDIA_DELETE_FILE',$data);
259
    if ($evt->advise_before()) {
260
        $old = @filemtime($file);
261
        if(!file_exists(mediaFN($id, $old)) && file_exists($file)) {
262
            // add old revision to the attic
263
            media_saveOldRevision($id);
264
        }
265
266
        $data['unl'] = @unlink($file);
267
        if($data['unl']) {
268
            $sizechange = 0 - $data['size'];
269
            addMediaLogEntry(time(), $id, DOKU_CHANGE_TYPE_DELETE, $lang['deleted'], '', null, $sizechange);
270
271
            $data['del'] = io_sweepNS($id, 'mediadir');
272
        }
273
    }
274
    $evt->advise_after();
275
    unset($evt);
276
277
    if($data['unl'] && $data['del']){
278
        return DOKU_MEDIA_DELETED | DOKU_MEDIA_EMPTY_NS;
279
    }
280
281
    return $data['unl'] ? DOKU_MEDIA_DELETED : 0;
282
}
283
284
/**
285
 * Handle file uploads via XMLHttpRequest
286
 *
287
 * @param string $ns   target namespace
288
 * @param int    $auth current auth check result
289
 * @return false|string false on error, id of the new file on success
290
 */
291
function media_upload_xhr($ns,$auth){
292
    if(!checkSecurityToken()) return false;
293
    global $INPUT;
294
295
    $id = $INPUT->get->str('qqfile');
296
    list($ext,$mime) = mimetype($id);
297
    $input = fopen("php://input", "r");
298
    if (!($tmp = io_mktmpdir())) return false;
299
    $path = $tmp.'/'.md5($id);
300
    $target = fopen($path, "w");
301
    $realSize = stream_copy_to_stream($input, $target);
302
    fclose($target);
303
    fclose($input);
304
    if (isset($_SERVER["CONTENT_LENGTH"]) && ($realSize != (int)$_SERVER["CONTENT_LENGTH"])){
305
        unlink($path);
306
        return false;
307
    }
308
309
    $res = media_save(
310
        array('name' => $path,
311
            'mime' => $mime,
312
            'ext'  => $ext),
313
        $ns.':'.$id,
314
        (($INPUT->get->str('ow') == 'true') ? true : false),
315
        $auth,
316
        'copy'
317
    );
318
    unlink($path);
319
    if ($tmp) io_rmdir($tmp, true);
320
    if (is_array($res)) {
321
        msg($res[0], $res[1]);
322
        return false;
323
    }
324
    return $res;
325
}
326
327
/**
328
 * Handles media file uploads
329
 *
330
 * @author Andreas Gohr <[email protected]>
331
 * @author Michael Klier <[email protected]>
332
 *
333
 * @param string     $ns    target namespace
334
 * @param int        $auth  current auth check result
335
 * @param bool|array $file  $_FILES member, $_FILES['upload'] if false
336
 * @return false|string false on error, id of the new file on success
337
 */
338
function media_upload($ns,$auth,$file=false){
339
    if(!checkSecurityToken()) return false;
340
    global $lang;
341
    global $INPUT;
342
343
    // get file and id
344
    $id   = $INPUT->post->str('mediaid');
345
    if (!$file) $file = $_FILES['upload'];
346
    if(empty($id)) $id = $file['name'];
347
348
    // check for errors (messages are done in lib/exe/mediamanager.php)
349
    if($file['error']) return false;
350
351
    // check extensions
352
    list($fext,$fmime) = mimetype($file['name']);
353
    list($iext,$imime) = mimetype($id);
354
    if($fext && !$iext){
355
        // no extension specified in id - read original one
356
        $id   .= '.'.$fext;
357
        $imime = $fmime;
358
    }elseif($fext && $fext != $iext){
359
        // extension was changed, print warning
360
        msg(sprintf($lang['mediaextchange'],$fext,$iext));
361
    }
362
363
    $res = media_save(array('name' => $file['tmp_name'],
364
                            'mime' => $imime,
365
                            'ext'  => $iext), $ns.':'.$id,
366
                      $INPUT->post->bool('ow'), $auth, 'copy_uploaded_file');
367
    if (is_array($res)) {
368
        msg($res[0], $res[1]);
369
        return false;
370
    }
371
    return $res;
372
}
373
374
/**
375
 * An alternative to move_uploaded_file that copies
376
 *
377
 * Using copy, makes sure any setgid bits on the media directory are honored
378
 *
379
 * @see   move_uploaded_file()
380
 *
381
 * @param string $from
382
 * @param string $to
383
 * @return bool
384
 */
385
function copy_uploaded_file($from, $to){
386
    if(!is_uploaded_file($from)) return false;
387
    $ok = copy($from, $to);
388
    @unlink($from);
389
    return $ok;
390
}
391
392
/**
393
 * This generates an action event and delegates to _media_upload_action().
394
 * Action plugins are allowed to pre/postprocess the uploaded file.
395
 * (The triggered event is preventable.)
396
 *
397
 * Event data:
398
 * $data[0]     fn_tmp:    the temporary file name (read from $_FILES)
399
 * $data[1]     fn:        the file name of the uploaded file
400
 * $data[2]     id:        the future directory id of the uploaded file
401
 * $data[3]     imime:     the mimetype of the uploaded file
402
 * $data[4]     overwrite: if an existing file is going to be overwritten
403
 * $data[5]     move:      name of function that performs move/copy/..
404
 *
405
 * @triggers MEDIA_UPLOAD_FINISH
406
 *
407
 * @param array  $file
408
 * @param string $id   media id
409
 * @param bool   $ow   overwrite?
410
 * @param int    $auth permission level
411
 * @param string $move name of functions that performs move/copy/..
412
 * @return false|array|string
413
 */
414
function media_save($file, $id, $ow, $auth, $move) {
415
    if($auth < AUTH_UPLOAD) {
416
        return array("You don't have permissions to upload files.", -1);
417
    }
418
419
    if (!isset($file['mime']) || !isset($file['ext'])) {
420
        list($ext, $mime) = mimetype($id);
421
        if (!isset($file['mime'])) {
422
            $file['mime'] = $mime;
423
        }
424
        if (!isset($file['ext'])) {
425
            $file['ext'] = $ext;
426
        }
427
    }
428
429
    global $lang, $conf;
430
431
    // get filename
432
    $id   = cleanID($id);
433
    $fn   = mediaFN($id);
434
435
    // get filetype regexp
436
    $types = array_keys(getMimeTypes());
437
    $types = array_map(
438
        function ($q) {
439
            return preg_quote($q, "/");
440
        },
441
        $types
442
    );
443
    $regex = join('|',$types);
444
445
    // because a temp file was created already
446
    if(!preg_match('/\.('.$regex.')$/i',$fn)) {
447
        return array($lang['uploadwrong'],-1);
448
    }
449
450
    //check for overwrite
451
    $overwrite = file_exists($fn);
452
    $auth_ow = (($conf['mediarevisions']) ? AUTH_UPLOAD : AUTH_DELETE);
453
    if($overwrite && (!$ow || $auth < $auth_ow)) {
454
        return array($lang['uploadexist'], 0);
455
    }
456
    // check for valid content
457
    $ok = media_contentcheck($file['name'], $file['mime']);
458
    if($ok == -1){
459
        return array(sprintf($lang['uploadbadcontent'],'.' . $file['ext']),-1);
460
    }elseif($ok == -2){
461
        return array($lang['uploadspam'],-1);
462
    }elseif($ok == -3){
463
        return array($lang['uploadxss'],-1);
464
    }
465
466
    // prepare event data
467
    $data = array();
468
    $data[0] = $file['name'];
469
    $data[1] = $fn;
470
    $data[2] = $id;
471
    $data[3] = $file['mime'];
472
    $data[4] = $overwrite;
473
    $data[5] = $move;
474
475
    // trigger event
476
    return Event::createAndTrigger('MEDIA_UPLOAD_FINISH', $data, '_media_upload_action', true);
477
}
478
479
/**
480
 * Callback adapter for media_upload_finish() triggered by MEDIA_UPLOAD_FINISH
481
 *
482
 * @author Michael Klier <[email protected]>
483
 *
484
 * @param array $data event data
485
 * @return false|array|string
486
 */
487
function _media_upload_action($data) {
488
    // fixme do further sanity tests of given data?
489
    if(is_array($data) && count($data)===6) {
490
        return media_upload_finish($data[0], $data[1], $data[2], $data[3], $data[4], $data[5]);
491
    } else {
492
        return false; //callback error
493
    }
494
}
495
496
/**
497
 * Saves an uploaded media file
498
 *
499
 * @author Andreas Gohr <[email protected]>
500
 * @author Michael Klier <[email protected]>
501
 * @author Kate Arzamastseva <[email protected]>
502
 *
503
 * @param string $fn_tmp
504
 * @param string $fn
505
 * @param string $id        media id
506
 * @param string $imime     mime type
507
 * @param bool   $overwrite overwrite existing?
508
 * @param string $move      function name
509
 * @return array|string
510
 */
511
function media_upload_finish($fn_tmp, $fn, $id, $imime, $overwrite, $move = 'move_uploaded_file') {
512
    global $conf;
513
    global $lang;
514
    global $REV;
515
516
    $old = @filemtime($fn);
517
    if(!file_exists(mediaFN($id, $old)) && file_exists($fn)) {
518
        // add old revision to the attic if missing
519
        media_saveOldRevision($id);
520
    }
521
522
    // prepare directory
523
    io_createNamespace($id, 'media');
524
525
    $filesize_old = file_exists($fn) ? filesize($fn) : 0;
526
527
    if($move($fn_tmp, $fn)) {
528
        @clearstatcache(true,$fn);
529
        $new = @filemtime($fn);
530
        // Set the correct permission here.
531
        // Always chmod media because they may be saved with different permissions than expected from the php umask.
532
        // (Should normally chmod to $conf['fperm'] only if $conf['fperm'] is set.)
533
        chmod($fn, $conf['fmode']);
534
        msg($lang['uploadsucc'],1);
535
        media_notify($id,$fn,$imime,$old,$new);
536
        // add a log entry to the media changelog
537
        $filesize_new = filesize($fn);
538
        $sizechange = $filesize_new - $filesize_old;
539
        if($REV) {
540
            addMediaLogEntry(
541
                $new,
542
                $id,
543
                DOKU_CHANGE_TYPE_REVERT,
544
                sprintf($lang['restored'], dformat($REV)),
545
                $REV,
546
                null,
547
                $sizechange
548
            );
549
        } elseif($overwrite) {
550
            addMediaLogEntry($new, $id, DOKU_CHANGE_TYPE_EDIT, '', '', null, $sizechange);
551
        } else {
552
            addMediaLogEntry($new, $id, DOKU_CHANGE_TYPE_CREATE, $lang['created'], '', null, $sizechange);
553
        }
554
        return $id;
555
    }else{
556
        return array($lang['uploadfail'],-1);
557
    }
558
}
559
560
/**
561
 * Moves the current version of media file to the media_attic
562
 * directory
563
 *
564
 * @author Kate Arzamastseva <[email protected]>
565
 *
566
 * @param string $id
567
 * @return int - revision date
568
 */
569
function media_saveOldRevision($id){
570
    global $conf, $lang;
571
572
    $oldf = mediaFN($id);
573
    if(!file_exists($oldf)) return '';
574
    $date = filemtime($oldf);
575
    if (!$conf['mediarevisions']) return $date;
576
577
    $medialog = new MediaChangeLog($id);
578
    if (!$medialog->getRevisionInfo($date)) {
579
        // there was an external edit,
580
        // there is no log entry for current version of file
581
        $sizechange = filesize($oldf);
582
        if(!file_exists(mediaMetaFN($id, '.changes'))) {
583
            addMediaLogEntry($date, $id, DOKU_CHANGE_TYPE_CREATE, $lang['created'], '', null, $sizechange);
584
        } else {
585
            $oldRev = $medialog->getRevisions(-1, 1); // from changelog
586
            $oldRev = (int) (empty($oldRev) ? 0 : $oldRev[0]);
587
            $filesize_old = filesize(mediaFN($id, $oldRev));
588
            $sizechange = $sizechange - $filesize_old;
589
590
            addMediaLogEntry($date, $id, DOKU_CHANGE_TYPE_EDIT, '', '', null, $sizechange);
591
        }
592
    }
593
594
    $newf = mediaFN($id,$date);
595
    io_makeFileDir($newf);
596
    if(copy($oldf, $newf)) {
597
        // Set the correct permission here.
598
        // Always chmod media because they may be saved with different permissions than expected from the php umask.
599
        // (Should normally chmod to $conf['fperm'] only if $conf['fperm'] is set.)
600
        chmod($newf, $conf['fmode']);
601
    }
602
    return $date;
603
}
604
605
/**
606
 * This function checks if the uploaded content is really what the
607
 * mimetype says it is. We also do spam checking for text types here.
608
 *
609
 * We need to do this stuff because we can not rely on the browser
610
 * to do this check correctly. Yes, IE is broken as usual.
611
 *
612
 * @author Andreas Gohr <[email protected]>
613
 * @link   http://www.splitbrain.org/blog/2007-02/12-internet_explorer_facilitates_cross_site_scripting
614
 * @fixme  check all 26 magic IE filetypes here?
615
 *
616
 * @param string $file path to file
617
 * @param string $mime mimetype
618
 * @return int
619
 */
620
function media_contentcheck($file,$mime){
621
    global $conf;
622
    if($conf['iexssprotect']){
623
        $fh = @fopen($file, 'rb');
624
        if($fh){
625
            $bytes = fread($fh, 256);
626
            fclose($fh);
627
            if(preg_match('/<(script|a|img|html|body|iframe)[\s>]/i',$bytes)){
628
                return -3; //XSS: possibly malicious content
629
            }
630
        }
631
    }
632
    if(substr($mime,0,6) == 'image/'){
633
        $info = @getimagesize($file);
634
        if($mime == 'image/gif' && $info[2] != 1){
635
            return -1; // uploaded content did not match the file extension
636
        }elseif($mime == 'image/jpeg' && $info[2] != 2){
637
            return -1;
638
        }elseif($mime == 'image/png' && $info[2] != 3){
639
            return -1;
640
        }
641
        # fixme maybe check other images types as well
642
    }elseif(substr($mime,0,5) == 'text/'){
643
        global $TEXT;
644
        $TEXT = io_readFile($file);
645
        if(checkwordblock()){
646
            return -2; //blocked by the spam blacklist
647
        }
648
    }
649
    return 0;
650
}
651
652
/**
653
 * Send a notify mail on uploads
654
 *
655
 * @author Andreas Gohr <[email protected]>
656
 *
657
 * @param string   $id      media id
658
 * @param string   $file    path to file
659
 * @param string   $mime    mime type
660
 * @param bool|int $old_rev revision timestamp or false
661
 * @return bool
662
 */
663
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...
664
    global $conf;
665
    if(empty($conf['notify'])) return false; //notify enabled?
666
667
    $subscription = new MediaSubscriptionSender();
668
    return $subscription->sendMediaDiff($conf['notify'], 'uploadmail', $id, $old_rev, $current_rev);
669
}
670
671
/**
672
 * List all files in a given Media namespace
673
 *
674
 * @param string      $ns             namespace
675
 * @param null|int    $auth           permission level
676
 * @param string      $jump           id
677
 * @param bool        $fullscreenview
678
 * @param bool|string $sort           sorting order, false skips sorting
679
 */
680
function media_filelist($ns,$auth=null,$jump='',$fullscreenview=false,$sort=false){
681
    global $conf;
682
    global $lang;
683
    $ns = cleanID($ns);
684
685
    // check auth our self if not given (needed for ajax calls)
686
    if(is_null($auth)) $auth = auth_quickaclcheck("$ns:*");
687
688
    if (!$fullscreenview) echo '<h1 id="media__ns">:'.hsc($ns).'</h1>'.NL;
689
690
    if($auth < AUTH_READ){
691
        // FIXME: print permission warning here instead?
692
        echo '<div class="nothing">'.$lang['nothingfound'].'</div>'.NL;
693
    }else{
694
        if (!$fullscreenview) {
695
            media_uploadform($ns, $auth);
696
            media_searchform($ns);
697
        }
698
699
        $dir = utf8_encodeFN(str_replace(':','/',$ns));
700
        $data = array();
701
        search($data,$conf['mediadir'],'search_media',
702
                array('showmsg'=>true,'depth'=>1),$dir,1,$sort);
703
704
        if(!count($data)){
705
            echo '<div class="nothing">'.$lang['nothingfound'].'</div>'.NL;
706
        }else {
707
            if ($fullscreenview) {
708
                echo '<ul class="' . _media_get_list_type() . '">';
709
            }
710
            foreach($data as $item){
711
                if (!$fullscreenview) {
712
                    media_printfile($item,$auth,$jump);
713
                } else {
714
                    media_printfile_thumbs($item,$auth,$jump);
715
                }
716
            }
717
            if ($fullscreenview) echo '</ul>'.NL;
718
        }
719
    }
720
}
721
722
/**
723
 * Prints tabs for files list actions
724
 *
725
 * @author Kate Arzamastseva <[email protected]>
726
 * @author Adrian Lang <[email protected]>
727
 *
728
 * @param string $selected_tab - opened tab
729
 */
730
731
function media_tabs_files($selected_tab = ''){
732
    global $lang;
733
    $tabs = array();
734
    foreach(array('files'  => 'mediaselect',
735
                  'upload' => 'media_uploadtab',
736
                  'search' => 'media_searchtab') as $tab => $caption) {
737
        $tabs[$tab] = array('href'    => media_managerURL(['tab_files' => $tab], '&'),
738
                            'caption' => $lang[$caption]);
739
    }
740
741
    html_tabs($tabs, $selected_tab);
742
}
743
744
/**
745
 * Prints tabs for files details actions
746
 *
747
 * @author Kate Arzamastseva <[email protected]>
748
 * @param string $image filename of the current image
749
 * @param string $selected_tab opened tab
750
 */
751
function media_tabs_details($image, $selected_tab = '') {
752
    global $lang, $conf;
753
754
    $tabs = array();
755
    $tabs['view'] = array('href'    => media_managerURL(['tab_details' => 'view'], '&'),
756
                          'caption' => $lang['media_viewtab']);
757
758
    list(, $mime) = mimetype($image);
759
    if ($mime == 'image/jpeg' && file_exists(mediaFN($image))) {
760
        $tabs['edit'] = array('href'    => media_managerURL(['tab_details' => 'edit'], '&'),
761
                              'caption' => $lang['media_edittab']);
762
    }
763
    if ($conf['mediarevisions']) {
764
        $tabs['history'] = array('href'    => media_managerURL(['tab_details' => 'history'], '&'),
765
                                 'caption' => $lang['media_historytab']);
766
    }
767
768
    html_tabs($tabs, $selected_tab);
769
}
770
771
/**
772
 * Prints options for the tab that displays a list of all files
773
 *
774
 * @author Kate Arzamastseva <[email protected]>
775
 */
776
function media_tab_files_options() {
777
    global $lang;
778
    global $INPUT;
779
    global $ID;
780
781
    $form = new Form([
782
            'method' => 'get',
783
            'action' => wl($ID),
784
            'class' => 'options'
785
    ]);
786
    $form->addTagOpen('div')->addClass('no');
787
    $form->setHiddenField('sectok', null);
788
    $media_manager_params = media_managerURL([], '', false, true);
789
    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...
790
        $form->setHiddenField($pKey, $pVal);
791
    }
792
    if ($INPUT->has('q')) {
793
        $form->setHiddenField('q', $INPUT->str('q'));
794
    }
795
    $form->addHTML('<ul>'.NL);
796
    foreach (array('list' => array('listType', array('thumbs', 'rows')),
797
                  'sort' => array('sortBy', array('name', 'date')))
798
            as $group => $content) {
799
        $checked = "_media_get_${group}_type";
800
        $checked = $checked();
801
802
        $form->addHTML('<li class="'. $content[0] .'">');
803
        foreach ($content[1] as $option) {
804
            $attrs = array();
805
            if ($checked == $option) {
806
                $attrs['checked'] = 'checked';
807
            }
808
            $radio = $form->addRadioButton(
809
                $group.'_dwmedia',
810
                $lang['media_'.$group.'_'.$option]
811
            )->val($option)->id($content[0].'__'.$option)->addClass($option);
812
            $radio->attrs($attrs);
813
        }
814
        $form->addHTML('</li>'.NL);
815
    }
816
    $form->addHTML('<li>');
817
    $form->addButton('', $lang['btn_apply'])->attr('type', 'submit');
818
    $form->addHTML('</li>'.NL);
819
    $form->addHTML('</ul>'.NL);
820
    $form->addTagClose('div');
821
    print $form->toHTML();
822
}
823
824
/**
825
 * Returns type of sorting for the list of files in media manager
826
 *
827
 * @author Kate Arzamastseva <[email protected]>
828
 *
829
 * @return string - sort type
830
 */
831
function _media_get_sort_type() {
832
    return _media_get_display_param('sort', array('default' => 'name', 'date'));
833
}
834
835
/**
836
 * Returns type of listing for the list of files in media manager
837
 *
838
 * @author Kate Arzamastseva <[email protected]>
839
 *
840
 * @return string - list type
841
 */
842
function _media_get_list_type() {
843
    return _media_get_display_param('list', array('default' => 'thumbs', 'rows'));
844
}
845
846
/**
847
 * Get display parameters
848
 *
849
 * @param string $param   name of parameter
850
 * @param array  $values  allowed values, where default value has index key 'default'
851
 * @return string the parameter value
852
 */
853
function _media_get_display_param($param, $values) {
854
    global $INPUT;
855
    if (in_array($INPUT->str($param), $values)) {
856
        // FIXME: Set cookie
857
        return $INPUT->str($param);
858
    } else {
859
        $val = get_doku_pref($param, $values['default']);
860
        if (!in_array($val, $values)) {
861
            $val = $values['default'];
862
        }
863
        return $val;
864
    }
865
}
866
867
/**
868
 * Prints tab that displays a list of all files
869
 *
870
 * @author Kate Arzamastseva <[email protected]>
871
 *
872
 * @param string    $ns
873
 * @param null|int  $auth permission level
874
 * @param string    $jump item id
875
 */
876
function media_tab_files($ns,$auth=null,$jump='') {
877
    global $lang;
878
    if(is_null($auth)) $auth = auth_quickaclcheck("$ns:*");
879
880
    if($auth < AUTH_READ){
881
        echo '<div class="nothing">'.$lang['media_perm_read'].'</div>'.NL;
882
    }else{
883
        media_filelist($ns,$auth,$jump,true,_media_get_sort_type());
884
    }
885
}
886
887
/**
888
 * Prints tab that displays uploading form
889
 *
890
 * @author Kate Arzamastseva <[email protected]>
891
 *
892
 * @param string   $ns
893
 * @param null|int $auth permission level
894
 * @param string   $jump item id
895
 */
896
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...
897
    global $lang;
898
    if(is_null($auth)) $auth = auth_quickaclcheck("$ns:*");
899
900
    echo '<div class="upload">'.NL;
901
    if ($auth >= AUTH_UPLOAD) {
902
        echo '<p>' . $lang['mediaupload'] . '</p>';
903
    }
904
    media_uploadform($ns, $auth, true);
905
    echo '</div>'.NL;
906
}
907
908
/**
909
 * Prints tab that displays search form
910
 *
911
 * @author Kate Arzamastseva <[email protected]>
912
 *
913
 * @param string $ns
914
 * @param null|int $auth permission level
915
 */
916
function media_tab_search($ns,$auth=null) {
917
    global $INPUT;
918
919
    $do = $INPUT->str('mediado');
920
    $query = $INPUT->str('q');
921
    echo '<div class="search">'.NL;
922
923
    media_searchform($ns, $query, true);
924
    if ($do == 'searchlist' || $query) {
925
        media_searchlist($query,$ns,$auth,true,_media_get_sort_type());
926
    }
927
    echo '</div>'.NL;
928
}
929
930
/**
931
 * Prints tab that displays mediafile details
932
 *
933
 * @author Kate Arzamastseva <[email protected]>
934
 *
935
 * @param string     $image media id
936
 * @param string     $ns
937
 * @param null|int   $auth  permission level
938
 * @param string|int $rev   revision timestamp or empty string
939
 */
940
function media_tab_view($image, $ns, $auth=null, $rev='') {
941
    global $lang;
942
    if(is_null($auth)) $auth = auth_quickaclcheck("$ns:*");
943
944
    if ($image && $auth >= AUTH_READ) {
945
        $meta = new JpegMeta(mediaFN($image, $rev));
946
        media_preview($image, $auth, $rev, $meta);
947
        media_preview_buttons($image, $auth, $rev);
948
        media_details($image, $auth, $rev, $meta);
949
950
    } else {
951
        echo '<div class="nothing">'.$lang['media_perm_read'].'</div>'.NL;
952
    }
953
}
954
955
/**
956
 * Prints tab that displays form for editing mediafile metadata
957
 *
958
 * @author Kate Arzamastseva <[email protected]>
959
 *
960
 * @param string     $image media id
961
 * @param string     $ns
962
 * @param null|int   $auth permission level
963
 */
964
function media_tab_edit($image, $ns, $auth=null) {
965
    if(is_null($auth)) $auth = auth_quickaclcheck("$ns:*");
966
967
    if ($image) {
968
        list(, $mime) = mimetype($image);
969
        if ($mime == 'image/jpeg') media_metaform($image,$auth);
970
    }
971
}
972
973
/**
974
 * Prints tab that displays mediafile revisions
975
 *
976
 * @author Kate Arzamastseva <[email protected]>
977
 *
978
 * @param string     $image media id
979
 * @param string     $ns
980
 * @param null|int   $auth permission level
981
 */
982
function media_tab_history($image, $ns, $auth=null) {
983
    global $lang;
984
    global $INPUT;
985
986
    if(is_null($auth)) $auth = auth_quickaclcheck("$ns:*");
987
    $do = $INPUT->str('mediado');
988
989
    if ($auth >= AUTH_READ && $image) {
990
        if ($do == 'diff'){
991
            media_diff($image, $ns, $auth);
992
        } else {
993
            $first = $INPUT->int('first');
994
            html_revisions($first, $image);
0 ignored issues
show
Deprecated Code introduced by
The function html_revisions() has been deprecated with message: 2020-07-18

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

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

Loading history...
995
        }
996
    } else {
997
        echo '<div class="nothing">'.$lang['media_perm_read'].'</div>'.NL;
998
    }
999
}
1000
1001
/**
1002
 * Prints mediafile details
1003
 *
1004
 * @param string         $image media id
1005
 * @param int            $auth permission level
1006
 * @param int|string     $rev revision timestamp or empty string
1007
 * @param JpegMeta|bool  $meta
1008
 *
1009
 * @author Kate Arzamastseva <[email protected]>
1010
 */
1011
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...
1012
1013
    $size = media_image_preview_size($image, $rev, $meta);
1014
1015
    if ($size) {
1016
        global $lang;
1017
        echo '<div class="image">';
1018
1019
        $more = array();
1020
        if ($rev) {
1021
            $more['rev'] = $rev;
1022
        } else {
1023
            $t = @filemtime(mediaFN($image));
1024
            $more['t'] = $t;
1025
        }
1026
1027
        $more['w'] = $size[0];
1028
        $more['h'] = $size[1];
1029
        $src = ml($image, $more);
1030
1031
        echo '<a href="'.$src.'" target="_blank" title="'.$lang['mediaview'].'">';
1032
        echo '<img src="'.$src.'" alt="" style="max-width: '.$size[0].'px;" />';
1033
        echo '</a>';
1034
1035
        echo '</div>'.NL;
1036
    }
1037
}
1038
1039
/**
1040
 * Prints mediafile action buttons
1041
 *
1042
 * @author Kate Arzamastseva <[email protected]>
1043
 *
1044
 * @param string     $image media id
1045
 * @param int        $auth  permission level
1046
 * @param string|int $rev   revision timestamp, or empty string
1047
 */
1048
function media_preview_buttons($image, $auth, $rev = '') {
1049
    global $lang, $conf;
1050
1051
    echo '<ul class="actions">'.DOKU_LF;
1052
1053
    if ($auth >= AUTH_DELETE && !$rev && file_exists(mediaFN($image))) {
1054
1055
        // delete button
1056
        $form = new Form([
1057
            'id' => 'mediamanager__btn_delete',
1058
            'action' => media_managerURL(['delete' => $image], '&'),
1059
        ]);
1060
        $form->addTagOpen('div')->addClass('no');
1061
        $form->addButton('', $lang['btn_delete'])->attr('type', 'submit');
1062
        $form->addTagClose('div');
1063
        echo '<li>';
1064
        echo $form->toHTML();
1065
        echo '</li>'.DOKU_LF;
1066
    }
1067
1068
    $auth_ow = (($conf['mediarevisions']) ? AUTH_UPLOAD : AUTH_DELETE);
1069
    if ($auth >= $auth_ow && !$rev) {
1070
1071
        // upload new version button
1072
        $form = new Form([
1073
            'id' => 'mediamanager__btn_update',
1074
            'action' => media_managerURL(['image' => $image, 'mediado' => 'update'], '&'),
1075
        ]);
1076
        $form->addTagOpen('div')->addClass('no');
1077
        $form->addButton('', $lang['media_update'])->attr('type', 'submit');
1078
        $form->addTagClose('div');
1079
        echo '<li>';
1080
        echo $form->toHTML();
1081
        echo '</li>'.DOKU_LF;
1082
    }
1083
1084
    if ($auth >= AUTH_UPLOAD && $rev && $conf['mediarevisions'] && file_exists(mediaFN($image, $rev))) {
1085
1086
        // restore button
1087
        $form = new Form([
1088
            'id' => 'mediamanager__btn_restore',
1089
            'action'=>media_managerURL(['image' => $image], '&'),
1090
        ]);
1091
        $form->addTagOpen('div')->addClass('no');
1092
        $form->setHiddenField('mediado', 'restore');
1093
        $form->setHiddenField('rev', $rev);
1094
        $form->addButton('', $lang['media_restore'])->attr('type', 'submit');
1095
        $form->addTagClose('div');
1096
        echo '<li>';
1097
        echo $form->toHTML();
1098
        echo '</li>'.DOKU_LF;
1099
    }
1100
1101
    echo '</ul>'.DOKU_LF;
1102
}
1103
1104
/**
1105
 * Returns image width and height for mediamanager preview panel
1106
 *
1107
 * @author Kate Arzamastseva <[email protected]>
1108
 * @param string         $image
1109
 * @param int|string     $rev
1110
 * @param JpegMeta|bool  $meta
1111
 * @param int            $size
1112
 * @return array|false
1113
 */
1114
function media_image_preview_size($image, $rev, $meta, $size = 500) {
1115
    if (!preg_match("/\.(jpe?g|gif|png)$/", $image) || !file_exists(mediaFN($image, $rev))) return false;
1116
1117
    $info = getimagesize(mediaFN($image, $rev));
1118
    $w = (int) $info[0];
1119
    $h = (int) $info[1];
1120
1121
    if($meta && ($w > $size || $h > $size)){
1122
        $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...
1123
        $w = floor($w * $ratio);
1124
        $h = floor($h * $ratio);
1125
    }
1126
    return array($w, $h);
1127
}
1128
1129
/**
1130
 * Returns the requested EXIF/IPTC tag from the image meta
1131
 *
1132
 * @author Kate Arzamastseva <[email protected]>
1133
 *
1134
 * @param array    $tags array with tags, first existing is returned
1135
 * @param JpegMeta $meta
1136
 * @param string   $alt  alternative value
1137
 * @return string
1138
 */
1139
function media_getTag($tags,$meta,$alt=''){
1140
    if($meta === false) return $alt;
1141
    $info = $meta->getField($tags);
1142
    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...
1143
    return $info;
1144
}
1145
1146
/**
1147
 * Returns mediafile tags
1148
 *
1149
 * @author Kate Arzamastseva <[email protected]>
1150
 *
1151
 * @param JpegMeta $meta
1152
 * @return array list of tags of the mediafile
1153
 */
1154
function media_file_tags($meta) {
1155
    // load the field descriptions
1156
    static $fields = null;
1157
    if(is_null($fields)){
1158
        $config_files = getConfigFiles('mediameta');
1159
        foreach ($config_files as $config_file) {
1160
            if(file_exists($config_file)) include($config_file);
1161
        }
1162
    }
1163
1164
    $tags = array();
1165
1166
    foreach($fields as $key => $tag){
0 ignored issues
show
Bug introduced by
The expression $fields of type null is not traversable.
Loading history...
1167
        $t = array();
1168
        if (!empty($tag[0])) $t = array($tag[0]);
1169
        if(isset($tag[3]) && is_array($tag[3])) $t = array_merge($t,$tag[3]);
1170
        $value = media_getTag($t, $meta);
1171
        $tags[] = array('tag' => $tag, 'value' => $value);
1172
    }
1173
1174
    return $tags;
1175
}
1176
1177
/**
1178
 * Prints mediafile tags
1179
 *
1180
 * @author Kate Arzamastseva <[email protected]>
1181
 *
1182
 * @param string        $image image id
1183
 * @param int           $auth  permission level
1184
 * @param string|int    $rev   revision timestamp, or empty string
1185
 * @param bool|JpegMeta $meta  image object, or create one if false
1186
 */
1187
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...
1188
    global $lang;
1189
1190
    if (!$meta) $meta = new JpegMeta(mediaFN($image, $rev));
1191
    $tags = media_file_tags($meta);
0 ignored issues
show
Bug introduced by
It seems like $meta defined by parameter $meta on line 1187 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...
1192
1193
    echo '<dl>'.NL;
1194
    foreach($tags as $tag){
1195
        if ($tag['value']) {
1196
            $value = cleanText($tag['value']);
1197
            echo '<dt>'.$lang[$tag['tag'][1]].'</dt><dd>';
1198
            if ($tag['tag'][2] == 'date') echo dformat($value);
1199
            else echo hsc($value);
1200
            echo '</dd>'.NL;
1201
        }
1202
    }
1203
    echo '</dl>'.NL;
1204
    echo '<dl>'.NL;
1205
    echo '<dt>'.$lang['reference'].':</dt>';
1206
    $media_usage = ft_mediause($image,true);
1207
    if(count($media_usage) > 0){
1208
        foreach($media_usage as $path){
1209
            echo '<dd>'.html_wikilink($path).'</dd>';
1210
        }
1211
    }else{
1212
        echo '<dd>'.$lang['nothingfound'].'</dd>';
1213
    }
1214
    echo '</dl>'.NL;
1215
1216
}
1217
1218
/**
1219
 * Shows difference between two revisions of file
1220
 *
1221
 * @author Kate Arzamastseva <[email protected]>
1222
 *
1223
 * @param string $image  image id
1224
 * @param string $ns
1225
 * @param int $auth permission level
1226
 * @param bool $fromajax
1227
 * @return false|null|string
1228
 */
1229
function media_diff($image, $ns, $auth, $fromajax = false) {
1230
    global $conf;
1231
    global $INPUT;
1232
1233
    if ($auth < AUTH_READ || !$image || !$conf['mediarevisions']) return '';
1234
1235
    $rev1 = $INPUT->int('rev');
1236
1237
    $rev2 = $INPUT->ref('rev2');
1238
    if(is_array($rev2)){
1239
        $rev1 = (int) $rev2[0];
1240
        $rev2 = (int) $rev2[1];
1241
1242
        if(!$rev1){
1243
            $rev1 = $rev2;
1244
            unset($rev2);
1245
        }
1246
    }else{
1247
        $rev2 = $INPUT->int('rev2');
1248
    }
1249
1250
    if ($rev1 && !file_exists(mediaFN($image, $rev1))) $rev1 = false;
1251
    if ($rev2 && !file_exists(mediaFN($image, $rev2))) $rev2 = false;
1252
1253
    if($rev1 && $rev2){            // two specific revisions wanted
1254
        // make sure order is correct (older on the left)
1255
        if($rev1 < $rev2){
1256
            $l_rev = $rev1;
1257
            $r_rev = $rev2;
1258
        }else{
1259
            $l_rev = $rev2;
1260
            $r_rev = $rev1;
1261
        }
1262
    }elseif($rev1){                // single revision given, compare to current
1263
        $r_rev = '';
1264
        $l_rev = $rev1;
1265
    }else{                        // no revision was given, compare previous to current
1266
        $r_rev = '';
1267
        $medialog = new MediaChangeLog($image);
1268
        $revs = $medialog->getRevisions(0, 1);
1269
        if (file_exists(mediaFN($image, $revs[0]))) {
1270
            $l_rev = $revs[0];
1271
        } else {
1272
            $l_rev = '';
1273
        }
1274
    }
1275
1276
    // prepare event data
1277
    $data = array();
1278
    $data[0] = $image;
1279
    $data[1] = $l_rev;
1280
    $data[2] = $r_rev;
1281
    $data[3] = $ns;
1282
    $data[4] = $auth;
1283
    $data[5] = $fromajax;
1284
1285
    // trigger event
1286
    return Event::createAndTrigger('MEDIA_DIFF', $data, '_media_file_diff', true);
1287
}
1288
1289
/**
1290
 * Callback for media file diff
1291
 *
1292
 * @param array $data event data
1293
 * @return false|null
1294
 */
1295
function _media_file_diff($data) {
1296
    if(is_array($data) && count($data)===6) {
1297
        media_file_diff($data[0], $data[1], $data[2], $data[3], $data[4], $data[5]);
1298
    } else {
1299
        return false;
1300
    }
1301
}
1302
1303
/**
1304
 * Shows difference between two revisions of image
1305
 *
1306
 * @author Kate Arzamastseva <[email protected]>
1307
 *
1308
 * @param string $image
1309
 * @param string|int $l_rev revision timestamp, or empty string
1310
 * @param string|int $r_rev revision timestamp, or empty string
1311
 * @param string $ns
1312
 * @param int $auth permission level
1313
 * @param bool $fromajax
1314
 */
1315
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...
1316
    global $lang;
1317
    global $INPUT;
1318
1319
    $l_meta = new JpegMeta(mediaFN($image, $l_rev));
1320
    $r_meta = new JpegMeta(mediaFN($image, $r_rev));
1321
1322
    $is_img = preg_match('/\.(jpe?g|gif|png)$/', $image);
1323
    if ($is_img) {
1324
        $l_size = media_image_preview_size($image, $l_rev, $l_meta);
1325
        $r_size = media_image_preview_size($image, $r_rev, $r_meta);
1326
        $is_img = ($l_size && $r_size && ($l_size[0] >= 30 || $r_size[0] >= 30));
1327
1328
        $difftype = $INPUT->str('difftype');
1329
1330
        if (!$fromajax) {
1331
            $form = new Form([
1332
                'id' => 'mediamanager__form_diffview',
1333
                'action' => media_managerURL([], '&'),
1334
                'method' => 'get',
1335
                'class' => 'diffView',
1336
            ]);
1337
            $form->addTagOpen('div')->addClass('no');
1338
            $form->setHiddenField('sectok', null);
1339
            $form->setHiddenField('mediado', 'diff');
1340
            $form->setHiddenField('rev2[0]', $l_rev);
1341
            $form->setHiddenField('rev2[1]', $r_rev);
1342
            echo $form->toHTML();
1343
1344
            echo NL.'<div id="mediamanager__diff" >'.NL;
1345
        }
1346
1347
        if ($difftype == 'opacity' || $difftype == 'portions') {
1348
            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 1324 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 1325 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...
1349
            if (!$fromajax) echo '</div>';
1350
            return;
1351
        }
1352
    }
1353
1354
    list($l_head, $r_head) = (new dokuwiki\Ui\Diff)->diffHead($l_rev, $r_rev, $image, true);
1355
1356
    ?>
1357
    <div class="table">
1358
    <table>
1359
      <tr>
1360
        <th><?php echo $l_head; ?></th>
1361
        <th><?php echo $r_head; ?></th>
1362
      </tr>
1363
    <?php
1364
1365
    echo '<tr class="image">';
1366
    echo '<td>';
1367
    media_preview($image, $auth, $l_rev, $l_meta);
1368
    echo '</td>';
1369
1370
    echo '<td>';
1371
    media_preview($image, $auth, $r_rev, $r_meta);
1372
    echo '</td>';
1373
    echo '</tr>'.NL;
1374
1375
    echo '<tr class="actions">';
1376
    echo '<td>';
1377
    media_preview_buttons($image, $auth, $l_rev);
1378
    echo '</td>';
1379
1380
    echo '<td>';
1381
    media_preview_buttons($image, $auth, $r_rev);
1382
    echo '</td>';
1383
    echo '</tr>'.NL;
1384
1385
    $l_tags = media_file_tags($l_meta);
1386
    $r_tags = media_file_tags($r_meta);
1387
    // FIXME r_tags-only stuff
1388
    foreach ($l_tags as $key => $l_tag) {
1389
        if ($l_tag['value'] != $r_tags[$key]['value']) {
1390
            $r_tags[$key]['highlighted'] = true;
1391
            $l_tags[$key]['highlighted'] = true;
1392
        } else if (!$l_tag['value'] || !$r_tags[$key]['value']) {
1393
            unset($r_tags[$key]);
1394
            unset($l_tags[$key]);
1395
        }
1396
    }
1397
1398
    echo '<tr>';
1399
    foreach(array($l_tags,$r_tags) as $tags){
1400
        echo '<td>'.NL;
1401
1402
        echo '<dl class="img_tags">';
1403
        foreach($tags as $tag){
1404
            $value = cleanText($tag['value']);
1405
            if (!$value) $value = '-';
1406
            echo '<dt>'.$lang[$tag['tag'][1]].'</dt>';
1407
            echo '<dd>';
1408
            if ($tag['highlighted']) {
1409
                echo '<strong>';
1410
            }
1411
            if ($tag['tag'][2] == 'date') echo dformat($value);
1412
            else echo hsc($value);
1413
            if ($tag['highlighted']) {
1414
                echo '</strong>';
1415
            }
1416
            echo '</dd>';
1417
        }
1418
        echo '</dl>'.NL;
1419
1420
        echo '</td>';
1421
    }
1422
    echo '</tr>'.NL;
1423
1424
    echo '</table>'.NL;
1425
    echo '</div>'.NL;
1426
1427
    if ($is_img && !$fromajax) echo '</div>';
1428
}
1429
1430
/**
1431
 * Prints two images side by side
1432
 * and slider
1433
 *
1434
 * @author Kate Arzamastseva <[email protected]>
1435
 *
1436
 * @param string $image   image id
1437
 * @param int    $l_rev   revision timestamp, or empty string
1438
 * @param int    $r_rev   revision timestamp, or empty string
1439
 * @param array  $l_size  array with width and height
1440
 * @param array  $r_size  array with width and height
1441
 * @param string $type
1442
 */
1443
function media_image_diff($image, $l_rev, $r_rev, $l_size, $r_size, $type) {
1444
    if ($l_size != $r_size) {
1445
        if ($r_size[0] > $l_size[0]) {
1446
            $l_size = $r_size;
1447
        }
1448
    }
1449
1450
    $l_more = array('rev' => $l_rev, 'h' => $l_size[1], 'w' => $l_size[0]);
1451
    $r_more = array('rev' => $r_rev, 'h' => $l_size[1], 'w' => $l_size[0]);
1452
1453
    $l_src = ml($image, $l_more);
1454
    $r_src = ml($image, $r_more);
1455
1456
    // slider
1457
    echo '<div class="slider" style="max-width: '.($l_size[0]-20).'px;" ></div>'.NL;
1458
1459
    // two images in divs
1460
    echo '<div class="imageDiff ' . $type . '">'.NL;
1461
    echo '<div class="image1" style="max-width: '.$l_size[0].'px;">';
1462
    echo '<img src="'.$l_src.'" alt="" />';
1463
    echo '</div>'.NL;
1464
    echo '<div class="image2" style="max-width: '.$l_size[0].'px;">';
1465
    echo '<img src="'.$r_src.'" alt="" />';
1466
    echo '</div>'.NL;
1467
    echo '</div>'.NL;
1468
}
1469
1470
/**
1471
 * Restores an old revision of a media file
1472
 *
1473
 * @param string $image media id
1474
 * @param int    $rev   revision timestamp or empty string
1475
 * @param int    $auth
1476
 * @return string - file's id
1477
 *
1478
 * @author Kate Arzamastseva <[email protected]>
1479
 */
1480
function media_restore($image, $rev, $auth){
1481
    global $conf;
1482
    if ($auth < AUTH_UPLOAD || !$conf['mediarevisions']) return false;
1483
    $removed = (!file_exists(mediaFN($image)) && file_exists(mediaMetaFN($image, '.changes')));
1484
    if (!$image || (!file_exists(mediaFN($image)) && !$removed)) return false;
1485
    if (!$rev || !file_exists(mediaFN($image, $rev))) return false;
1486
    list(,$imime,) = mimetype($image);
1487
    $res = media_upload_finish(mediaFN($image, $rev),
1488
        mediaFN($image),
1489
        $image,
1490
        $imime,
1491
        true,
1492
        'copy');
1493
    if (is_array($res)) {
1494
        msg($res[0], $res[1]);
1495
        return false;
1496
    }
1497
    return $res;
1498
}
1499
1500
/**
1501
 * List all files found by the search request
1502
 *
1503
 * @author Tobias Sarnowski <[email protected]>
1504
 * @author Andreas Gohr <[email protected]>
1505
 * @author Kate Arzamastseva <[email protected]>
1506
 * @triggers MEDIA_SEARCH
1507
 *
1508
 * @param string $query
1509
 * @param string $ns
1510
 * @param null|int $auth
1511
 * @param bool $fullscreen
1512
 * @param string $sort
1513
 */
1514
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...
1515
    global $conf;
1516
    global $lang;
1517
1518
    $ns = cleanID($ns);
1519
    $evdata = array(
1520
        'ns'    => $ns,
1521
        'data'  => array(),
1522
        'query' => $query
1523
    );
1524
    if (!blank($query)) {
1525
        $evt = new Event('MEDIA_SEARCH', $evdata);
1526
        if ($evt->advise_before()) {
1527
            $dir = utf8_encodeFN(str_replace(':','/',$evdata['ns']));
1528
            $quoted = preg_quote($evdata['query'],'/');
1529
            //apply globbing
1530
            $quoted = str_replace(array('\*', '\?'), array('.*', '.'), $quoted, $count);
1531
1532
            //if we use globbing file name must match entirely but may be preceded by arbitrary namespace
1533
            if ($count > 0) $quoted = '^([^:]*:)*'.$quoted.'$';
1534
1535
            $pattern = '/'.$quoted.'/i';
1536
            search($evdata['data'],
1537
                    $conf['mediadir'],
1538
                    'search_media',
1539
                    array('showmsg'=>false,'pattern'=>$pattern),
1540
                    $dir,
1541
                    1,
1542
                    $sort);
1543
        }
1544
        $evt->advise_after();
1545
        unset($evt);
1546
    }
1547
1548
    if (!$fullscreen) {
1549
        echo '<h1 id="media__ns">'.sprintf($lang['searchmedia_in'],hsc($ns).':*').'</h1>'.NL;
1550
        media_searchform($ns,$query);
1551
    }
1552
1553
    if(!count($evdata['data'])){
1554
        echo '<div class="nothing">'.$lang['nothingfound'].'</div>'.NL;
1555
    }else {
1556
        if ($fullscreen) {
1557
            echo '<ul class="' . _media_get_list_type() . '">';
1558
        }
1559
        foreach($evdata['data'] as $item){
1560
            if (!$fullscreen) media_printfile($item,$item['perm'],'',true);
1561
            else media_printfile_thumbs($item,$item['perm'],false,true);
1562
        }
1563
        if ($fullscreen) echo '</ul>'.NL;
1564
    }
1565
}
1566
1567
/**
1568
 * Formats and prints one file in the list
1569
 *
1570
 * @param array     $item
1571
 * @param int       $auth              permission level
1572
 * @param string    $jump              item id
1573
 * @param bool      $display_namespace
1574
 */
1575
function media_printfile($item,$auth,$jump,$display_namespace=false){
1576
    global $lang;
1577
1578
    // Prepare zebra coloring
1579
    // I always wanted to use this variable name :-D
1580
    static $twibble = 1;
1581
    $twibble *= -1;
1582
    $zebra = ($twibble == -1) ? 'odd' : 'even';
1583
1584
    // Automatically jump to recent action
1585
    if($jump == $item['id']) {
1586
        $jump = ' id="scroll__here" ';
1587
    }else{
1588
        $jump = '';
1589
    }
1590
1591
    // Prepare fileicons
1592
    list($ext) = mimetype($item['file'],false);
1593
    $class = preg_replace('/[^_\-a-z0-9]+/i','_',$ext);
1594
    $class = 'select mediafile mf_'.$class;
1595
1596
    // Prepare filename
1597
    $file = utf8_decodeFN($item['file']);
1598
1599
    // Prepare info
1600
    $info = '';
1601
    if($item['isimg']){
1602
        $info .= (int) $item['meta']->getField('File.Width');
1603
        $info .= '&#215;';
1604
        $info .= (int) $item['meta']->getField('File.Height');
1605
        $info .= ' ';
1606
    }
1607
    $info .= '<i>'.dformat($item['mtime']).'</i>';
1608
    $info .= ' ';
1609
    $info .= filesize_h($item['size']);
1610
1611
    // output
1612
    echo '<div class="'.$zebra.'"'.$jump.' title="'.hsc($item['id']).'">'.NL;
1613
    if (!$display_namespace) {
1614
        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 1597 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...
1615
    } else {
1616
        echo '<a id="h_:'.$item['id'].'" class="'.$class.'">'.hsc($item['id']).'</a><br/>';
1617
    }
1618
    echo '<span class="info">('.$info.')</span>'.NL;
1619
1620
    // view button
1621
    $link = ml($item['id'],'',true);
1622
    echo ' <a href="'.$link.'" target="_blank"><img src="'.DOKU_BASE.'lib/images/magnifier.png" '.
1623
        'alt="'.$lang['mediaview'].'" title="'.$lang['mediaview'].'" class="btn" /></a>';
1624
1625
    // mediamanager button
1626
    $link = wl('',array('do'=>'media','image'=>$item['id'],'ns'=>getNS($item['id'])));
1627
    echo ' <a href="'.$link.'" target="_blank"><img src="'.DOKU_BASE.'lib/images/mediamanager.png" '.
1628
        'alt="'.$lang['btn_media'].'" title="'.$lang['btn_media'].'" class="btn" /></a>';
1629
1630
    // delete button
1631
    if($item['writable'] && $auth >= AUTH_DELETE){
1632
        $link = DOKU_BASE.'lib/exe/mediamanager.php?delete='.rawurlencode($item['id']).
1633
            '&amp;sectok='.getSecurityToken();
1634
        echo ' <a href="'.$link.'" class="btn_media_delete" title="'.$item['id'].'">'.
1635
            '<img src="'.DOKU_BASE.'lib/images/trash.png" alt="'.$lang['btn_delete'].'" '.
1636
            'title="'.$lang['btn_delete'].'" class="btn" /></a>';
1637
    }
1638
1639
    echo '<div class="example" id="ex_'.str_replace(':','_',$item['id']).'">';
1640
    echo $lang['mediausage'].' <code>{{:'.$item['id'].'}}</code>';
1641
    echo '</div>';
1642
    if($item['isimg']) media_printimgdetail($item);
1643
    echo '<div class="clearer"></div>'.NL;
1644
    echo '</div>'.NL;
1645
}
1646
1647
/**
1648
 * Display a media icon
1649
 *
1650
 * @param string $filename media id
1651
 * @param string $size     the size subfolder, if not specified 16x16 is used
1652
 * @return string html
1653
 */
1654
function media_printicon($filename, $size=''){
1655
    list($ext) = mimetype(mediaFN($filename),false);
1656
1657
    if (file_exists(DOKU_INC.'lib/images/fileicons/'.$size.'/'.$ext.'.png')) {
1658
        $icon = DOKU_BASE.'lib/images/fileicons/'.$size.'/'.$ext.'.png';
1659
    } else {
1660
        $icon = DOKU_BASE.'lib/images/fileicons/'.$size.'/file.png';
1661
    }
1662
1663
    return '<img src="'.$icon.'" alt="'.$filename.'" class="icon" />';
1664
}
1665
1666
/**
1667
 * Formats and prints one file in the list in the thumbnails view
1668
 *
1669
 * @author Kate Arzamastseva <[email protected]>
1670
 *
1671
 * @param array       $item
1672
 * @param int         $auth              permission level
1673
 * @param bool|string $jump              item id
1674
 * @param bool        $display_namespace
1675
 */
1676
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...
1677
1678
    // Prepare filename
1679
    $file = utf8_decodeFN($item['file']);
1680
1681
    // output
1682
    echo '<li><dl title="'.hsc($item['id']).'">'.NL;
1683
1684
        echo '<dt>';
1685
    if($item['isimg']) {
1686
        media_printimgdetail($item, true);
1687
1688
    } else {
1689
        echo '<a id="d_:'.$item['id'].'" class="image" title="'.$item['id'].'" href="'.
1690
            media_managerURL(['image' => hsc($item['id']), 'ns' => getNS($item['id']),
1691
            'tab_details' => 'view']).'">';
1692
        echo media_printicon($item['id'], '32x32');
1693
        echo '</a>';
1694
    }
1695
    echo '</dt>'.NL;
1696
    if (!$display_namespace) {
1697
        $name = hsc($file);
0 ignored issues
show
Security Bug introduced by
It seems like $file defined by utf8_decodeFN($item['file']) on line 1679 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...
1698
    } else {
1699
        $name = hsc($item['id']);
1700
    }
1701
    echo '<dd class="name"><a href="'.media_managerURL(['image' => hsc($item['id']), 'ns' => getNS($item['id']),
1702
        'tab_details' => 'view']).'" id="h_:'.$item['id'].'">'.$name.'</a></dd>'.NL;
1703
1704
    if($item['isimg']){
1705
        $size = '';
1706
        $size .= (int) $item['meta']->getField('File.Width');
1707
        $size .= '&#215;';
1708
        $size .= (int) $item['meta']->getField('File.Height');
1709
        echo '<dd class="size">'.$size.'</dd>'.NL;
1710
    } else {
1711
        echo '<dd class="size">&#160;</dd>'.NL;
1712
    }
1713
    $date = dformat($item['mtime']);
1714
    echo '<dd class="date">'.$date.'</dd>'.NL;
1715
    $filesize = filesize_h($item['size']);
1716
    echo '<dd class="filesize">'.$filesize.'</dd>'.NL;
1717
    echo '</dl></li>'.NL;
1718
}
1719
1720
/**
1721
 * Prints a thumbnail and metainfo
1722
 *
1723
 * @param array $item
1724
 * @param bool  $fullscreen
1725
 */
1726
function media_printimgdetail($item, $fullscreen=false){
1727
    // prepare thumbnail
1728
    $size = $fullscreen ? 90 : 120;
1729
1730
    $w = (int) $item['meta']->getField('File.Width');
1731
    $h = (int) $item['meta']->getField('File.Height');
1732
    if($w>$size || $h>$size){
1733
        if (!$fullscreen) {
1734
            $ratio = $item['meta']->getResizeRatio($size);
1735
        } else {
1736
            $ratio = $item['meta']->getResizeRatio($size,$size);
1737
        }
1738
        $w = floor($w * $ratio);
1739
        $h = floor($h * $ratio);
1740
    }
1741
    $src = ml($item['id'],array('w'=>$w,'h'=>$h,'t'=>$item['mtime']));
1742
    $p = array();
1743
    if (!$fullscreen) {
1744
        // In fullscreen mediamanager view, image resizing is done via CSS.
1745
        $p['width']  = $w;
1746
        $p['height'] = $h;
1747
    }
1748
    $p['alt']    = $item['id'];
1749
    $att = buildAttributes($p);
1750
1751
    // output
1752
    if ($fullscreen) {
1753
        echo '<a id="l_:'.$item['id'].'" class="image thumb" href="'.
1754
            media_managerURL(['image' => hsc($item['id']), 'ns' => getNS($item['id']), 'tab_details' => 'view']).'">';
1755
        echo '<img src="'.$src.'" '.$att.' />';
1756
        echo '</a>';
1757
    }
1758
1759
    if ($fullscreen) return;
1760
1761
    echo '<div class="detail">';
1762
    echo '<div class="thumb">';
1763
    echo '<a id="d_:'.$item['id'].'" class="select">';
1764
    echo '<img src="'.$src.'" '.$att.' />';
1765
    echo '</a>';
1766
    echo '</div>';
1767
1768
    // read EXIF/IPTC data
1769
    $t = $item['meta']->getField(array('IPTC.Headline','xmp.dc:title'));
1770
    $d = $item['meta']->getField(array('IPTC.Caption','EXIF.UserComment',
1771
                'EXIF.TIFFImageDescription',
1772
                'EXIF.TIFFUserComment'));
1773
    if(\dokuwiki\Utf8\PhpString::strlen($d) > 250) $d = \dokuwiki\Utf8\PhpString::substr($d,0,250).'...';
1774
    $k = $item['meta']->getField(array('IPTC.Keywords','IPTC.Category','xmp.dc:subject'));
1775
1776
    // print EXIF/IPTC data
1777
    if($t || $d || $k ){
1778
        echo '<p>';
1779
        if($t) echo '<strong>'.hsc($t).'</strong><br />';
1780
        if($d) echo hsc($d).'<br />';
1781
        if($t) echo '<em>'.hsc($k).'</em>';
1782
        echo '</p>';
1783
    }
1784
    echo '</div>';
1785
}
1786
1787
/**
1788
 * Build link based on the current, adding/rewriting parameters
1789
 *
1790
 * @author Kate Arzamastseva <[email protected]>
1791
 *
1792
 * @param array|bool $params
1793
 * @param string     $amp           separator
1794
 * @param bool       $abs           absolute url?
1795
 * @param bool       $params_array  return the parmeters array?
1796
 * @return string|array - link or link parameters
1797
 */
1798
function media_managerURL($params = false, $amp = '&amp;', $abs = false, $params_array = false) {
1799
    global $ID;
1800
    global $INPUT;
1801
1802
    $gets = array('do' => 'media');
1803
    $media_manager_params = array('tab_files', 'tab_details', 'image', 'ns', 'list', 'sort');
1804
    foreach ($media_manager_params as $x) {
1805
        if ($INPUT->has($x)) $gets[$x] = $INPUT->str($x);
1806
    }
1807
1808
    if ($params) {
1809
        $gets = $params + $gets;
1810
    }
1811
    unset($gets['id']);
1812
    if (isset($gets['delete'])) {
1813
        unset($gets['image']);
1814
        unset($gets['tab_details']);
1815
    }
1816
1817
    if ($params_array) return $gets;
1818
1819
    return wl($ID,$gets,$abs,$amp);
1820
}
1821
1822
/**
1823
 * Print the media upload form if permissions are correct
1824
 *
1825
 * @author Andreas Gohr <[email protected]>
1826
 * @author Kate Arzamastseva <[email protected]>
1827
 *
1828
 * @param string $ns
1829
 * @param int    $auth permission level
1830
 * @param bool  $fullscreen
1831
 */
1832
function media_uploadform($ns, $auth, $fullscreen = false) {
1833
    global $lang;
1834
    global $conf;
1835
    global $INPUT;
1836
1837
    if ($auth < AUTH_UPLOAD) {
1838
        echo '<div class="nothing">'.$lang['media_perm_upload'].'</div>'.NL;
1839
        return;
1840
    }
1841
    $auth_ow = (($conf['mediarevisions']) ? AUTH_UPLOAD : AUTH_DELETE);
1842
1843
    $update = false;
1844
    $id = '';
1845
    if ($auth >= $auth_ow && $fullscreen && $INPUT->str('mediado') == 'update') {
1846
        $update = true;
1847
        $id = cleanID($INPUT->str('image'));
1848
    }
1849
1850
    // The default HTML upload form
1851
    $form = new Form([
1852
        'id' => 'dw__upload',
1853
        'enctype' => 'multipart/form-data',
1854
        'action' => ($fullscreen)
1855
                    ? media_managerURL(['tab_files' => 'files', 'tab_details' => 'view'], '&')
1856
                    : DOKU_BASE.'lib/exe/mediamanager.php',
1857
    ]);
1858
    $form->addTagOpen('div')->addClass('no');
1859
    $form->setHiddenField('ns', hsc($ns));  // FIXME hsc required?
1860
    $form->addTagOpen('p');
1861
    $form->addTextInput('upload', $lang['txt_upload'])->id('upload__file')
1862
            ->attrs(['type' => 'file']);
1863
    $form->addTagClose('p');
1864
    $form->addTagOpen('p');
1865
    $form->addTextInput('mediaid', $lang['txt_filename'])->id('upload__name')
1866
            ->val(noNS($id));
1867
    $form->addButton('', $lang['btn_upload'])->attr('type', 'submit');
1868
    $form->addTagClose('p');
1869
    if ($auth >= $auth_ow){
1870
        $form->addTagOpen('p');
1871
        $attrs = array();
1872
        if ($update) $attrs['checked'] = 'checked';
1873
        $form->addCheckbox('ow', $lang['txt_overwrt'])->id('dw__ow')->val('1')
1874
            ->addClass('check')->attrs($attrs);
1875
        $form->addTagClose('p');
1876
    }
1877
    $form->addTagClose('div');
1878
1879
    if (!$fullscreen) {
1880
        echo '<div class="upload">'. $lang['mediaupload'] .'</div>'.DOKU_LF;
1881
    } else {
1882
        echo DOKU_LF;
1883
    }
1884
1885
    echo '<div id="mediamanager__uploader">'.DOKU_LF;
1886
    // emit HTML_LOGINFORM_OUTPUT event
1887
    Event::createAndTrigger('HTML_UPLOADFORM_OUTPUT', $form, null, false);
1888
    echo $form->toHTML();
1889
    echo '</div>'.DOKU_LF;
1890
1891
    echo '<p class="maxsize">';
1892
    printf($lang['maxuploadsize'], filesize_h(media_getuploadsize()));
1893
    echo ' <a class="allowedmime" href="#">'. $lang['allowedmime'] .'</a>';
1894
    echo ' <span>'. implode(', ', array_keys(getMimeTypes())) .'</span>';
1895
    echo '</p>'.DOKU_LF;
1896
}
1897
1898
/**
1899
 * Returns the size uploaded files may have
1900
 *
1901
 * This uses a conservative approach using the lowest number found
1902
 * in any of the limiting ini settings
1903
 *
1904
 * @returns int size in bytes
1905
 */
1906
function media_getuploadsize(){
1907
    $okay = 0;
1908
1909
    $post = (int) php_to_byte(@ini_get('post_max_size'));
1910
    $suho = (int) php_to_byte(@ini_get('suhosin.post.max_value_length'));
1911
    $upld = (int) php_to_byte(@ini_get('upload_max_filesize'));
1912
1913
    if($post && ($post < $okay || $okay == 0)) $okay = $post;
1914
    if($suho && ($suho < $okay || $okay == 0)) $okay = $suho;
1915
    if($upld && ($upld < $okay || $okay == 0)) $okay = $upld;
1916
1917
    return $okay;
1918
}
1919
1920
/**
1921
 * Print the search field form
1922
 *
1923
 * @author Tobias Sarnowski <[email protected]>
1924
 * @author Kate Arzamastseva <[email protected]>
1925
 *
1926
 * @param string $ns
1927
 * @param string $query
1928
 * @param bool $fullscreen
1929
 */
1930
function media_searchform($ns, $query = '', $fullscreen = false) {
1931
    global $lang;
1932
1933
    // The default HTML search form
1934
    $form = new Form([
1935
        'id'     => 'dw__mediasearch',
1936
        'action' => ($fullscreen)
1937
                    ? media_managerURL([], '&')
1938
                    : DOKU_BASE.'lib/exe/mediamanager.php',
1939
    ]);
1940
    $form->addTagOpen('div')->addClass('no');
1941
    $form->setHiddenField('ns', $ns);
1942
    $form->setHiddenField($fullscreen ? 'mediado' : 'do', 'searchlist');
1943
1944
    $form->addTagOpen('p');
1945
    $input = $form->addTextInput('q', $lang['searchmedia'])
0 ignored issues
show
Unused Code introduced by
$input is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

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