Completed
Push — authpdo ( f7028a...7f89f0 )
by Andreas
06:16
created

media.php ➔ media_file_diff()   F

Complexity

Conditions 21
Paths 1596

Size

Total Lines 113
Code Lines 80

Duplication

Lines 0
Ratio 0 %
Metric Value
cc 21
eloc 80
nc 1596
nop 6
dl 0
loc 113
rs 2

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
if(!defined('DOKU_INC')) die('meh.');
10
if(!defined('NL')) define('NL',"\n");
11
12
/**
13
 * Lists pages which currently use a media file selected for deletion
14
 *
15
 * References uses the same visual as search results and share
16
 * their CSS tags except pagenames won't be links.
17
 *
18
 * @author Matthias Grimm <[email protected]>
19
 *
20
 * @param array $data
21
 * @param string $id
22
 */
23
function media_filesinuse($data,$id){
24
    global $lang;
25
    echo '<h1>'.$lang['reference'].' <code>'.hsc(noNS($id)).'</code></h1>';
26
    echo '<p>'.hsc($lang['ref_inuse']).'</p>';
27
28
    $hidden=0; //count of hits without read permission
29
    foreach($data as $row){
30
        if(auth_quickaclcheck($row) >= AUTH_READ && isVisiblePage($row)){
31
            echo '<div class="search_result">';
32
            echo '<span class="mediaref_ref">'.hsc($row).'</span>';
33
            echo '</div>';
34
        }else
35
            $hidden++;
36
    }
37
    if ($hidden){
38
        print '<div class="mediaref_hidden">'.$lang['ref_hidden'].'</div>';
39
    }
40
}
41
42
/**
43
 * Handles the saving of image meta data
44
 *
45
 * @author Andreas Gohr <[email protected]>
46
 * @author Kate Arzamastseva <[email protected]>
47
 *
48
 * @param string $id media id
49
 * @param int $auth permission level
50
 * @param array $data
51
 * @return false|string
52
 */
53
function media_metasave($id,$auth,$data){
54
    if($auth < AUTH_UPLOAD) return false;
55
    if(!checkSecurityToken()) return false;
56
    global $lang;
57
    global $conf;
58
    $src = mediaFN($id);
59
60
    $meta = new JpegMeta($src);
61
    $meta->_parseAll();
62
63
    foreach($data as $key => $val){
64
        $val=trim($val);
65
        if(empty($val)){
66
            $meta->deleteField($key);
67
        }else{
68
            $meta->setField($key,$val);
69
        }
70
    }
71
72
    $old = @filemtime($src);
73
    if(!file_exists(mediaFN($id, $old)) && file_exists($src)) {
74
        // add old revision to the attic
75
        media_saveOldRevision($id);
76
    }
77
78
    if($meta->save()){
79
        if($conf['fperm']) chmod($src, $conf['fperm']);
80
81
        $new = @filemtime($src);
82
        // add a log entry to the media changelog
83
        addMediaLogEntry($new, $id, DOKU_CHANGE_TYPE_EDIT, $lang['media_meta_edited']);
84
85
        msg($lang['metasaveok'],1);
86
        return $id;
87
    }else{
88
        msg($lang['metasaveerr'],-1);
89
        return false;
90
    }
91
}
92
93
/**
94
 * check if a media is external source
95
 *
96
 * @author Gerrit Uitslag <[email protected]>
97
 *
98
 * @param string $id the media ID or URL
99
 * @return bool
100
 */
101
function media_isexternal($id){
102
    if (preg_match('#^(?:https?|ftp)://#i', $id)) return true;
103
    return false;
104
}
105
106
/**
107
 * Check if a media item is public (eg, external URL or readable by @ALL)
108
 *
109
 * @author Andreas Gohr <[email protected]>
110
 *
111
 * @param string $id  the media ID or URL
112
 * @return bool
113
 */
114
function media_ispublic($id){
115
    if(media_isexternal($id)) return true;
116
    $id = cleanID($id);
117
    if(auth_aclcheck(getNS($id).':*', '', array()) >= AUTH_READ) return true;
118
    return false;
119
}
120
121
/**
122
 * Display the form to edit image meta data
123
 *
124
 * @author Andreas Gohr <[email protected]>
125
 * @author Kate Arzamastseva <[email protected]>
126
 *
127
 * @param string $id media id
128
 * @param int $auth permission level
129
 * @return bool
130
 */
131
function media_metaform($id,$auth){
132
    global $lang;
133
134
    if($auth < AUTH_UPLOAD) {
135
        echo '<div class="nothing">'.$lang['media_perm_upload'].'</div>'.NL;
136
        return false;
137
    }
138
139
    // load the field descriptions
140
    static $fields = null;
141
    if(is_null($fields)){
142
        $config_files = getConfigFiles('mediameta');
143
        foreach ($config_files as $config_file) {
144
            if(file_exists($config_file)) include($config_file);
145
        }
146
    }
147
148
    $src = mediaFN($id);
149
150
    // output
151
    $form = new Doku_Form(array('action' => media_managerURL(array('tab_details' => 'view'), '&'),
152
                                'class' => 'meta'));
153
    $form->addHidden('img', $id);
154
    $form->addHidden('mediado', 'save');
155
    foreach($fields as $key => $field){
0 ignored issues
show
Bug introduced by
The expression $fields of type null is not traversable.
Loading history...
156
        // get current value
157
        if (empty($field[0])) continue;
158
        $tags = array($field[0]);
159
        if(is_array($field[3])) $tags = array_merge($tags,$field[3]);
160
        $value = tpl_img_getTag($tags,'',$src);
161
        $value = cleanText($value);
162
163
        // prepare attributes
164
        $p = array();
165
        $p['class'] = 'edit';
166
        $p['id']    = 'meta__'.$key;
167
        $p['name']  = 'meta['.$field[0].']';
168
        $p_attrs    = array('class' => 'edit');
169
170
        $form->addElement('<div class="row">');
171
        if($field[2] == 'text'){
172
            $form->addElement(form_makeField('text', $p['name'], $value, ($lang[$field[1]]) ? $lang[$field[1]] : $field[1] . ':', $p['id'], $p['class'], $p_attrs));
173
        }else{
174
            $att = buildAttributes($p);
175
            $form->addElement('<label for="meta__'.$key.'">'.$lang[$field[1]].'</label>');
176
            $form->addElement("<textarea $att rows=\"6\" cols=\"50\">".formText($value).'</textarea>');
177
        }
178
        $form->addElement('</div>'.NL);
179
    }
180
    $form->addElement('<div class="buttons">');
181
    $form->addElement(form_makeButton('submit', '', $lang['btn_save'], array('accesskey' => 's', 'name' => 'mediado[save]')));
182
    $form->addElement('</div>'.NL);
183
    $form->printForm();
184
185
    return true;
186
}
187
188
/**
189
 * Convenience function to check if a media file is still in use
190
 *
191
 * @author Michael Klier <[email protected]>
192
 *
193
 * @param string $id media id
194
 * @return array|bool
195
 */
196
function media_inuse($id) {
197
    global $conf;
198
199
    if($conf['refcheck']){
200
        $mediareferences = ft_mediause($id,true);
201
        if(!count($mediareferences)) {
202
            return false;
203
        } else {
204
            return $mediareferences;
205
        }
206
    } else {
207
        return false;
208
    }
209
}
210
211
define('DOKU_MEDIA_DELETED', 1);
212
define('DOKU_MEDIA_NOT_AUTH', 2);
213
define('DOKU_MEDIA_INUSE', 4);
214
define('DOKU_MEDIA_EMPTY_NS', 8);
215
216
/**
217
 * Handles media file deletions
218
 *
219
 * If configured, checks for media references before deletion
220
 *
221
 * @author             Andreas Gohr <[email protected]>
222
 *
223
 * @param string $id media id
224
 * @param int $auth no longer used
225
 * @return int One of: 0,
226
 *                     DOKU_MEDIA_DELETED,
227
 *                     DOKU_MEDIA_DELETED | DOKU_MEDIA_EMPTY_NS,
228
 *                     DOKU_MEDIA_NOT_AUTH,
229
 *                     DOKU_MEDIA_INUSE
230
 */
231
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...
232
    global $lang;
233
    $auth = auth_quickaclcheck(ltrim(getNS($id).':*', ':'));
234
    if($auth < AUTH_DELETE) return DOKU_MEDIA_NOT_AUTH;
235
    if(media_inuse($id)) return DOKU_MEDIA_INUSE;
236
237
    $file = mediaFN($id);
238
239
    // trigger an event - MEDIA_DELETE_FILE
240
    $data = array();
241
    $data['id']   = $id;
242
    $data['name'] = utf8_basename($file);
243
    $data['path'] = $file;
244
    $data['size'] = (file_exists($file)) ? filesize($file) : 0;
245
246
    $data['unl'] = false;
247
    $data['del'] = false;
248
    $evt = new Doku_Event('MEDIA_DELETE_FILE',$data);
249
    if ($evt->advise_before()) {
250
        $old = @filemtime($file);
251
        if(!file_exists(mediaFN($id, $old)) && file_exists($file)) {
252
            // add old revision to the attic
253
            media_saveOldRevision($id);
254
        }
255
256
        $data['unl'] = @unlink($file);
257
        if($data['unl']){
258
            addMediaLogEntry(time(), $id, DOKU_CHANGE_TYPE_DELETE, $lang['deleted']);
259
            $data['del'] = io_sweepNS($id,'mediadir');
260
        }
261
    }
262
    $evt->advise_after();
263
    unset($evt);
264
265
    if($data['unl'] && $data['del']){
266
        return DOKU_MEDIA_DELETED | DOKU_MEDIA_EMPTY_NS;
267
    }
268
269
    return $data['unl'] ? DOKU_MEDIA_DELETED : 0;
270
}
271
272
/**
273
 * Handle file uploads via XMLHttpRequest
274
 *
275
 * @param string $ns   target namespace
276
 * @param int    $auth current auth check result
277
 * @return false|string false on error, id of the new file on success
278
 */
279
function media_upload_xhr($ns,$auth){
280
    if(!checkSecurityToken()) return false;
281
    global $INPUT;
282
283
    $id = $INPUT->get->str('qqfile');
284
    list($ext,$mime) = mimetype($id);
285
    $input = fopen("php://input", "r");
286
    if (!($tmp = io_mktmpdir())) return false;
287
    $path = $tmp.'/'.md5($id);
288
    $target = fopen($path, "w");
289
    $realSize = stream_copy_to_stream($input, $target);
290
    fclose($target);
291
    fclose($input);
292
    if (isset($_SERVER["CONTENT_LENGTH"]) && ($realSize != (int)$_SERVER["CONTENT_LENGTH"])){
293
        unlink($path);
294
        return false;
295
    }
296
297
    $res = media_save(
298
        array('name' => $path,
299
            'mime' => $mime,
300
            'ext'  => $ext),
301
        $ns.':'.$id,
302
        (($INPUT->get->str('ow') == 'checked') ? true : false),
303
        $auth,
304
        'copy'
305
    );
306
    unlink($path);
307
    if ($tmp) io_rmdir($tmp, true);
308
    if (is_array($res)) {
309
        msg($res[0], $res[1]);
310
        return false;
311
    }
312
    return $res;
313
}
314
315
/**
316
 * Handles media file uploads
317
 *
318
 * @author Andreas Gohr <[email protected]>
319
 * @author Michael Klier <[email protected]>
320
 *
321
 * @param string     $ns    target namespace
322
 * @param int        $auth  current auth check result
323
 * @param bool|array $file  $_FILES member, $_FILES['upload'] if false
324
 * @return false|string false on error, id of the new file on success
325
 */
326
function media_upload($ns,$auth,$file=false){
327
    if(!checkSecurityToken()) return false;
328
    global $lang;
329
    global $INPUT;
330
331
    // get file and id
332
    $id   = $INPUT->post->str('mediaid');
333
    if (!$file) $file = $_FILES['upload'];
334
    if(empty($id)) $id = $file['name'];
335
336
    // check for errors (messages are done in lib/exe/mediamanager.php)
337
    if($file['error']) return false;
338
339
    // check extensions
340
    list($fext,$fmime) = mimetype($file['name']);
341
    list($iext,$imime) = mimetype($id);
342
    if($fext && !$iext){
343
        // no extension specified in id - read original one
344
        $id   .= '.'.$fext;
345
        $imime = $fmime;
346
    }elseif($fext && $fext != $iext){
347
        // extension was changed, print warning
348
        msg(sprintf($lang['mediaextchange'],$fext,$iext));
349
    }
350
351
    $res = media_save(array('name' => $file['tmp_name'],
352
                            'mime' => $imime,
353
                            'ext'  => $iext), $ns.':'.$id,
354
                      $INPUT->post->bool('ow'), $auth, 'copy_uploaded_file');
355
    if (is_array($res)) {
356
        msg($res[0], $res[1]);
357
        return false;
358
    }
359
    return $res;
360
}
361
362
/**
363
 * An alternative to move_uploaded_file that copies
364
 *
365
 * Using copy, makes sure any setgid bits on the media directory are honored
366
 *
367
 * @see   move_uploaded_file()
368
 *
369
 * @param string $from
370
 * @param string $to
371
 * @return bool
372
 */
373
function copy_uploaded_file($from, $to){
374
    if(!is_uploaded_file($from)) return false;
375
    $ok = copy($from, $to);
376
    @unlink($from);
1 ignored issue
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
377
    return $ok;
378
}
379
380
/**
381
 * This generates an action event and delegates to _media_upload_action().
382
 * Action plugins are allowed to pre/postprocess the uploaded file.
383
 * (The triggered event is preventable.)
384
 *
385
 * Event data:
386
 * $data[0]     fn_tmp:    the temporary file name (read from $_FILES)
387
 * $data[1]     fn:        the file name of the uploaded file
388
 * $data[2]     id:        the future directory id of the uploaded file
389
 * $data[3]     imime:     the mimetype of the uploaded file
390
 * $data[4]     overwrite: if an existing file is going to be overwritten
391
 * $data[5]     move:      name of function that performs move/copy/..
392
 *
393
 * @triggers MEDIA_UPLOAD_FINISH
394
 *
395
 * @param array  $file
396
 * @param string $id   media id
397
 * @param bool   $ow   overwrite?
398
 * @param int    $auth permission level
399
 * @param string $move name of functions that performs move/copy/..
400
 * @return false|array|string
401
 */
402
function media_save($file, $id, $ow, $auth, $move) {
403
    if($auth < AUTH_UPLOAD) {
404
        return array("You don't have permissions to upload files.", -1);
405
    }
406
407
    if (!isset($file['mime']) || !isset($file['ext'])) {
408
        list($ext, $mime) = mimetype($id);
409
        if (!isset($file['mime'])) {
410
            $file['mime'] = $mime;
411
        }
412
        if (!isset($file['ext'])) {
413
            $file['ext'] = $ext;
414
        }
415
    }
416
417
    global $lang, $conf;
418
419
    // get filename
420
    $id   = cleanID($id);
421
    $fn   = mediaFN($id);
422
423
    // get filetype regexp
424
    $types = array_keys(getMimeTypes());
425
    $types = array_map(create_function('$q','return preg_quote($q,"/");'),$types);
426
    $regex = join('|',$types);
427
428
    // because a temp file was created already
429
    if(!preg_match('/\.('.$regex.')$/i',$fn)) {
430
        return array($lang['uploadwrong'],-1);
431
    }
432
433
    //check for overwrite
434
    $overwrite = file_exists($fn);
435
    $auth_ow = (($conf['mediarevisions']) ? AUTH_UPLOAD : AUTH_DELETE);
436
    if($overwrite && (!$ow || $auth < $auth_ow)) {
437
        return array($lang['uploadexist'], 0);
438
    }
439
    // check for valid content
440
    $ok = media_contentcheck($file['name'], $file['mime']);
441
    if($ok == -1){
442
        return array(sprintf($lang['uploadbadcontent'],'.' . $file['ext']),-1);
443
    }elseif($ok == -2){
444
        return array($lang['uploadspam'],-1);
445
    }elseif($ok == -3){
446
        return array($lang['uploadxss'],-1);
447
    }
448
449
    // prepare event data
450
    $data = array();
451
    $data[0] = $file['name'];
452
    $data[1] = $fn;
453
    $data[2] = $id;
454
    $data[3] = $file['mime'];
455
    $data[4] = $overwrite;
456
    $data[5] = $move;
457
458
    // trigger event
459
    return trigger_event('MEDIA_UPLOAD_FINISH', $data, '_media_upload_action', true);
460
}
461
462
/**
463
 * Callback adapter for media_upload_finish() triggered by MEDIA_UPLOAD_FINISH
464
 *
465
 * @author Michael Klier <[email protected]>
466
 *
467
 * @param array $data event data
468
 * @return false|array|string
469
 */
470
function _media_upload_action($data) {
471
    // fixme do further sanity tests of given data?
472
    if(is_array($data) && count($data)===6) {
473
        return media_upload_finish($data[0], $data[1], $data[2], $data[3], $data[4], $data[5]);
474
    } else {
475
        return false; //callback error
476
    }
477
}
478
479
/**
480
 * Saves an uploaded media file
481
 *
482
 * @author Andreas Gohr <[email protected]>
483
 * @author Michael Klier <[email protected]>
484
 * @author Kate Arzamastseva <[email protected]>
485
 *
486
 * @param string $fn_tmp
487
 * @param string $fn
488
 * @param string $id        media id
489
 * @param string $imime     mime type
490
 * @param bool   $overwrite overwrite existing?
491
 * @param string $move      function name
492
 * @return array|string
493
 */
494
function media_upload_finish($fn_tmp, $fn, $id, $imime, $overwrite, $move = 'move_uploaded_file') {
495
    global $conf;
496
    global $lang;
497
    global $REV;
498
499
    $old = @filemtime($fn);
500
    if(!file_exists(mediaFN($id, $old)) && file_exists($fn)) {
501
        // add old revision to the attic if missing
502
        media_saveOldRevision($id);
503
    }
504
505
    // prepare directory
506
    io_createNamespace($id, 'media');
507
508
    if($move($fn_tmp, $fn)) {
509
        @clearstatcache(true,$fn);
1 ignored issue
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
510
        $new = @filemtime($fn);
511
        // Set the correct permission here.
512
        // Always chmod media because they may be saved with different permissions than expected from the php umask.
513
        // (Should normally chmod to $conf['fperm'] only if $conf['fperm'] is set.)
514
        chmod($fn, $conf['fmode']);
515
        msg($lang['uploadsucc'],1);
516
        media_notify($id,$fn,$imime,$old);
517
        // add a log entry to the media changelog
518
        if ($REV){
519
            addMediaLogEntry($new, $id, DOKU_CHANGE_TYPE_REVERT, sprintf($lang['restored'], dformat($REV)), $REV);
520
        } elseif ($overwrite) {
521
            addMediaLogEntry($new, $id, DOKU_CHANGE_TYPE_EDIT);
522
        } else {
523
            addMediaLogEntry($new, $id, DOKU_CHANGE_TYPE_CREATE, $lang['created']);
524
        }
525
        return $id;
526
    }else{
527
        return array($lang['uploadfail'],-1);
528
    }
529
}
530
531
/**
532
 * Moves the current version of media file to the media_attic
533
 * directory
534
 *
535
 * @author Kate Arzamastseva <[email protected]>
536
 *
537
 * @param string $id
538
 * @return int - revision date
539
 */
540
function media_saveOldRevision($id){
541
    global $conf, $lang;
542
543
    $oldf = mediaFN($id);
544
    if(!file_exists($oldf)) return '';
545
    $date = filemtime($oldf);
546
    if (!$conf['mediarevisions']) return $date;
547
548
    $medialog = new MediaChangeLog($id);
549
    if (!$medialog->getRevisionInfo($date)) {
550
        // there was an external edit,
551
        // there is no log entry for current version of file
552
        if (!file_exists(mediaMetaFN($id,'.changes'))) {
553
            addMediaLogEntry($date, $id, DOKU_CHANGE_TYPE_CREATE, $lang['created']);
554
        } else {
555
            addMediaLogEntry($date, $id, DOKU_CHANGE_TYPE_EDIT);
556
        }
557
    }
558
559
    $newf = mediaFN($id,$date);
560
    io_makeFileDir($newf);
561
    if(copy($oldf, $newf)) {
562
        // Set the correct permission here.
563
        // Always chmod media because they may be saved with different permissions than expected from the php umask.
564
        // (Should normally chmod to $conf['fperm'] only if $conf['fperm'] is set.)
565
        chmod($newf, $conf['fmode']);
566
    }
567
    return $date;
568
}
569
570
/**
571
 * This function checks if the uploaded content is really what the
572
 * mimetype says it is. We also do spam checking for text types here.
573
 *
574
 * We need to do this stuff because we can not rely on the browser
575
 * to do this check correctly. Yes, IE is broken as usual.
576
 *
577
 * @author Andreas Gohr <[email protected]>
578
 * @link   http://www.splitbrain.org/blog/2007-02/12-internet_explorer_facilitates_cross_site_scripting
579
 * @fixme  check all 26 magic IE filetypes here?
580
 *
581
 * @param string $file path to file
582
 * @param string $mime mimetype
583
 * @return int
584
 */
585
function media_contentcheck($file,$mime){
586
    global $conf;
587
    if($conf['iexssprotect']){
588
        $fh = @fopen($file, 'rb');
589
        if($fh){
590
            $bytes = fread($fh, 256);
591
            fclose($fh);
592
            if(preg_match('/<(script|a|img|html|body|iframe)[\s>]/i',$bytes)){
593
                return -3; //XSS: possibly malicious content
594
            }
595
        }
596
    }
597
    if(substr($mime,0,6) == 'image/'){
598
        $info = @getimagesize($file);
599
        if($mime == 'image/gif' && $info[2] != 1){
600
            return -1; // uploaded content did not match the file extension
601
        }elseif($mime == 'image/jpeg' && $info[2] != 2){
602
            return -1;
603
        }elseif($mime == 'image/png' && $info[2] != 3){
604
            return -1;
605
        }
606
        # fixme maybe check other images types as well
607
    }elseif(substr($mime,0,5) == 'text/'){
608
        global $TEXT;
609
        $TEXT = io_readFile($file);
610
        if(checkwordblock()){
611
            return -2; //blocked by the spam blacklist
612
        }
613
    }
614
    return 0;
615
}
616
617
/**
618
 * Send a notify mail on uploads
619
 *
620
 * @author Andreas Gohr <[email protected]>
621
 *
622
 * @param string   $id      media id
623
 * @param string   $file    path to file
624
 * @param string   $mime    mime type
625
 * @param bool|int $old_rev revision timestamp or false
626
 * @return bool
627
 */
628
function media_notify($id,$file,$mime,$old_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...
629
    global $conf;
630
    if(empty($conf['notify'])) return false; //notify enabled?
631
632
    $subscription = new Subscription();
633
    return $subscription->send_media_diff($conf['notify'], 'uploadmail', $id, $old_rev);
634
}
635
636
/**
637
 * List all files in a given Media namespace
638
 *
639
 * @param string      $ns             namespace
640
 * @param null|int    $auth           permission level
641
 * @param string      $jump           id
642
 * @param bool        $fullscreenview
643
 * @param bool|string $sort           sorting order, false skips sorting
644
 */
645
function media_filelist($ns,$auth=null,$jump='',$fullscreenview=false,$sort=false){
646
    global $conf;
647
    global $lang;
648
    $ns = cleanID($ns);
649
650
    // check auth our self if not given (needed for ajax calls)
651
    if(is_null($auth)) $auth = auth_quickaclcheck("$ns:*");
652
653
    if (!$fullscreenview) echo '<h1 id="media__ns">:'.hsc($ns).'</h1>'.NL;
654
655
    if($auth < AUTH_READ){
656
        // FIXME: print permission warning here instead?
657
        echo '<div class="nothing">'.$lang['nothingfound'].'</div>'.NL;
658
    }else{
659
        if (!$fullscreenview) {
660
            media_uploadform($ns, $auth);
661
            media_searchform($ns);
662
        }
663
664
        $dir = utf8_encodeFN(str_replace(':','/',$ns));
665
        $data = array();
666
        search($data,$conf['mediadir'],'search_media',
667
                array('showmsg'=>true,'depth'=>1),$dir,1,$sort);
668
669
        if(!count($data)){
670
            echo '<div class="nothing">'.$lang['nothingfound'].'</div>'.NL;
671
        }else {
672
            if ($fullscreenview) {
673
                echo '<ul class="' . _media_get_list_type() . '">';
674
            }
675
            foreach($data as $item){
676
                if (!$fullscreenview) {
677
                    media_printfile($item,$auth,$jump);
678
                } else {
679
                    media_printfile_thumbs($item,$auth,$jump);
680
                }
681
            }
682
            if ($fullscreenview) echo '</ul>'.NL;
683
        }
684
    }
685
}
686
687
/**
688
 * Prints tabs for files list actions
689
 *
690
 * @author Kate Arzamastseva <[email protected]>
691
 * @author Adrian Lang <[email protected]>
692
 *
693
 * @param string $selected_tab - opened tab
694
 */
695
696
function media_tabs_files($selected_tab = ''){
697
    global $lang;
698
    $tabs = array();
699
    foreach(array('files'  => 'mediaselect',
700
                  'upload' => 'media_uploadtab',
701
                  'search' => 'media_searchtab') as $tab => $caption) {
702
        $tabs[$tab] = array('href'    => media_managerURL(array('tab_files' => $tab), '&'),
703
                            'caption' => $lang[$caption]);
704
    }
705
706
    html_tabs($tabs, $selected_tab);
707
}
708
709
/**
710
 * Prints tabs for files details actions
711
 *
712
 * @author Kate Arzamastseva <[email protected]>
713
 * @param string $image filename of the current image
714
 * @param string $selected_tab opened tab
715
 */
716
function media_tabs_details($image, $selected_tab = ''){
717
    global $lang, $conf;
718
719
    $tabs = array();
720
    $tabs['view'] = array('href'    => media_managerURL(array('tab_details' => 'view'), '&'),
721
                          'caption' => $lang['media_viewtab']);
722
723
    list(, $mime) = mimetype($image);
724
    if ($mime == 'image/jpeg' && file_exists(mediaFN($image))) {
725
        $tabs['edit'] = array('href'    => media_managerURL(array('tab_details' => 'edit'), '&'),
726
                              'caption' => $lang['media_edittab']);
727
    }
728
    if ($conf['mediarevisions']) {
729
        $tabs['history'] = array('href'    => media_managerURL(array('tab_details' => 'history'), '&'),
730
                                 'caption' => $lang['media_historytab']);
731
    }
732
733
    html_tabs($tabs, $selected_tab);
734
}
735
736
/**
737
 * Prints options for the tab that displays a list of all files
738
 *
739
 * @author Kate Arzamastseva <[email protected]>
740
 */
741
function media_tab_files_options(){
742
    global $lang;
743
    global $INPUT;
744
    global $ID;
745
    $form = new Doku_Form(array('class' => 'options', 'method' => 'get',
746
                                'action' => wl($ID)));
747
    $media_manager_params = media_managerURL(array(), '', false, true);
748
    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...
749
        $form->addHidden($pKey, $pVal);
750
    }
751
    $form->addHidden('sectok', null);
752
    if ($INPUT->has('q')) {
753
        $form->addHidden('q', $INPUT->str('q'));
754
    }
755
    $form->addElement('<ul>'.NL);
756
    foreach(array('list' => array('listType', array('thumbs', 'rows')),
757
                  'sort' => array('sortBy', array('name', 'date')))
758
            as $group => $content) {
759
        $checked = "_media_get_${group}_type";
760
        $checked = $checked();
761
762
        $form->addElement('<li class="' . $content[0] . '">');
763
        foreach($content[1] as $option) {
764
            $attrs = array();
765
            if ($checked == $option) {
766
                $attrs['checked'] = 'checked';
767
            }
768
            $form->addElement(form_makeRadioField($group . '_dwmedia', $option,
769
                                       $lang['media_' . $group . '_' . $option],
770
                                                  $content[0] . '__' . $option,
771
                                                  $option, $attrs));
772
        }
773
        $form->addElement('</li>'.NL);
774
    }
775
    $form->addElement('<li>');
776
    $form->addElement(form_makeButton('submit', '', $lang['btn_apply']));
777
    $form->addElement('</li>'.NL);
778
    $form->addElement('</ul>'.NL);
779
    $form->printForm();
780
}
781
782
/**
783
 * Returns type of sorting for the list of files in media manager
784
 *
785
 * @author Kate Arzamastseva <[email protected]>
786
 *
787
 * @return string - sort type
788
 */
789
function _media_get_sort_type() {
790
    return _media_get_display_param('sort', array('default' => 'name', 'date'));
791
}
792
793
/**
794
 * Returns type of listing for the list of files in media manager
795
 *
796
 * @author Kate Arzamastseva <[email protected]>
797
 *
798
 * @return string - list type
799
 */
800
function _media_get_list_type() {
801
    return _media_get_display_param('list', array('default' => 'thumbs', 'rows'));
802
}
803
804
/**
805
 * Get display parameters
806
 *
807
 * @param string $param   name of parameter
808
 * @param array  $values  allowed values, where default value has index key 'default'
809
 * @return string the parameter value
810
 */
811
function _media_get_display_param($param, $values) {
812
    global $INPUT;
813
    if (in_array($INPUT->str($param), $values)) {
814
        // FIXME: Set cookie
815
        return $INPUT->str($param);
816
    } else {
817
        $val = get_doku_pref($param, $values['default']);
818
        if (!in_array($val, $values)) {
819
            $val = $values['default'];
820
        }
821
        return $val;
822
    }
823
}
824
825
/**
826
 * Prints tab that displays a list of all files
827
 *
828
 * @author Kate Arzamastseva <[email protected]>
829
 *
830
 * @param string    $ns
831
 * @param null|int  $auth permission level
832
 * @param string    $jump item id
833
 */
834
function media_tab_files($ns,$auth=null,$jump='') {
835
    global $lang;
836
    if(is_null($auth)) $auth = auth_quickaclcheck("$ns:*");
837
838
    if($auth < AUTH_READ){
839
        echo '<div class="nothing">'.$lang['media_perm_read'].'</div>'.NL;
840
    }else{
841
        media_filelist($ns,$auth,$jump,true,_media_get_sort_type());
842
    }
843
}
844
845
/**
846
 * Prints tab that displays uploading form
847
 *
848
 * @author Kate Arzamastseva <[email protected]>
849
 *
850
 * @param string   $ns
851
 * @param null|int $auth permission level
852
 * @param string   $jump item id
853
 */
854
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...
855
    global $lang;
856
    if(is_null($auth)) $auth = auth_quickaclcheck("$ns:*");
857
858
    echo '<div class="upload">'.NL;
859
    if ($auth >= AUTH_UPLOAD) {
860
        echo '<p>' . $lang['mediaupload'] . '</p>';
861
    }
862
    media_uploadform($ns, $auth, true);
863
    echo '</div>'.NL;
864
}
865
866
/**
867
 * Prints tab that displays search form
868
 *
869
 * @author Kate Arzamastseva <[email protected]>
870
 *
871
 * @param string $ns
872
 * @param null|int $auth permission level
873
 */
874
function media_tab_search($ns,$auth=null) {
875
    global $INPUT;
876
877
    $do = $INPUT->str('mediado');
878
    $query = $INPUT->str('q');
879
    echo '<div class="search">'.NL;
880
881
    media_searchform($ns, $query, true);
882
    if ($do == 'searchlist' || $query) {
883
        media_searchlist($query,$ns,$auth,true,_media_get_sort_type());
884
    }
885
    echo '</div>'.NL;
886
}
887
888
/**
889
 * Prints tab that displays mediafile details
890
 *
891
 * @author Kate Arzamastseva <[email protected]>
892
 *
893
 * @param string     $image media id
894
 * @param string     $ns
895
 * @param null|int   $auth  permission level
896
 * @param string|int $rev   revision timestamp or empty string
897
 */
898
function media_tab_view($image, $ns, $auth=null, $rev='') {
899
    global $lang;
900
    if(is_null($auth)) $auth = auth_quickaclcheck("$ns:*");
901
902
    if ($image && $auth >= AUTH_READ) {
903
        $meta = new JpegMeta(mediaFN($image, $rev));
904
        media_preview($image, $auth, $rev, $meta);
905
        media_preview_buttons($image, $auth, $rev);
906
        media_details($image, $auth, $rev, $meta);
907
908
    } else {
909
        echo '<div class="nothing">'.$lang['media_perm_read'].'</div>'.NL;
910
    }
911
}
912
913
/**
914
 * Prints tab that displays form for editing mediafile metadata
915
 *
916
 * @author Kate Arzamastseva <[email protected]>
917
 *
918
 * @param string     $image media id
919
 * @param string     $ns
920
 * @param null|int   $auth permission level
921
 */
922
function media_tab_edit($image, $ns, $auth=null) {
923
    if(is_null($auth)) $auth = auth_quickaclcheck("$ns:*");
924
925
    if ($image) {
926
        list(, $mime) = mimetype($image);
927
        if ($mime == 'image/jpeg') media_metaform($image,$auth);
928
    }
929
}
930
931
/**
932
 * Prints tab that displays mediafile revisions
933
 *
934
 * @author Kate Arzamastseva <[email protected]>
935
 *
936
 * @param string     $image media id
937
 * @param string     $ns
938
 * @param null|int   $auth permission level
939
 */
940
function media_tab_history($image, $ns, $auth=null) {
941
    global $lang;
942
    global $INPUT;
943
944
    if(is_null($auth)) $auth = auth_quickaclcheck("$ns:*");
945
    $do = $INPUT->str('mediado');
946
947
    if ($auth >= AUTH_READ && $image) {
948
        if ($do == 'diff'){
949
            media_diff($image, $ns, $auth);
950
        } else {
951
            $first = $INPUT->int('first');
952
            html_revisions($first, $image);
953
        }
954
    } else {
955
        echo '<div class="nothing">'.$lang['media_perm_read'].'</div>'.NL;
956
    }
957
}
958
959
/**
960
 * Prints mediafile details
961
 *
962
 * @param string         $image media id
963
 * @param int            $auth permission level
964
 * @param int|string     $rev revision timestamp or empty string
965
 * @param JpegMeta|bool  $meta
966
 *
967
 * @author Kate Arzamastseva <[email protected]>
968
 */
969
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...
970
971
    $size = media_image_preview_size($image, $rev, $meta);
972
973
    if ($size) {
974
        global $lang;
975
        echo '<div class="image">';
976
977
        $more = array();
978
        if ($rev) {
979
            $more['rev'] = $rev;
980
        } else {
981
            $t = @filemtime(mediaFN($image));
982
            $more['t'] = $t;
983
        }
984
985
        $more['w'] = $size[0];
986
        $more['h'] = $size[1];
987
        $src = ml($image, $more);
988
989
        echo '<a href="'.$src.'" target="_blank" title="'.$lang['mediaview'].'">';
990
        echo '<img src="'.$src.'" alt="" style="max-width: '.$size[0].'px;" />';
991
        echo '</a>';
992
993
        echo '</div>'.NL;
994
    }
995
}
996
997
/**
998
 * Prints mediafile action buttons
999
 *
1000
 * @author Kate Arzamastseva <[email protected]>
1001
 *
1002
 * @param string     $image media id
1003
 * @param int        $auth  permission level
1004
 * @param string|int $rev   revision timestamp, or empty string
1005
 */
1006
function media_preview_buttons($image, $auth, $rev='') {
1007
    global $lang, $conf;
1008
1009
    echo '<ul class="actions">'.NL;
1010
1011
    if($auth >= AUTH_DELETE && !$rev && file_exists(mediaFN($image))){
1012
1013
        // delete button
1014
        $form = new Doku_Form(array('id' => 'mediamanager__btn_delete',
1015
            'action'=>media_managerURL(array('delete' => $image), '&')));
1016
        $form->addElement(form_makeButton('submit','',$lang['btn_delete']));
1017
        echo '<li>';
1018
        $form->printForm();
1019
        echo '</li>'.NL;
1020
    }
1021
1022
    $auth_ow = (($conf['mediarevisions']) ? AUTH_UPLOAD : AUTH_DELETE);
1023
    if($auth >= $auth_ow && !$rev){
1024
1025
        // upload new version button
1026
        $form = new Doku_Form(array('id' => 'mediamanager__btn_update',
1027
            'action'=>media_managerURL(array('image' => $image, 'mediado' => 'update'), '&')));
1028
        $form->addElement(form_makeButton('submit','',$lang['media_update']));
1029
        echo '<li>';
1030
        $form->printForm();
1031
        echo '</li>'.NL;
1032
    }
1033
1034
    if($auth >= AUTH_UPLOAD && $rev && $conf['mediarevisions'] && file_exists(mediaFN($image, $rev))){
1035
1036
        // restore button
1037
        $form = new Doku_Form(array('id' => 'mediamanager__btn_restore',
1038
            'action'=>media_managerURL(array('image' => $image), '&')));
1039
        $form->addHidden('mediado','restore');
1040
        $form->addHidden('rev',$rev);
1041
        $form->addElement(form_makeButton('submit','',$lang['media_restore']));
1042
        echo '<li>';
1043
        $form->printForm();
1044
        echo '</li>'.NL;
1045
    }
1046
1047
    echo '</ul>'.NL;
1048
}
1049
1050
/**
1051
 * Returns image width and height for mediamanager preview panel
1052
 *
1053
 * @author Kate Arzamastseva <[email protected]>
1054
 * @param string         $image
1055
 * @param int|string     $rev
1056
 * @param JpegMeta|bool  $meta
1057
 * @param int            $size
1058
 * @return array|false
1059
 */
1060
function media_image_preview_size($image, $rev, $meta, $size = 500) {
1061
    if (!preg_match("/\.(jpe?g|gif|png)$/", $image) || !file_exists(mediaFN($image, $rev))) return false;
1062
1063
    $info = getimagesize(mediaFN($image, $rev));
1064
    $w = (int) $info[0];
1065
    $h = (int) $info[1];
1066
1067
    if($meta && ($w > $size || $h > $size)){
1068
        $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...
1069
        $w = floor($w * $ratio);
1070
        $h = floor($h * $ratio);
1071
    }
1072
    return array($w, $h);
1073
}
1074
1075
/**
1076
 * Returns the requested EXIF/IPTC tag from the image meta
1077
 *
1078
 * @author Kate Arzamastseva <[email protected]>
1079
 *
1080
 * @param array    $tags array with tags, first existing is returned
1081
 * @param JpegMeta $meta
1082
 * @param string   $alt  alternative value
1083
 * @return string
1084
 */
1085
function media_getTag($tags,$meta,$alt=''){
1086
    if($meta === false) return $alt;
1087
    $info = $meta->getField($tags);
1088
    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...
1089
    return $info;
1090
}
1091
1092
/**
1093
 * Returns mediafile tags
1094
 *
1095
 * @author Kate Arzamastseva <[email protected]>
1096
 *
1097
 * @param JpegMeta $meta
1098
 * @return array list of tags of the mediafile
1099
 */
1100
function media_file_tags($meta) {
1101
    // load the field descriptions
1102
    static $fields = null;
1103
    if(is_null($fields)){
1104
        $config_files = getConfigFiles('mediameta');
1105
        foreach ($config_files as $config_file) {
1106
            if(file_exists($config_file)) include($config_file);
1107
        }
1108
    }
1109
1110
    $tags = array();
1111
1112
    foreach($fields as $key => $tag){
0 ignored issues
show
Bug introduced by
The expression $fields of type null is not traversable.
Loading history...
1113
        $t = array();
1114
        if (!empty($tag[0])) $t = array($tag[0]);
1115
        if(isset($tag[3]) && is_array($tag[3])) $t = array_merge($t,$tag[3]);
1116
        $value = media_getTag($t, $meta);
1117
        $tags[] = array('tag' => $tag, 'value' => $value);
1118
    }
1119
1120
    return $tags;
1121
}
1122
1123
/**
1124
 * Prints mediafile tags
1125
 *
1126
 * @author Kate Arzamastseva <[email protected]>
1127
 *
1128
 * @param string        $image image id
1129
 * @param int           $auth  permission level
1130
 * @param string|int    $rev   revision timestamp, or empty string
1131
 * @param bool|JpegMeta $meta  image object, or create one if false
1132
 */
1133
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...
1134
    global $lang;
1135
1136
    if (!$meta) $meta = new JpegMeta(mediaFN($image, $rev));
1137
    $tags = media_file_tags($meta);
0 ignored issues
show
Bug introduced by
It seems like $meta defined by parameter $meta on line 1133 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...
1138
1139
    echo '<dl>'.NL;
1140
    foreach($tags as $tag){
1141
        if ($tag['value']) {
1142
            $value = cleanText($tag['value']);
1143
            echo '<dt>'.$lang[$tag['tag'][1]].'</dt><dd>';
1144
            if ($tag['tag'][2] == 'date') echo dformat($value);
1145
            else echo hsc($value);
1146
            echo '</dd>'.NL;
1147
        }
1148
    }
1149
    echo '</dl>'.NL;
1150
}
1151
1152
/**
1153
 * Shows difference between two revisions of file
1154
 *
1155
 * @author Kate Arzamastseva <[email protected]>
1156
 *
1157
 * @param string $image  image id
1158
 * @param string $ns
1159
 * @param int $auth permission level
1160
 * @param bool $fromajax
1161
 * @return false|null|string
1162
 */
1163
function media_diff($image, $ns, $auth, $fromajax = false) {
1164
    global $conf;
1165
    global $INPUT;
1166
1167
    if ($auth < AUTH_READ || !$image || !$conf['mediarevisions']) return '';
1168
1169
    $rev1 = $INPUT->int('rev');
1170
1171
    $rev2 = $INPUT->ref('rev2');
1172
    if(is_array($rev2)){
1173
        $rev1 = (int) $rev2[0];
1174
        $rev2 = (int) $rev2[1];
1175
1176
        if(!$rev1){
1177
            $rev1 = $rev2;
1178
            unset($rev2);
1179
        }
1180
    }else{
1181
        $rev2 = $INPUT->int('rev2');
1182
    }
1183
1184
    if ($rev1 && !file_exists(mediaFN($image, $rev1))) $rev1 = false;
1185
    if ($rev2 && !file_exists(mediaFN($image, $rev2))) $rev2 = false;
1186
1187
    if($rev1 && $rev2){            // two specific revisions wanted
1188
        // make sure order is correct (older on the left)
1189
        if($rev1 < $rev2){
1190
            $l_rev = $rev1;
1191
            $r_rev = $rev2;
1192
        }else{
1193
            $l_rev = $rev2;
1194
            $r_rev = $rev1;
1195
        }
1196
    }elseif($rev1){                // single revision given, compare to current
1197
        $r_rev = '';
1198
        $l_rev = $rev1;
1199
    }else{                        // no revision was given, compare previous to current
1200
        $r_rev = '';
1201
        $medialog = new MediaChangeLog($image);
1202
        $revs = $medialog->getRevisions(0, 1);
1203
        if (file_exists(mediaFN($image, $revs[0]))) {
1204
            $l_rev = $revs[0];
1205
        } else {
1206
            $l_rev = '';
1207
        }
1208
    }
1209
1210
    // prepare event data
1211
    $data = array();
1212
    $data[0] = $image;
1213
    $data[1] = $l_rev;
1214
    $data[2] = $r_rev;
1215
    $data[3] = $ns;
1216
    $data[4] = $auth;
1217
    $data[5] = $fromajax;
1218
1219
    // trigger event
1220
    return trigger_event('MEDIA_DIFF', $data, '_media_file_diff', true);
1221
}
1222
1223
/**
1224
 * Callback for media file diff
1225
 *
1226
 * @param array $data event data
1227
 * @return false|null
1228
 */
1229
function _media_file_diff($data) {
1230
    if(is_array($data) && count($data)===6) {
1231
        media_file_diff($data[0], $data[1], $data[2], $data[3], $data[4], $data[5]);
1232
    } else {
1233
        return false;
1234
    }
1235
}
1236
1237
/**
1238
 * Shows difference between two revisions of image
1239
 *
1240
 * @author Kate Arzamastseva <[email protected]>
1241
 *
1242
 * @param string $image
1243
 * @param string|int $l_rev revision timestamp, or empty string
1244
 * @param string|int $r_rev revision timestamp, or empty string
1245
 * @param string $ns
1246
 * @param int $auth permission level
1247
 * @param bool $fromajax
1248
 */
1249
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...
1250
    global $lang;
1251
    global $INPUT;
1252
1253
    $l_meta = new JpegMeta(mediaFN($image, $l_rev));
1254
    $r_meta = new JpegMeta(mediaFN($image, $r_rev));
1255
1256
    $is_img = preg_match('/\.(jpe?g|gif|png)$/', $image);
1257
    if ($is_img) {
1258
        $l_size = media_image_preview_size($image, $l_rev, $l_meta);
1259
        $r_size = media_image_preview_size($image, $r_rev, $r_meta);
1260
        $is_img = ($l_size && $r_size && ($l_size[0] >= 30 || $r_size[0] >= 30));
1261
1262
        $difftype = $INPUT->str('difftype');
1263
1264
        if (!$fromajax) {
1265
            $form = new Doku_Form(array(
1266
                'action' => media_managerURL(array(), '&'),
1267
                'method' => 'get',
1268
                'id' => 'mediamanager__form_diffview',
1269
                'class' => 'diffView'
1270
            ));
1271
            $form->addHidden('sectok', null);
1272
            $form->addElement('<input type="hidden" name="rev2[]" value="'.$l_rev.'" ></input>');
1273
            $form->addElement('<input type="hidden" name="rev2[]" value="'.$r_rev.'" ></input>');
1274
            $form->addHidden('mediado', 'diff');
1275
            $form->printForm();
1276
1277
            echo NL.'<div id="mediamanager__diff" >'.NL;
1278
        }
1279
1280
        if ($difftype == 'opacity' || $difftype == 'portions') {
1281
            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 1258 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 1259 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...
1282
            if (!$fromajax) echo '</div>';
1283
            return;
1284
        }
1285
    }
1286
1287
    list($l_head, $r_head) = html_diff_head($l_rev, $r_rev, $image, true);
1288
1289
    ?>
1290
    <div class="table">
1291
    <table>
1292
      <tr>
1293
        <th><?php echo $l_head; ?></th>
1294
        <th><?php echo $r_head; ?></th>
1295
      </tr>
1296
    <?php
1297
1298
    echo '<tr class="image">';
1299
    echo '<td>';
1300
    media_preview($image, $auth, $l_rev, $l_meta);
1301
    echo '</td>';
1302
1303
    echo '<td>';
1304
    media_preview($image, $auth, $r_rev, $r_meta);
1305
    echo '</td>';
1306
    echo '</tr>'.NL;
1307
1308
    echo '<tr class="actions">';
1309
    echo '<td>';
1310
    media_preview_buttons($image, $auth, $l_rev);
1311
    echo '</td>';
1312
1313
    echo '<td>';
1314
    media_preview_buttons($image, $auth, $r_rev);
1315
    echo '</td>';
1316
    echo '</tr>'.NL;
1317
1318
    $l_tags = media_file_tags($l_meta);
1319
    $r_tags = media_file_tags($r_meta);
1320
    // FIXME r_tags-only stuff
1321
    foreach ($l_tags as $key => $l_tag) {
1322
        if ($l_tag['value'] != $r_tags[$key]['value']) {
1323
            $r_tags[$key]['highlighted'] = true;
1324
            $l_tags[$key]['highlighted'] = true;
1325
        } else if (!$l_tag['value'] || !$r_tags[$key]['value']) {
1326
            unset($r_tags[$key]);
1327
            unset($l_tags[$key]);
1328
        }
1329
    }
1330
1331
    echo '<tr>';
1332
    foreach(array($l_tags,$r_tags) as $tags){
1333
        echo '<td>'.NL;
1334
1335
        echo '<dl class="img_tags">';
1336
        foreach($tags as $tag){
1337
            $value = cleanText($tag['value']);
1338
            if (!$value) $value = '-';
1339
            echo '<dt>'.$lang[$tag['tag'][1]].'</dt>';
1340
            echo '<dd>';
1341
            if ($tag['highlighted']) {
1342
                echo '<strong>';
1343
            }
1344
            if ($tag['tag'][2] == 'date') echo dformat($value);
1345
            else echo hsc($value);
1346
            if ($tag['highlighted']) {
1347
                echo '</strong>';
1348
            }
1349
            echo '</dd>';
1350
        }
1351
        echo '</dl>'.NL;
1352
1353
        echo '</td>';
1354
    }
1355
    echo '</tr>'.NL;
1356
1357
    echo '</table>'.NL;
1358
    echo '</div>'.NL;
1359
1360
    if ($is_img && !$fromajax) echo '</div>';
1361
}
1362
1363
/**
1364
 * Prints two images side by side
1365
 * and slider
1366
 *
1367
 * @author Kate Arzamastseva <[email protected]>
1368
 *
1369
 * @param string $image   image id
1370
 * @param int    $l_rev   revision timestamp, or empty string
1371
 * @param int    $r_rev   revision timestamp, or empty string
1372
 * @param array  $l_size  array with width and height
1373
 * @param array  $r_size  array with width and height
1374
 * @param string $type
1375
 */
1376
function media_image_diff($image, $l_rev, $r_rev, $l_size, $r_size, $type) {
1377
    if ($l_size != $r_size) {
1378
        if ($r_size[0] > $l_size[0]) {
1379
            $l_size = $r_size;
1380
        }
1381
    }
1382
1383
    $l_more = array('rev' => $l_rev, 'h' => $l_size[1], 'w' => $l_size[0]);
1384
    $r_more = array('rev' => $r_rev, 'h' => $l_size[1], 'w' => $l_size[0]);
1385
1386
    $l_src = ml($image, $l_more);
1387
    $r_src = ml($image, $r_more);
1388
1389
    // slider
1390
    echo '<div class="slider" style="max-width: '.($l_size[0]-20).'px;" ></div>'.NL;
1391
1392
    // two images in divs
1393
    echo '<div class="imageDiff ' . $type . '">'.NL;
1394
    echo '<div class="image1" style="max-width: '.$l_size[0].'px;">';
1395
    echo '<img src="'.$l_src.'" alt="" />';
1396
    echo '</div>'.NL;
1397
    echo '<div class="image2" style="max-width: '.$l_size[0].'px;">';
1398
    echo '<img src="'.$r_src.'" alt="" />';
1399
    echo '</div>'.NL;
1400
    echo '</div>'.NL;
1401
}
1402
1403
/**
1404
 * Restores an old revision of a media file
1405
 *
1406
 * @param string $image media id
1407
 * @param int    $rev   revision timestamp or empty string
1408
 * @param int    $auth
1409
 * @return string - file's id
1410
 *
1411
 * @author Kate Arzamastseva <[email protected]>
1412
 */
1413
function media_restore($image, $rev, $auth){
1414
    global $conf;
1415
    if ($auth < AUTH_UPLOAD || !$conf['mediarevisions']) return false;
1416
    $removed = (!file_exists(mediaFN($image)) && file_exists(mediaMetaFN($image, '.changes')));
1417
    if (!$image || (!file_exists(mediaFN($image)) && !$removed)) return false;
1418
    if (!$rev || !file_exists(mediaFN($image, $rev))) return false;
1419
    list(,$imime,) = mimetype($image);
1420
    $res = media_upload_finish(mediaFN($image, $rev),
1421
        mediaFN($image),
1422
        $image,
1423
        $imime,
1424
        true,
1425
        'copy');
1426
    if (is_array($res)) {
1427
        msg($res[0], $res[1]);
1428
        return false;
1429
    }
1430
    return $res;
1431
}
1432
1433
/**
1434
 * List all files found by the search request
1435
 *
1436
 * @author Tobias Sarnowski <[email protected]>
1437
 * @author Andreas Gohr <[email protected]>
1438
 * @author Kate Arzamastseva <[email protected]>
1439
 * @triggers MEDIA_SEARCH
1440
 *
1441
 * @param string $query
1442
 * @param string $ns
1443
 * @param null|int $auth
1444
 * @param bool $fullscreen
1445
 * @param string $sort
1446
 */
1447
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...
1448
    global $conf;
1449
    global $lang;
1450
1451
    $ns = cleanID($ns);
1452
    $evdata = array(
1453
        'ns'    => $ns,
1454
        'data'  => array(),
1455
        'query' => $query
1456
    );
1457
    if ($query) {
1458
        $evt = new Doku_Event('MEDIA_SEARCH', $evdata);
1459
        if ($evt->advise_before()) {
1460
            $dir = utf8_encodeFN(str_replace(':','/',$evdata['ns']));
1461
            $pattern = '/'.preg_quote($evdata['query'],'/').'/i';
1462
            search($evdata['data'],
1463
                    $conf['mediadir'],
1464
                    'search_media',
1465
                    array('showmsg'=>false,'pattern'=>$pattern),
1466
                    $dir,
1467
                    1,
1468
                    $sort);
1469
        }
1470
        $evt->advise_after();
1471
        unset($evt);
1472
    }
1473
1474
    if (!$fullscreen) {
1475
        echo '<h1 id="media__ns">'.sprintf($lang['searchmedia_in'],hsc($ns).':*').'</h1>'.NL;
1476
        media_searchform($ns,$query);
1477
    }
1478
1479
    if(!count($evdata['data'])){
1480
        echo '<div class="nothing">'.$lang['nothingfound'].'</div>'.NL;
1481
    }else {
1482
        if ($fullscreen) {
1483
            echo '<ul class="' . _media_get_list_type() . '">';
1484
        }
1485
        foreach($evdata['data'] as $item){
1486
            if (!$fullscreen) media_printfile($item,$item['perm'],'',true);
1487
            else media_printfile_thumbs($item,$item['perm'],false,true);
1488
        }
1489
        if ($fullscreen) echo '</ul>'.NL;
1490
    }
1491
}
1492
1493
/**
1494
 * Formats and prints one file in the list
1495
 *
1496
 * @param array     $item
1497
 * @param int       $auth              permission level
1498
 * @param string    $jump              item id
1499
 * @param bool      $display_namespace
1500
 */
1501
function media_printfile($item,$auth,$jump,$display_namespace=false){
1502
    global $lang;
1503
1504
    // Prepare zebra coloring
1505
    // I always wanted to use this variable name :-D
1506
    static $twibble = 1;
1507
    $twibble *= -1;
1508
    $zebra = ($twibble == -1) ? 'odd' : 'even';
1509
1510
    // Automatically jump to recent action
1511
    if($jump == $item['id']) {
1512
        $jump = ' id="scroll__here" ';
1513
    }else{
1514
        $jump = '';
1515
    }
1516
1517
    // Prepare fileicons
1518
    list($ext) = mimetype($item['file'],false);
1519
    $class = preg_replace('/[^_\-a-z0-9]+/i','_',$ext);
1520
    $class = 'select mediafile mf_'.$class;
1521
1522
    // Prepare filename
1523
    $file = utf8_decodeFN($item['file']);
1524
1525
    // Prepare info
1526
    $info = '';
1527
    if($item['isimg']){
1528
        $info .= (int) $item['meta']->getField('File.Width');
1529
        $info .= '&#215;';
1530
        $info .= (int) $item['meta']->getField('File.Height');
1531
        $info .= ' ';
1532
    }
1533
    $info .= '<i>'.dformat($item['mtime']).'</i>';
1534
    $info .= ' ';
1535
    $info .= filesize_h($item['size']);
1536
1537
    // output
1538
    echo '<div class="'.$zebra.'"'.$jump.' title="'.hsc($item['id']).'">'.NL;
1539
    if (!$display_namespace) {
1540
        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 1523 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...
1541
    } else {
1542
        echo '<a id="h_:'.$item['id'].'" class="'.$class.'">'.hsc($item['id']).'</a><br/>';
1543
    }
1544
    echo '<span class="info">('.$info.')</span>'.NL;
1545
1546
    // view button
1547
    $link = ml($item['id'],'',true);
1548
    echo ' <a href="'.$link.'" target="_blank"><img src="'.DOKU_BASE.'lib/images/magnifier.png" '.
1549
        'alt="'.$lang['mediaview'].'" title="'.$lang['mediaview'].'" class="btn" /></a>';
1550
1551
    // mediamanager button
1552
    $link = wl('',array('do'=>'media','image'=>$item['id'],'ns'=>getNS($item['id'])));
1553
    echo ' <a href="'.$link.'" target="_blank"><img src="'.DOKU_BASE.'lib/images/mediamanager.png" '.
1554
        'alt="'.$lang['btn_media'].'" title="'.$lang['btn_media'].'" class="btn" /></a>';
1555
1556
    // delete button
1557
    if($item['writable'] && $auth >= AUTH_DELETE){
1558
        $link = DOKU_BASE.'lib/exe/mediamanager.php?delete='.rawurlencode($item['id']).
1559
            '&amp;sectok='.getSecurityToken();
1560
        echo ' <a href="'.$link.'" class="btn_media_delete" title="'.$item['id'].'">'.
1561
            '<img src="'.DOKU_BASE.'lib/images/trash.png" alt="'.$lang['btn_delete'].'" '.
1562
            'title="'.$lang['btn_delete'].'" class="btn" /></a>';
1563
    }
1564
1565
    echo '<div class="example" id="ex_'.str_replace(':','_',$item['id']).'">';
1566
    echo $lang['mediausage'].' <code>{{:'.$item['id'].'}}</code>';
1567
    echo '</div>';
1568
    if($item['isimg']) media_printimgdetail($item);
1569
    echo '<div class="clearer"></div>'.NL;
1570
    echo '</div>'.NL;
1571
}
1572
1573
/**
1574
 * Display a media icon
1575
 *
1576
 * @param string $filename media id
1577
 * @param string $size     the size subfolder, if not specified 16x16 is used
1578
 * @return string html
1579
 */
1580
function media_printicon($filename, $size=''){
1581
    list($ext) = mimetype(mediaFN($filename),false);
1582
1583
    if (file_exists(DOKU_INC.'lib/images/fileicons/'.$size.'/'.$ext.'.png')) {
1584
        $icon = DOKU_BASE.'lib/images/fileicons/'.$size.'/'.$ext.'.png';
1585
    } else {
1586
        $icon = DOKU_BASE.'lib/images/fileicons/'.$size.'/file.png';
1587
    }
1588
1589
    return '<img src="'.$icon.'" alt="'.$filename.'" class="icon" />';
1590
}
1591
1592
/**
1593
 * Formats and prints one file in the list in the thumbnails view
1594
 *
1595
 * @author Kate Arzamastseva <[email protected]>
1596
 *
1597
 * @param array       $item
1598
 * @param int         $auth              permission level
1599
 * @param bool|string $jump              item id
1600
 * @param bool        $display_namespace
1601
 */
1602
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...
1603
1604
    // Prepare filename
1605
    $file = utf8_decodeFN($item['file']);
1606
1607
    // output
1608
    echo '<li><dl title="'.hsc($item['id']).'">'.NL;
1609
1610
        echo '<dt>';
1611
    if($item['isimg']) {
1612
        media_printimgdetail($item, true);
1613
1614
    } else {
1615
        echo '<a id="d_:'.$item['id'].'" class="image" title="'.$item['id'].'" href="'.
1616
            media_managerURL(array('image' => hsc($item['id']), 'ns' => getNS($item['id']),
1617
            'tab_details' => 'view')).'">';
1618
        echo media_printicon($item['id'], '32x32');
1619
        echo '</a>';
1620
    }
1621
    echo '</dt>'.NL;
1622
    if (!$display_namespace) {
1623
        $name = hsc($file);
0 ignored issues
show
Security Bug introduced by
It seems like $file defined by utf8_decodeFN($item['file']) on line 1605 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...
1624
    } else {
1625
        $name = hsc($item['id']);
1626
    }
1627
    echo '<dd class="name"><a href="'.media_managerURL(array('image' => hsc($item['id']), 'ns' => getNS($item['id']),
1628
        'tab_details' => 'view')).'" id="h_:'.$item['id'].'">'.$name.'</a></dd>'.NL;
1629
1630
    if($item['isimg']){
1631
        $size = '';
1632
        $size .= (int) $item['meta']->getField('File.Width');
1633
        $size .= '&#215;';
1634
        $size .= (int) $item['meta']->getField('File.Height');
1635
        echo '<dd class="size">'.$size.'</dd>'.NL;
1636
    } else {
1637
        echo '<dd class="size">&#160;</dd>'.NL;
1638
    }
1639
    $date = dformat($item['mtime']);
1640
    echo '<dd class="date">'.$date.'</dd>'.NL;
1641
    $filesize = filesize_h($item['size']);
1642
    echo '<dd class="filesize">'.$filesize.'</dd>'.NL;
1643
    echo '</dl></li>'.NL;
1644
}
1645
1646
/**
1647
 * Prints a thumbnail and metainfo
1648
 *
1649
 * @param array $item
1650
 * @param bool  $fullscreen
1651
 */
1652
function media_printimgdetail($item, $fullscreen=false){
1653
    // prepare thumbnail
1654
    $size = $fullscreen ? 90 : 120;
1655
1656
    $w = (int) $item['meta']->getField('File.Width');
1657
    $h = (int) $item['meta']->getField('File.Height');
1658
    if($w>$size || $h>$size){
1659
        if (!$fullscreen) {
1660
            $ratio = $item['meta']->getResizeRatio($size);
1661
        } else {
1662
            $ratio = $item['meta']->getResizeRatio($size,$size);
1663
        }
1664
        $w = floor($w * $ratio);
1665
        $h = floor($h * $ratio);
1666
    }
1667
    $src = ml($item['id'],array('w'=>$w,'h'=>$h,'t'=>$item['mtime']));
1668
    $p = array();
1669
    if (!$fullscreen) {
1670
        // In fullscreen mediamanager view, image resizing is done via CSS.
1671
        $p['width']  = $w;
1672
        $p['height'] = $h;
1673
    }
1674
    $p['alt']    = $item['id'];
1675
    $att = buildAttributes($p);
1676
1677
    // output
1678
    if ($fullscreen) {
1679
        echo '<a id="l_:'.$item['id'].'" class="image thumb" href="'.
1680
            media_managerURL(array('image' => hsc($item['id']), 'ns' => getNS($item['id']), 'tab_details' => 'view')).'">';
1681
        echo '<img src="'.$src.'" '.$att.' />';
1682
        echo '</a>';
1683
    }
1684
1685
    if ($fullscreen) return;
1686
1687
    echo '<div class="detail">';
1688
    echo '<div class="thumb">';
1689
    echo '<a id="d_:'.$item['id'].'" class="select">';
1690
    echo '<img src="'.$src.'" '.$att.' />';
1691
    echo '</a>';
1692
    echo '</div>';
1693
1694
    // read EXIF/IPTC data
1695
    $t = $item['meta']->getField(array('IPTC.Headline','xmp.dc:title'));
1696
    $d = $item['meta']->getField(array('IPTC.Caption','EXIF.UserComment',
1697
                'EXIF.TIFFImageDescription',
1698
                'EXIF.TIFFUserComment'));
1699
    if(utf8_strlen($d) > 250) $d = utf8_substr($d,0,250).'...';
1700
    $k = $item['meta']->getField(array('IPTC.Keywords','IPTC.Category','xmp.dc:subject'));
1701
1702
    // print EXIF/IPTC data
1703
    if($t || $d || $k ){
1704
        echo '<p>';
1705
        if($t) echo '<strong>'.htmlspecialchars($t).'</strong><br />';
1706
        if($d) echo htmlspecialchars($d).'<br />';
1707
        if($t) echo '<em>'.htmlspecialchars($k).'</em>';
1708
        echo '</p>';
1709
    }
1710
    echo '</div>';
1711
}
1712
1713
/**
1714
 * Build link based on the current, adding/rewriting parameters
1715
 *
1716
 * @author Kate Arzamastseva <[email protected]>
1717
 *
1718
 * @param array|bool $params
1719
 * @param string     $amp           separator
1720
 * @param bool       $abs           absolute url?
1721
 * @param bool       $params_array  return the parmeters array?
1722
 * @return string|array - link or link parameters
1723
 */
1724
function media_managerURL($params=false, $amp='&amp;', $abs=false, $params_array=false) {
1725
    global $ID;
1726
    global $INPUT;
1727
1728
    $gets = array('do' => 'media');
1729
    $media_manager_params = array('tab_files', 'tab_details', 'image', 'ns', 'list', 'sort');
1730
    foreach ($media_manager_params as $x) {
1731
        if ($INPUT->has($x)) $gets[$x] = $INPUT->str($x);
1732
    }
1733
1734
    if ($params) {
1735
        $gets = $params + $gets;
1736
    }
1737
    unset($gets['id']);
1738
    if (isset($gets['delete'])) {
1739
        unset($gets['image']);
1740
        unset($gets['tab_details']);
1741
    }
1742
1743
    if ($params_array) return $gets;
1744
1745
    return wl($ID,$gets,$abs,$amp);
1746
}
1747
1748
/**
1749
 * Print the media upload form if permissions are correct
1750
 *
1751
 * @author Andreas Gohr <[email protected]>
1752
 * @author Kate Arzamastseva <[email protected]>
1753
 *
1754
 * @param string $ns
1755
 * @param int    $auth permission level
1756
 * @param bool  $fullscreen
1757
 */
1758
function media_uploadform($ns, $auth, $fullscreen = false){
1759
    global $lang;
1760
    global $conf;
1761
    global $INPUT;
1762
1763
    if($auth < AUTH_UPLOAD) {
1764
        echo '<div class="nothing">'.$lang['media_perm_upload'].'</div>'.NL;
1765
        return;
1766
    }
1767
    $auth_ow = (($conf['mediarevisions']) ? AUTH_UPLOAD : AUTH_DELETE);
1768
1769
    $update = false;
1770
    $id = '';
1771
    if ($auth >= $auth_ow && $fullscreen && $INPUT->str('mediado') == 'update') {
1772
        $update = true;
1773
        $id = cleanID($INPUT->str('image'));
1774
    }
1775
1776
    // The default HTML upload form
1777
    $params = array('id'      => 'dw__upload',
1778
                    'enctype' => 'multipart/form-data');
1779
    if (!$fullscreen) {
1780
        $params['action'] = DOKU_BASE.'lib/exe/mediamanager.php';
1781
    } else {
1782
        $params['action'] = media_managerURL(array('tab_files' => 'files',
1783
            'tab_details' => 'view'), '&');
1784
    }
1785
1786
    $form = new Doku_Form($params);
1787
    if (!$fullscreen) echo '<div class="upload">' . $lang['mediaupload'] . '</div>';
1788
    $form->addElement(formSecurityToken());
1789
    $form->addHidden('ns', hsc($ns));
1790
    $form->addElement(form_makeOpenTag('p'));
1791
    $form->addElement(form_makeFileField('upload', $lang['txt_upload'], 'upload__file'));
1792
    $form->addElement(form_makeCloseTag('p'));
1793
    $form->addElement(form_makeOpenTag('p'));
1794
    $form->addElement(form_makeTextField('mediaid', noNS($id), $lang['txt_filename'], 'upload__name'));
1795
    $form->addElement(form_makeButton('submit', '', $lang['btn_upload']));
1796
    $form->addElement(form_makeCloseTag('p'));
1797
1798
    if($auth >= $auth_ow){
1799
        $form->addElement(form_makeOpenTag('p'));
1800
        $attrs = array();
1801
        if ($update) $attrs['checked'] = 'checked';
1802
        $form->addElement(form_makeCheckboxField('ow', 1, $lang['txt_overwrt'], 'dw__ow', 'check', $attrs));
1803
        $form->addElement(form_makeCloseTag('p'));
1804
    }
1805
1806
    echo NL.'<div id="mediamanager__uploader">'.NL;
1807
    html_form('upload', $form);
1808
1809
    echo '</div>'.NL;
1810
1811
    echo '<p class="maxsize">';
1812
    printf($lang['maxuploadsize'],filesize_h(media_getuploadsize()));
1813
    echo '</p>'.NL;
1814
1815
}
1816
1817
/**
1818
 * Returns the size uploaded files may have
1819
 *
1820
 * This uses a conservative approach using the lowest number found
1821
 * in any of the limiting ini settings
1822
 *
1823
 * @returns int size in bytes
1824
 */
1825
function media_getuploadsize(){
1826
    $okay = 0;
1827
1828
    $post = (int) php_to_byte(@ini_get('post_max_size'));
1829
    $suho = (int) php_to_byte(@ini_get('suhosin.post.max_value_length'));
1830
    $upld = (int) php_to_byte(@ini_get('upload_max_filesize'));
1831
1832
    if($post && ($post < $okay || $okay == 0)) $okay = $post;
1833
    if($suho && ($suho < $okay || $okay == 0)) $okay = $suho;
1834
    if($upld && ($upld < $okay || $okay == 0)) $okay = $upld;
1835
1836
    return $okay;
1837
}
1838
1839
/**
1840
 * Print the search field form
1841
 *
1842
 * @author Tobias Sarnowski <[email protected]>
1843
 * @author Kate Arzamastseva <[email protected]>
1844
 *
1845
 * @param string $ns
1846
 * @param string $query
1847
 * @param bool $fullscreen
1848
 */
1849
function media_searchform($ns,$query='',$fullscreen=false){
1850
    global $lang;
1851
1852
    // The default HTML search form
1853
    $params = array('id' => 'dw__mediasearch');
1854
    if (!$fullscreen) {
1855
        $params['action'] = DOKU_BASE.'lib/exe/mediamanager.php';
1856
    } else {
1857
        $params['action'] = media_managerURL(array(), '&');
1858
    }
1859
    $form = new Doku_Form($params);
1860
    $form->addHidden('ns', $ns);
1861
    $form->addHidden($fullscreen ? 'mediado' : 'do', 'searchlist');
1862
1863
    $form->addElement(form_makeOpenTag('p'));
1864
    $form->addElement(form_makeTextField('q', $query,$lang['searchmedia'],'','',array('title'=>sprintf($lang['searchmedia_in'],hsc($ns).':*'))));
1865
    $form->addElement(form_makeButton('submit', '', $lang['btn_search']));
1866
    $form->addElement(form_makeCloseTag('p'));
1867
    html_form('searchmedia', $form);
1868
}
1869
1870
/**
1871
 * Build a tree outline of available media namespaces
1872
 *
1873
 * @author Andreas Gohr <[email protected]>
1874
 *
1875
 * @param string $ns
1876
 */
1877
function media_nstree($ns){
1878
    global $conf;
1879
    global $lang;
1880
1881
    // currently selected namespace
1882
    $ns  = cleanID($ns);
1883
    if(empty($ns)){
1884
        global $ID;
1885
        $ns = (string)getNS($ID);
1886
    }
1887
1888
    $ns_dir  = utf8_encodeFN(str_replace(':','/',$ns));
1889
1890
    $data = array();
1891
    search($data,$conf['mediadir'],'search_index',array('ns' => $ns_dir, 'nofiles' => true));
1892
1893
    // wrap a list with the root level around the other namespaces
1894
    array_unshift($data, array('level' => 0, 'id' => '', 'open' =>'true',
1895
                               'label' => '['.$lang['mediaroot'].']'));
1896
1897
    // insert the current ns into the hierarchy if it isn't already part of it
1898
    $ns_parts = explode(':', $ns);
1899
    $tmp_ns = '';
1900
    $pos = 0;
1901
    foreach ($ns_parts as $level => $part) {
1902
        if ($tmp_ns) $tmp_ns .= ':'.$part;
1903
        else $tmp_ns = $part;
1904
1905
        // find the namespace parts or insert them
1906
        while ($data[$pos]['id'] != $tmp_ns) {
1907
            if ($pos >= count($data) || ($data[$pos]['level'] <= $level+1 && strnatcmp(utf8_encodeFN($data[$pos]['id']), utf8_encodeFN($tmp_ns)) > 0)) {
1908
                array_splice($data, $pos, 0, array(array('level' => $level+1, 'id' => $tmp_ns, 'open' => 'true')));
1909
                break;
1910
            }
1911
            ++$pos;
1912
        }
1913
    }
1914
1915
    echo html_buildlist($data,'idx','media_nstree_item','media_nstree_li');
1916
}
1917
1918
/**
1919
 * Userfunction for html_buildlist
1920
 *
1921
 * Prints a media namespace tree item
1922
 *
1923
 * @author Andreas Gohr <[email protected]>
1924
 *
1925
 * @param array $item
1926
 * @return string html
1927
 */
1928
function media_nstree_item($item){
1929
    global $INPUT;
1930
    $pos   = strrpos($item['id'], ':');
1931
    $label = substr($item['id'], $pos > 0 ? $pos + 1 : 0);
1932
    if(empty($item['label'])) $item['label'] = $label;
1933
1934
    $ret  = '';
1935
    if (!($INPUT->str('do') == 'media'))
1936
    $ret .= '<a href="'.DOKU_BASE.'lib/exe/mediamanager.php?ns='.idfilter($item['id']).'" class="idx_dir">';
1937
    else $ret .= '<a href="'.media_managerURL(array('ns' => idfilter($item['id'], false), 'tab_files' => 'files'))
1938
        .'" class="idx_dir">';
1939
    $ret .= $item['label'];
1940
    $ret .= '</a>';
1941
    return $ret;
1942
}
1943
1944
/**
1945
 * Userfunction for html_buildlist
1946
 *
1947
 * Prints a media namespace tree item opener
1948
 *
1949
 * @author Andreas Gohr <[email protected]>
1950
 *
1951
 * @param array $item
1952
 * @return string html
1953
 */
1954
function media_nstree_li($item){
1955
    $class='media level'.$item['level'];
1956
    if($item['open']){
1957
        $class .= ' open';
1958
        $img   = DOKU_BASE.'lib/images/minus.gif';
1959
        $alt   = '−';
1960
    }else{
1961
        $class .= ' closed';
1962
        $img   = DOKU_BASE.'lib/images/plus.gif';
1963
        $alt   = '+';
1964
    }
1965
    // TODO: only deliver an image if it actually has a subtree...
1966
    return '<li class="'.$class.'">'.
1967
        '<img src="'.$img.'" alt="'.$alt.'" />';
1968
}
1969
1970
/**
1971
 * Resizes the given image to the given size
1972
 *
1973
 * @author  Andreas Gohr <[email protected]>
1974
 *
1975
 * @param string $file filename, path to file
1976
 * @param string $ext  extension
1977
 * @param int    $w    desired width
1978
 * @param int    $h    desired height
1979
 * @return string path to resized or original size if failed
1980
 */
1981
function media_resize_image($file, $ext, $w, $h=0){
1982
    global $conf;
1983
1984
    $info = @getimagesize($file); //get original size
1985
    if($info == false) return $file; // that's no image - it's a spaceship!
1986
1987
    if(!$h) $h = round(($w * $info[1]) / $info[0]);
1988
    if(!$w) $w = round(($h * $info[0]) / $info[1]);
1989
1990
    // we wont scale up to infinity
1991
    if($w > 2000 || $h > 2000) return $file;
1992
1993
    // resize necessary? - (w,h) = native dimensions
1994
    if(($w == $info[0]) && ($h == $info[1])) return $file;
1995
1996
    //cache
1997
    $local = getCacheName($file,'.media.'.$w.'x'.$h.'.'.$ext);
1998
    $mtime = @filemtime($local); // 0 if not exists
1999
2000
    if($mtime > filemtime($file) ||
2001
        media_resize_imageIM($ext, $file, $info[0], $info[1], $local, $w, $h) ||
2002
        media_resize_imageGD($ext, $file, $info[0], $info[1], $local, $w, $h)
2003
    ) {
2004
        if(!empty($conf['fperm'])) @chmod($local, $conf['fperm']);
1 ignored issue
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
2005
        return $local;
2006
    }
2007
    //still here? resizing failed
2008
    return $file;
2009
}
2010
2011
/**
2012
 * Crops the given image to the wanted ratio, then calls media_resize_image to scale it
2013
 * to the wanted size
2014
 *
2015
 * Crops are centered horizontally but prefer the upper third of an vertical
2016
 * image because most pics are more interesting in that area (rule of thirds)
2017
 *
2018
 * @author  Andreas Gohr <[email protected]>
2019
 *
2020
 * @param string $file filename, path to file
2021
 * @param string $ext  extension
2022
 * @param int    $w    desired width
2023
 * @param int    $h    desired height
2024
 * @return string path to resized or original size if failed
2025
 */
2026
function media_crop_image($file, $ext, $w, $h=0){
2027
    global $conf;
2028
2029
    if(!$h) $h = $w;
2030
    $info = @getimagesize($file); //get original size
2031
    if($info == false) return $file; // that's no image - it's a spaceship!
2032
2033
    // calculate crop size
2034
    $fr = $info[0]/$info[1];
2035
    $tr = $w/$h;
2036
2037
    // check if the crop can be handled completely by resize,
2038
    // i.e. the specified width & height match the aspect ratio of the source image
2039
    if ($w == round($h*$fr)) {
2040
        return media_resize_image($file, $ext, $w);
2041
    }
2042
2043
    if($tr >= 1){
2044
        if($tr > $fr){
2045
            $cw = $info[0];
2046
            $ch = (int) ($info[0]/$tr);
2047
        }else{
2048
            $cw = (int) ($info[1]*$tr);
2049
            $ch = $info[1];
2050
        }
2051
    }else{
2052
        if($tr < $fr){
2053
            $cw = (int) ($info[1]*$tr);
2054
            $ch = $info[1];
2055
        }else{
2056
            $cw = $info[0];
2057
            $ch = (int) ($info[0]/$tr);
2058
        }
2059
    }
2060
    // calculate crop offset
2061
    $cx = (int) (($info[0]-$cw)/2);
2062
    $cy = (int) (($info[1]-$ch)/3);
2063
2064
    //cache
2065
    $local = getCacheName($file,'.media.'.$cw.'x'.$ch.'.crop.'.$ext);
2066
    $mtime = @filemtime($local); // 0 if not exists
2067
2068
    if( $mtime > @filemtime($file) ||
2069
            media_crop_imageIM($ext,$file,$info[0],$info[1],$local,$cw,$ch,$cx,$cy) ||
2070
            media_resize_imageGD($ext,$file,$cw,$ch,$local,$cw,$ch,$cx,$cy) ){
2071
        if(!empty($conf['fperm'])) @chmod($local, $conf['fperm']);
1 ignored issue
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
2072
        return media_resize_image($local,$ext, $w, $h);
2073
    }
2074
2075
    //still here? cropping failed
2076
    return media_resize_image($file,$ext, $w, $h);
2077
}
2078
2079
/**
2080
 * Calculate a token to be used to verify fetch requests for resized or
2081
 * cropped images have been internally generated - and prevent external
2082
 * DDOS attacks via fetch
2083
 *
2084
 * @author Christopher Smith <[email protected]>
2085
 *
2086
 * @param string  $id    id of the image
2087
 * @param int     $w     resize/crop width
2088
 * @param int     $h     resize/crop height
2089
 * @return string token or empty string if no token required
2090
 */
2091
function media_get_token($id,$w,$h){
2092
    // token is only required for modified images
2093
    if ($w || $h || media_isexternal($id)) {
2094
        $token = $id;
2095
        if ($w) $token .= '.'.$w;
2096
        if ($h) $token .= '.'.$h;
2097
2098
        return substr(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, 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...
2099
    }
2100
2101
    return '';
2102
}
2103
2104
/**
2105
 * Download a remote file and return local filename
2106
 *
2107
 * returns false if download fails. Uses cached file if available and
2108
 * wanted
2109
 *
2110
 * @author  Andreas Gohr <[email protected]>
2111
 * @author  Pavel Vitis <[email protected]>
2112
 *
2113
 * @param string $url
2114
 * @param string $ext   extension
2115
 * @param int    $cache cachetime in seconds
2116
 * @return false|string path to cached file
2117
 */
2118
function media_get_from_URL($url,$ext,$cache){
2119
    global $conf;
2120
2121
    // if no cache or fetchsize just redirect
2122
    if ($cache==0)           return false;
2123
    if (!$conf['fetchsize']) return false;
2124
2125
    $local = getCacheName(strtolower($url),".media.$ext");
2126
    $mtime = @filemtime($local); // 0 if not exists
2127
2128
    //decide if download needed:
2129
    if(($mtime == 0) || // cache does not exist
2130
        ($cache != -1 && $mtime < time() - $cache) // 'recache' and cache has expired
2131
    ) {
2132
        if(media_image_download($url, $local)) {
2133
            return $local;
2134
        } else {
2135
            return false;
2136
        }
2137
    }
2138
2139
    //if cache exists use it else
2140
    if($mtime) return $local;
2141
2142
    //else return false
2143
    return false;
2144
}
2145
2146
/**
2147
 * Download image files
2148
 *
2149
 * @author Andreas Gohr <[email protected]>
2150
 *
2151
 * @param string $url
2152
 * @param string $file path to file in which to put the downloaded content
2153
 * @return bool
2154
 */
2155
function media_image_download($url,$file){
2156
    global $conf;
2157
    $http = new DokuHTTPClient();
2158
    $http->keep_alive = false; // we do single ops here, no need for keep-alive
0 ignored issues
show
Bug introduced by
The property keep_alive cannot be accessed from this context as it is declared private in class HTTPClient.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
2159
2160
    $http->max_bodysize = $conf['fetchsize'];
0 ignored issues
show
Bug introduced by
The property max_bodysize cannot be accessed from this context as it is declared private in class HTTPClient.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
2161
    $http->timeout = 25; //max. 25 sec
0 ignored issues
show
Bug introduced by
The property timeout cannot be accessed from this context as it is declared private in class HTTPClient.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
2162
    $http->header_regexp = '!\r\nContent-Type: image/(jpe?g|gif|png)!i';
0 ignored issues
show
Bug introduced by
The property header_regexp cannot be accessed from this context as it is declared private in class HTTPClient.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
2163
2164
    $data = $http->get($url);
2165
    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...
2166
2167
    $fileexists = file_exists($file);
2168
    $fp = @fopen($file,"w");
2169
    if(!$fp) return false;
2170
    fwrite($fp,$data);
2171
    fclose($fp);
2172
    if(!$fileexists and $conf['fperm']) chmod($file, $conf['fperm']);
2173
2174
    // check if it is really an image
2175
    $info = @getimagesize($file);
2176
    if(!$info){
2177
        @unlink($file);
1 ignored issue
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
2178
        return false;
2179
    }
2180
2181
    return true;
2182
}
2183
2184
/**
2185
 * resize images using external ImageMagick convert program
2186
 *
2187
 * @author Pavel Vitis <[email protected]>
2188
 * @author Andreas Gohr <[email protected]>
2189
 *
2190
 * @param string $ext     extension
2191
 * @param string $from    filename path to file
2192
 * @param int    $from_w  original width
2193
 * @param int    $from_h  original height
2194
 * @param string $to      path to resized file
2195
 * @param int    $to_w    desired width
2196
 * @param int    $to_h    desired height
2197
 * @return bool
2198
 */
2199
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...
2200
    global $conf;
2201
2202
    // check if convert is configured
2203
    if(!$conf['im_convert']) return false;
2204
2205
    // prepare command
2206
    $cmd  = $conf['im_convert'];
2207
    $cmd .= ' -resize '.$to_w.'x'.$to_h.'!';
2208
    if ($ext == 'jpg' || $ext == 'jpeg') {
2209
        $cmd .= ' -quality '.$conf['jpg_quality'];
2210
    }
2211
    $cmd .= " $from $to";
2212
2213
    @exec($cmd,$out,$retval);
1 ignored issue
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
2214
    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...
2215
    return false;
2216
}
2217
2218
/**
2219
 * crop images using external ImageMagick convert program
2220
 *
2221
 * @author Andreas Gohr <[email protected]>
2222
 *
2223
 * @param string $ext     extension
2224
 * @param string $from    filename path to file
2225
 * @param int    $from_w  original width
2226
 * @param int    $from_h  original height
2227
 * @param string $to      path to resized file
2228
 * @param int    $to_w    desired width
2229
 * @param int    $to_h    desired height
2230
 * @param int    $ofs_x   offset of crop centre
2231
 * @param int    $ofs_y   offset of crop centre
2232
 * @return bool
2233
 */
2234
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...
2235
    global $conf;
2236
2237
    // check if convert is configured
2238
    if(!$conf['im_convert']) return false;
2239
2240
    // prepare command
2241
    $cmd  = $conf['im_convert'];
2242
    $cmd .= ' -crop '.$to_w.'x'.$to_h.'+'.$ofs_x.'+'.$ofs_y;
2243
    if ($ext == 'jpg' || $ext == 'jpeg') {
2244
        $cmd .= ' -quality '.$conf['jpg_quality'];
2245
    }
2246
    $cmd .= " $from $to";
2247
2248
    @exec($cmd,$out,$retval);
1 ignored issue
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
2249
    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...
2250
    return false;
2251
}
2252
2253
/**
2254
 * resize or crop images using PHP's libGD support
2255
 *
2256
 * @author Andreas Gohr <[email protected]>
2257
 * @author Sebastian Wienecke <[email protected]>
2258
 *
2259
 * @param string $ext     extension
2260
 * @param string $from    filename path to file
2261
 * @param int    $from_w  original width
2262
 * @param int    $from_h  original height
2263
 * @param string $to      path to resized file
2264
 * @param int    $to_w    desired width
2265
 * @param int    $to_h    desired height
2266
 * @param int    $ofs_x   offset of crop centre
2267
 * @param int    $ofs_y   offset of crop centre
2268
 * @return bool
2269
 */
2270
function media_resize_imageGD($ext,$from,$from_w,$from_h,$to,$to_w,$to_h,$ofs_x=0,$ofs_y=0){
2271
    global $conf;
2272
2273
    if($conf['gdlib'] < 1) return false; //no GDlib available or wanted
2274
2275
    // check available memory
2276
    if(!is_mem_available(($from_w * $from_h * 4) + ($to_w * $to_h * 4))){
2277
        return false;
2278
    }
2279
2280
    // create an image of the given filetype
2281
    $image = false;
2282
    if ($ext == 'jpg' || $ext == 'jpeg'){
2283
        if(!function_exists("imagecreatefromjpeg")) return false;
2284
        $image = @imagecreatefromjpeg($from);
2285
    }elseif($ext == 'png') {
2286
        if(!function_exists("imagecreatefrompng")) return false;
2287
        $image = @imagecreatefrompng($from);
2288
2289
    }elseif($ext == 'gif') {
2290
        if(!function_exists("imagecreatefromgif")) return false;
2291
        $image = @imagecreatefromgif($from);
2292
    }
2293
    if(!$image) return false;
2294
2295
    $newimg = false;
2296
    if(($conf['gdlib']>1) && function_exists("imagecreatetruecolor") && $ext != 'gif'){
2297
        $newimg = @imagecreatetruecolor ($to_w, $to_h);
2298
    }
2299
    if(!$newimg) $newimg = @imagecreate($to_w, $to_h);
2300
    if(!$newimg){
2301
        imagedestroy($image);
2302
        return false;
2303
    }
2304
2305
    //keep png alpha channel if possible
2306
    if($ext == 'png' && $conf['gdlib']>1 && function_exists('imagesavealpha')){
2307
        imagealphablending($newimg, false);
2308
        imagesavealpha($newimg,true);
2309
    }
2310
2311
    //keep gif transparent color if possible
2312
    if($ext == 'gif' && function_exists('imagefill') && function_exists('imagecolorallocate')) {
2313
        if(function_exists('imagecolorsforindex') && function_exists('imagecolortransparent')) {
2314
            $transcolorindex = @imagecolortransparent($image);
2315
            if($transcolorindex >= 0 ) { //transparent color exists
2316
                $transcolor = @imagecolorsforindex($image, $transcolorindex);
2317
                $transcolorindex = @imagecolorallocate($newimg, $transcolor['red'], $transcolor['green'], $transcolor['blue']);
2318
                @imagefill($newimg, 0, 0, $transcolorindex);
1 ignored issue
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
2319
                @imagecolortransparent($newimg, $transcolorindex);
1 ignored issue
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
2320
            }else{ //filling with white
2321
                $whitecolorindex = @imagecolorallocate($newimg, 255, 255, 255);
2322
                @imagefill($newimg, 0, 0, $whitecolorindex);
1 ignored issue
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
2323
            }
2324
        }else{ //filling with white
2325
            $whitecolorindex = @imagecolorallocate($newimg, 255, 255, 255);
2326
            @imagefill($newimg, 0, 0, $whitecolorindex);
1 ignored issue
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
2327
        }
2328
    }
2329
2330
    //try resampling first
2331
    if(function_exists("imagecopyresampled")){
2332
        if(!@imagecopyresampled($newimg, $image, 0, 0, $ofs_x, $ofs_y, $to_w, $to_h, $from_w, $from_h)) {
2333
            imagecopyresized($newimg, $image, 0, 0, $ofs_x, $ofs_y, $to_w, $to_h, $from_w, $from_h);
2334
        }
2335
    }else{
2336
        imagecopyresized($newimg, $image, 0, 0, $ofs_x, $ofs_y, $to_w, $to_h, $from_w, $from_h);
2337
    }
2338
2339
    $okay = false;
2340
    if ($ext == 'jpg' || $ext == 'jpeg'){
2341
        if(!function_exists('imagejpeg')){
2342
            $okay = false;
2343
        }else{
2344
            $okay = imagejpeg($newimg, $to, $conf['jpg_quality']);
2345
        }
2346
    }elseif($ext == 'png') {
2347
        if(!function_exists('imagepng')){
2348
            $okay = false;
2349
        }else{
2350
            $okay =  imagepng($newimg, $to);
2351
        }
2352
    }elseif($ext == 'gif') {
2353
        if(!function_exists('imagegif')){
2354
            $okay = false;
2355
        }else{
2356
            $okay = imagegif($newimg, $to);
2357
        }
2358
    }
2359
2360
    // destroy GD image ressources
2361
    if($image) imagedestroy($image);
2362
    if($newimg) imagedestroy($newimg);
2363
2364
    return $okay;
2365
}
2366
2367
/**
2368
 * Return other media files with the same base name
2369
 * but different extensions.
2370
 *
2371
 * @param string   $src     - ID of media file
2372
 * @param string[] $exts    - alternative extensions to find other files for
2373
 * @return array            - array(mime type => file ID)
2374
 *
2375
 * @author Anika Henke <[email protected]>
2376
 */
2377
function media_alternativefiles($src, $exts){
2378
2379
    $files = array();
2380
    list($srcExt, /* $srcMime */) = mimetype($src);
2381
    $filebase = substr($src, 0, -1 * (strlen($srcExt)+1));
2382
2383
    foreach($exts as $ext) {
2384
        $fileid = $filebase.'.'.$ext;
2385
        $file = mediaFN($fileid);
2386
        if(file_exists($file)) {
2387
            list(/* $fileExt */, $fileMime) = mimetype($file);
2388
            $files[$fileMime] = $fileid;
2389
        }
2390
    }
2391
    return $files;
2392
}
2393
2394
/**
2395
 * Check if video/audio is supported to be embedded.
2396
 *
2397
 * @param string $mime      - mimetype of media file
2398
 * @param string $type      - type of media files to check ('video', 'audio', or null for all)
2399
 * @return boolean
2400
 *
2401
 * @author Anika Henke <[email protected]>
2402
 */
2403
function media_supportedav($mime, $type=NULL){
2404
    $supportedAudio = array(
2405
        'ogg' => 'audio/ogg',
2406
        'mp3' => 'audio/mpeg',
2407
        'wav' => 'audio/wav',
2408
    );
2409
    $supportedVideo = array(
2410
        'webm' => 'video/webm',
2411
        'ogv' => 'video/ogg',
2412
        'mp4' => 'video/mp4',
2413
    );
2414
    if ($type == 'audio') {
2415
        $supportedAv = $supportedAudio;
2416
    } elseif ($type == 'video') {
2417
        $supportedAv = $supportedVideo;
2418
    } else {
2419
        $supportedAv = array_merge($supportedAudio, $supportedVideo);
2420
    }
2421
    return in_array($mime, $supportedAv);
2422
}
2423
2424
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
2425