xref: /dokuwiki/inc/media.php (revision 06ba4d1a8bd81e47efcec783875bc93cfaf694da)
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 <andi@splitbrain.org>
7 */
8
9if(!defined('DOKU_INC')) define('DOKU_INC',fullpath(dirname(__FILE__).'/../').'/');
10if(!defined('NL')) define('NL',"\n");
11
12require_once(DOKU_INC.'inc/html.php');
13require_once(DOKU_INC.'inc/search.php');
14require_once(DOKU_INC.'inc/JpegMeta.php');
15
16/**
17 * Lists pages which currently use a media file selected for deletion
18 *
19 * References uses the same visual as search results and share
20 * their CSS tags except pagenames won't be links.
21 *
22 * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
23 */
24function media_filesinuse($data,$id){
25    global $lang;
26    echo '<h1>'.$lang['reference'].' <code>'.hsc(noNS($id)).'</code></h1>';
27    echo '<p>'.hsc($lang['ref_inuse']).'</p>';
28
29    $hidden=0; //count of hits without read permission
30    foreach($data as $row){
31        if(auth_quickaclcheck($row) >= AUTH_READ && isVisiblePage($row)){
32            echo '<div class="search_result">';
33            echo '<span class="mediaref_ref">'.hsc($row).'</span>';
34            echo '</div>';
35        }else
36        $hidden++;
37    }
38    if ($hidden){
39      print '<div class="mediaref_hidden">'.$lang['ref_hidden'].'</div>';
40    }
41}
42
43/**
44 * Handles the saving of image meta data
45 *
46 * @author Andreas Gohr <andi@splitbrain.org>
47 */
48function media_metasave($id,$auth,$data){
49    if($auth < AUTH_UPLOAD) return false;
50    if(!checkSecurityToken()) return false;
51    global $lang;
52    global $conf;
53    $src = mediaFN($id);
54
55    $meta = new JpegMeta($src);
56    $meta->_parseAll();
57
58    foreach($data as $key => $val){
59        $val=trim($val);
60        if(empty($val)){
61            $meta->deleteField($key);
62        }else{
63            $meta->setField($key,$val);
64        }
65    }
66
67    if($meta->save()){
68        if($conf['fperm']) chmod($src, $conf['fperm']);
69        msg($lang['metasaveok'],1);
70        return $id;
71    }else{
72        msg($lang['metasaveerr'],-1);
73        return false;
74    }
75}
76
77/**
78 * Display the form to edit image meta data
79 *
80 * @author Andreas Gohr <andi@splitbrain.org>
81 */
82function media_metaform($id,$auth){
83    if($auth < AUTH_UPLOAD) return false;
84    global $lang;
85
86    // load the field descriptions
87    static $fields = null;
88    if(is_null($fields)){
89        include(DOKU_CONF.'mediameta.php');
90        if(@file_exists(DOKU_CONF.'mediameta.local.php')){
91            include(DOKU_CONF.'mediameta.local.php');
92        }
93    }
94
95    $src = mediaFN($id);
96
97    // output
98    echo '<h1>'.hsc(noNS($id)).'</h1>'.NL;
99    echo '<form action="'.DOKU_BASE.'lib/exe/mediamanager.php" accept-charset="utf-8" method="post" class="meta">'.NL;
100    formSecurityToken();
101    foreach($fields as $key => $field){
102        // get current value
103        $tags = array($field[0]);
104        if(is_array($field[3])) $tags = array_merge($tags,$field[3]);
105        $value = tpl_img_getTag($tags,'',$src);
106        $value = cleanText($value);
107
108        // prepare attributes
109        $p = array();
110        $p['class'] = 'edit';
111        $p['id']    = 'meta__'.$key;
112        $p['name']  = 'meta['.$field[0].']';
113
114        // put label
115        echo '<div class="metafield">';
116        echo '<label for="meta__'.$key.'">';
117        echo ($lang[$field[1]]) ? $lang[$field[1]] : $field[1];
118        echo ':</label>';
119
120        // put input field
121        if($field[2] == 'text'){
122            $p['value'] = $value;
123            $p['type']  = 'text';
124            $att = buildAttributes($p);
125            echo "<input $att/>".NL;
126        }else{
127            $att = buildAttributes($p);
128            echo "<textarea $att rows=\"6\" cols=\"50\">".formText($value).'</textarea>'.NL;
129        }
130        echo '</div>'.NL;
131    }
132    echo '<div class="buttons">'.NL;
133    echo '<input type="hidden" name="img" value="'.hsc($id).'" />'.NL;
134    echo '<input name="do[save]" type="submit" value="'.$lang['btn_save'].
135         '" title="ALT+S" accesskey="s" class="button" />'.NL;
136    echo '<input name="do[cancel]" type="submit" value="'.$lang['btn_cancel'].
137         '" title="ALT+C" accesskey="c" class="button" />'.NL;
138    echo '</div>'.NL;
139    echo '</form>'.NL;
140}
141
142
143/**
144 * Handles media file deletions
145 *
146 * If configured, checks for media references before deletion
147 *
148 * @author Andreas Gohr <andi@splitbrain.org>
149 * @return mixed false on error, true on delete or array with refs
150 */
151function media_delete($id,$auth){
152    if($auth < AUTH_DELETE) return false;
153    if(!checkSecurityToken()) return false;
154    global $conf;
155    global $lang;
156
157    // check for references if needed
158    $mediareferences = array();
159    if($conf['refcheck']){
160        require_once(DOKU_INC.'inc/fulltext.php');
161        $mediareferences = ft_mediause($id,$conf['refshow']);
162    }
163
164    if(!count($mediareferences)){
165        $file = mediaFN($id);
166        if(@unlink($file)){
167            msg(str_replace('%s',noNS($id),$lang['deletesucc']),1);
168            $del = io_sweepNS($id,'mediadir');
169            if($del){
170                // current namespace was removed. redirecting to root ns passing msg along
171                header('Location: '.DOKU_URL.'lib/exe/mediamanager.php?msg1='.
172                        rawurlencode(str_replace('%s',noNS($id),$lang['deletesucc'])));
173                exit;
174            }
175            return true;
176        }
177        //something went wrong
178        msg(str_replace('%s',$file,$lang['deletefail']),-1);
179        return false;
180    }elseif(!$conf['refshow']){
181        msg(str_replace('%s',noNS($id),$lang['mediainuse']),0);
182        return false;
183    }
184
185    return $mediareferences;
186}
187
188/**
189 * Handles media file uploads
190 *
191 * This generates an action event and delegates to _media_upload_action().
192 * Action plugins are allowed to pre/postprocess the uploaded file.
193 * (The triggered event is preventable.)
194 *
195 * Event data:
196 * $data[0]     fn_tmp: the temporary file name (read from $_FILES)
197 * $data[1]     fn: the file name of the uploaded file
198 * $data[2]     id: the future directory id of the uploaded file
199 * $data[3]     imime: the mimetype of the uploaded file
200 *
201 * @triggers MEDIA_UPLOAD_FINISH
202 * @author Andreas Gohr <andi@splitbrain.org>
203 * @author Michael Klier <chi@chimeric.de>
204 * @return mixed false on error, id of the new file on success
205 */
206function media_upload($ns,$auth){
207    if($auth < AUTH_UPLOAD) return false;
208    if(!checkSecurityToken()) return false;
209    require_once(DOKU_INC.'inc/confutils.php');
210    global $lang;
211    global $conf;
212
213    // get file and id
214    $id   = $_POST['id'];
215    $file = $_FILES['upload'];
216    if(empty($id)) $id = $file['name'];
217
218    // check for data
219    if(!@filesize($file['tmp_name'])){
220        msg('No data uploaded. Disk full?',-1);
221        return false;
222    }
223
224    // check extensions
225    list($fext,$fmime) = mimetype($file['name']);
226    list($iext,$imime) = mimetype($id);
227    if($fext && !$iext){
228        // no extension specified in id - read original one
229        $id   .= '.'.$fext;
230        $imime = $fmime;
231    }elseif($fext && $fext != $iext){
232        // extension was changed, print warning
233        msg(sprintf($lang['mediaextchange'],$fext,$iext));
234    }
235
236    // get filename
237    $id   = cleanID($ns.':'.$id);
238    $fn   = mediaFN($id);
239
240    // get filetype regexp
241    $types = array_keys(getMimeTypes());
242    $types = array_map(create_function('$q','return preg_quote($q,"/");'),$types);
243    $regex = join('|',$types);
244
245    // because a temp file was created already
246    if(preg_match('/\.('.$regex.')$/i',$fn)){
247        //check for overwrite
248        if(@file_exists($fn) && (!$_REQUEST['ow'] || $auth < AUTH_DELETE)){
249            msg($lang['uploadexist'],0);
250            return false;
251        }
252        // check for valid content
253        $ok = media_contentcheck($file['tmp_name'],$imime);
254        if($ok == -1){
255            msg(sprintf($lang['uploadbadcontent'],".$iext"),-1);
256            return false;
257        }elseif($ok == -2){
258            msg($lang['uploadspam'],-1);
259            return false;
260        }elseif($ok == -3){
261            msg($lang['uploadxss'],-1);
262            return false;
263        }
264
265        // prepare event data
266        $data[0] = $file['tmp_name'];
267        $data[1] = $fn;
268        $data[2] = $id;
269        $data[3] = $imime;
270
271        // trigger event
272        return trigger_event('MEDIA_UPLOAD_FINISH', $data, '_media_upload_action', true);
273
274    }else{
275        msg($lang['uploadwrong'],-1);
276    }
277    return false;
278}
279
280/**
281 * Callback adapter for media_upload_finish()
282 * @author Michael Klier <chi@chimeric.de>
283 */
284function _media_upload_action($data) {
285    // fixme do further sanity tests of given data?
286    if(is_array($data) && count($data)===4) {
287        return media_upload_finish($data[0], $data[1], $data[2], $data[3]);
288    } else {
289        return false; //callback error
290    }
291}
292
293/**
294 * Saves an uploaded media file
295 *
296 * @author Andreas Gohr <andi@splitbrain.org>
297 * @author Michael Klier <chi@chimeric.de>
298 */
299function media_upload_finish($fn_tmp, $fn, $id, $imime) {
300    global $conf;
301    global $lang;
302
303    // prepare directory
304    io_createNamespace($id, 'media');
305
306    if(move_uploaded_file($fn_tmp, $fn)) {
307        // Set the correct permission here.
308        // Always chmod media because they may be saved with different permissions than expected from the php umask.
309        // (Should normally chmod to $conf['fperm'] only if $conf['fperm'] is set.)
310        chmod($fn, $conf['fmode']);
311        msg($lang['uploadsucc'],1);
312        media_notify($id,$fn,$imime);
313        return $id;
314    }else{
315        msg($lang['uploadfail'],-1);
316    }
317}
318
319/**
320 * This function checks if the uploaded content is really what the
321 * mimetype says it is. We also do spam checking for text types here.
322 *
323 * We need to do this stuff because we can not rely on the browser
324 * to do this check correctly. Yes, IE is broken as usual.
325 *
326 * @author Andreas Gohr <andi@splitbrain.org>
327 * @link   http://www.splitbrain.org/blog/2007-02/12-internet_explorer_facilitates_cross_site_scripting
328 * @fixme  check all 26 magic IE filetypes here?
329 */
330function media_contentcheck($file,$mime){
331    global $conf;
332    if($conf['iexssprotect']){
333        $fh = @fopen($file, 'rb');
334        if($fh){
335            $bytes = fread($fh, 256);
336            fclose($fh);
337            if(preg_match('/<(script|a|img|html|body|iframe)[\s>]/i',$bytes)){
338                return -3;
339            }
340        }
341    }
342    if(substr($mime,0,6) == 'image/'){
343        $info = @getimagesize($file);
344        if($mime == 'image/gif' && $info[2] != 1){
345            return -1;
346        }elseif($mime == 'image/jpeg' && $info[2] != 2){
347            return -1;
348        }elseif($mime == 'image/png' && $info[2] != 3){
349            return -1;
350        }
351        # fixme maybe check other images types as well
352    }elseif(substr($mime,0,5) == 'text/'){
353        global $TEXT;
354        $TEXT = io_readFile($file);
355        if(checkwordblock()){
356            return -2;
357        }
358    }
359    return 0;
360}
361
362/**
363 * Send a notify mail on uploads
364 *
365 * @author Andreas Gohr <andi@splitbrain.org>
366 */
367function media_notify($id,$file,$mime){
368    global $lang;
369    global $conf;
370    if(empty($conf['notify'])) return; //notify enabled?
371
372    $text = rawLocale('uploadmail');
373    $text = str_replace('@DATE@',strftime($conf['dformat']),$text);
374    $text = str_replace('@BROWSER@',$_SERVER['HTTP_USER_AGENT'],$text);
375    $text = str_replace('@IPADDRESS@',$_SERVER['REMOTE_ADDR'],$text);
376    $text = str_replace('@HOSTNAME@',gethostbyaddr($_SERVER['REMOTE_ADDR']),$text);
377    $text = str_replace('@DOKUWIKIURL@',DOKU_URL,$text);
378    $text = str_replace('@USER@',$_SERVER['REMOTE_USER'],$text);
379    $text = str_replace('@MIME@',$mime,$text);
380    $text = str_replace('@MEDIA@',ml($id,'',true,'&',true),$text);
381    $text = str_replace('@SIZE@',filesize_h(filesize($file)),$text);
382
383    $from = $conf['mailfrom'];
384    $from = str_replace('@USER@',$_SERVER['REMOTE_USER'],$from);
385    $from = str_replace('@NAME@',$INFO['userinfo']['name'],$from);
386    $from = str_replace('@MAIL@',$INFO['userinfo']['mail'],$from);
387
388    $subject = '['.$conf['title'].'] '.$lang['mail_upload'].' '.$id;
389
390    mail_send($conf['notify'],$subject,$text,$from);
391}
392
393/**
394 * List all files in a given Media namespace
395 */
396function media_filelist($ns,$auth=null,$jump=''){
397    global $conf;
398    global $lang;
399    $ns = cleanID($ns);
400
401    // check auth our self if not given (needed for ajax calls)
402    if(is_null($auth)) $auth = auth_quickaclcheck("$ns:*");
403
404    echo '<h1 id="media__ns">:'.hsc($ns).'</h1>'.NL;
405
406    if($auth < AUTH_READ){
407        // FIXME: print permission warning here instead?
408        echo '<div class="nothing">'.$lang['nothingfound'].'</div>'.NL;
409        return;
410    }
411
412    media_uploadform($ns, $auth);
413
414    $dir = utf8_encodeFN(str_replace(':','/',$ns));
415    $data = array();
416    search($data,$conf['mediadir'],'search_media',array('showmsg'=>true),$dir);
417
418    if(!count($data)){
419        echo '<div class="nothing">'.$lang['nothingfound'].'</div>'.NL;
420        return;
421    }
422
423    foreach($data as $item){
424        media_printfile($item,$auth,$jump);
425    }
426}
427
428/**
429 * Print action links for a file depending on filetype
430 * and available permissions
431 *
432 * @todo contains inline javascript
433 */
434function media_fileactions($item,$auth){
435    global $lang;
436
437    // view button
438    $link = ml($item['id'],'',true);
439    echo ' <a href="'.$link.'" target="_blank"><img src="'.DOKU_BASE.'lib/images/magnifier.png" '.
440         'alt="'.$lang['mediaview'].'" title="'.$lang['mediaview'].'" class="btn" /></a>';
441
442
443    // no further actions if not writable
444    if(!$item['writable']) return;
445
446    // delete button
447    if($auth >= AUTH_DELETE){
448        $ask  = addslashes($lang['del_confirm']).'\\n';
449        $ask .= addslashes($item['id']);
450
451        echo ' <a href="'.DOKU_BASE.'lib/exe/mediamanager.php?delete='.rawurlencode($item['id']).
452             '&amp;sectok='.getSecurityToken().'" '.
453             'onclick="return confirm(\''.$ask.'\')" onkeypress="return confirm(\''.$ask.'\')">'.
454             '<img src="'.DOKU_BASE.'lib/images/trash.png" alt="'.$lang['btn_delete'].'" '.
455             'title="'.$lang['btn_delete'].'" class="btn" /></a>';
456    }
457
458    // edit button
459    if($auth >= AUTH_UPLOAD && $item['isimg'] && $item['meta']->getField('File.Mime') == 'image/jpeg'){
460        echo ' <a href="'.DOKU_BASE.'lib/exe/mediamanager.php?edit='.rawurlencode($item['id']).'">'.
461             '<img src="'.DOKU_BASE.'lib/images/pencil.png" alt="'.$lang['metaedit'].'" '.
462             'title="'.$lang['metaedit'].'" class="btn" /></a>';
463    }
464
465}
466
467/**
468 * Formats and prints one file in the list
469 */
470function media_printfile($item,$auth,$jump){
471    global $lang;
472    global $conf;
473
474    // Prepare zebra coloring
475    // I always wanted to use this variable name :-D
476    static $twibble = 1;
477    $twibble *= -1;
478    $zebra = ($twibble == -1) ? 'odd' : 'even';
479
480    // Automatically jump to recent action
481    if($jump == $item['id']) {
482        $jump = ' id="scroll__here" ';
483    }else{
484        $jump = '';
485    }
486
487    // Prepare fileicons
488    list($ext,$mime) = mimetype($item['file']);
489    $class = preg_replace('/[^_\-a-z0-9]+/i','_',$ext);
490    $class = 'select mediafile mf_'.$class;
491
492    // Prepare filename
493    $file = utf8_decodeFN($item['file']);
494
495    // Prepare info
496    $info = '';
497    if($item['isimg']){
498        $info .= (int) $item['meta']->getField('File.Width');
499        $info .= '&#215;';
500        $info .= (int) $item['meta']->getField('File.Height');
501        $info .= ' ';
502    }
503    $info .= '<i>'.strftime($conf['dformat'],$item['mtime']).'</i>';
504    $info .= ' ';
505    $info .= filesize_h($item['size']);
506
507    // ouput
508    echo '<div class="'.$zebra.'"'.$jump.'>'.NL;
509    echo '<a name="h_'.$item['id'].'" class="'.$class.'">'.$file.'</a> ';
510    echo '<span class="info">('.$info.')</span>'.NL;
511    media_fileactions($item,$auth);
512    echo '<div class="example" id="ex_'.str_replace(':','_',$item['id']).'">';
513    echo $lang['mediausage'].' <code>{{:'.$item['id'].'}}</code>';
514    echo '</div>';
515    if($item['isimg']) media_printimgdetail($item);
516    echo '<div class="clearer"></div>'.NL;
517    echo '</div>'.NL;
518}
519
520/**
521 * Prints a thumbnail and metainfos
522 */
523function media_printimgdetail($item){
524    // prepare thumbnail
525    $w = (int) $item['meta']->getField('File.Width');
526    $h = (int) $item['meta']->getField('File.Height');
527    if($w>120 || $h>120){
528        $ratio = $item['meta']->getResizeRatio(120);
529        $w = floor($w * $ratio);
530        $h = floor($h * $ratio);
531    }
532    $src = ml($item['id'],array('w'=>$w,'h'=>$h));
533    $p = array();
534    $p['width']  = $w;
535    $p['height'] = $h;
536    $p['alt']    = $item['id'];
537    $p['class']  = 'thumb';
538    $att = buildAttributes($p);
539
540    // output
541    echo '<div class="detail">';
542    echo '<div class="thumb">';
543    echo '<a name="d_'.$item['id'].'" class="select">';
544    echo '<img src="'.$src.'" '.$att.' />';
545    echo '</a>';
546    echo '</div>';
547
548    // read EXIF/IPTC data
549    $t = $item['meta']->getField(array('IPTC.Headline','xmp.dc:title'));
550    $d = $item['meta']->getField(array('IPTC.Caption','EXIF.UserComment',
551                                       'EXIF.TIFFImageDescription',
552                                       'EXIF.TIFFUserComment'));
553    if(utf8_strlen($d) > 250) $d = utf8_substr($d,0,250).'...';
554    $k = $item['meta']->getField(array('IPTC.Keywords','IPTC.Category','xmp.dc:subject'));
555
556    // print EXIF/IPTC data
557    if($t || $d || $k ){
558        echo '<p>';
559        if($t) echo '<strong>'.htmlspecialchars($t).'</strong><br />';
560        if($d) echo htmlspecialchars($d).'<br />';
561        if($t) echo '<em>'.htmlspecialchars($k).'</em>';
562        echo '</p>';
563    }
564    echo '</div>';
565}
566
567/**
568 * Print the media upload form if permissions are correct
569 *
570 * @author Andreas Gohr <andi@splitbrain.org>
571 */
572function media_uploadform($ns, $auth){
573    global $lang;
574
575    if($auth < AUTH_UPLOAD) return; //fixme print info on missing permissions?
576
577    // The default HTML upload form
578    $form = new Doku_Form('dw__upload', DOKU_BASE.'lib/exe/mediamanager.php', false, 'multipart/form-data');
579    $form->addElement('<div class="upload">' . $lang['mediaupload'] . '</div>');
580    $form->addElement(formSecurityToken());
581    $form->addHidden('ns', hsc($ns));
582    $form->addElement(form_makeOpenTag('p'));
583    $form->addElement(form_makeFileField('upload', $lang['txt_upload'].':', 'upload__file'));
584    $form->addElement(form_makeCloseTag('p'));
585    $form->addElement(form_makeOpenTag('p'));
586    $form->addElement(form_makeTextField('id', '', $lang['txt_filename'].':', 'upload__name'));
587    $form->addElement(form_makeButton('submit', '', $lang['btn_upload']));
588    $form->addElement(form_makeCloseTag('p'));
589
590    if($auth >= AUTH_DELETE){
591      $form->addElement(form_makeOpenTag('p'));
592      $form->addElement(form_makeCheckboxField('ow', 1, $lang['txt_overwrt'], 'dw__ow', 'check'));
593      $form->addElement(form_makeCloseTag('p'));
594    }
595    html_form('upload', $form);
596
597    // prepare flashvars for multiupload
598    $opt = array(
599        'L_gridname'  => $lang['mu_gridname'] ,
600        'L_gridsize'  => $lang['mu_gridsize'] ,
601        'L_gridstat'  => $lang['mu_gridstat'] ,
602        'L_namespace' => $lang['mu_namespace'] ,
603        'L_overwrite' => $lang['txt_overwrt'],
604        'L_browse'    => $lang['mu_browse'],
605        'L_upload'    => $lang['btn_upload'],
606        'L_toobig'    => $lang['mu_toobig'],
607        'L_ready'     => $lang['mu_ready'],
608        'L_done'      => $lang['mu_done'],
609        'L_fail'      => $lang['mu_fail'],
610        'L_authfail'  => $lang['mu_authfail'],
611        'L_progress'  => $lang['mu_progress'],
612        'L_filetypes' => $lang['mu_filetypes'],
613
614        'O_ns'        => ":$ns",
615        'O_backend'   => 'mediamanager.php?'.session_name().'='.session_id(),
616        'O_size'      => php_to_byte(ini_get('upload_max_filesize')),
617        'O_extensions'=> join('|',array_keys(getMimeTypes())),
618        'O_overwrite' => ($auth >= AUTH_DELETE),
619        'O_sectok'    => getSecurityToken(),
620        'O_authtok'   => auth_createToken(),
621    );
622    $var = buildURLparams($opt,'&');
623    // output the flash uploader
624    ?>
625    <div id="dw__flashupload" style="display:none">
626    <div class="upload"><?php echo $lang['mu_intro']?></div>
627    <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="100%" height="100%"
628        codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab">
629        <param name="movie" value="multipleUpload.swf?t=<?=time()?>" />
630        <param name="quality" value="high" />
631        <param name="bgcolor" value="#ffffff" />
632        <param name="FlashVars" value="<?php echo $var?>" />
633        <embed src="multipleUpload.swf?t=<?=time()?>" quality="high" bgcolor="#ffffff"
634            width="100%" height="100%" name="fileUpload" align="middle"
635            play="true" loop="false" quality="high" FlashVars="<?php echo $var?>"
636            allowScriptAccess="sameDomain"
637            type="application/x-shockwave-flash"
638            pluginspage="http://www.macromedia.com/go/getflashplayer">
639        </embed>
640    </object>
641    </div>
642    <?php
643}
644
645/**
646 * Build a tree outline of available media namespaces
647 *
648 * @author Andreas Gohr <andi@splitbrain.org>
649 */
650function media_nstree($ns){
651    global $conf;
652    global $lang;
653
654    // currently selected namespace
655    $ns  = cleanID($ns);
656    if(empty($ns)){
657        $ns = dirname(str_replace(':','/',$ID));
658        if($ns == '.') $ns ='';
659    }
660    $ns  = utf8_encodeFN(str_replace(':','/',$ns));
661
662    $data = array();
663    search($data,$conf['mediadir'],'search_index',array('ns' => $ns, 'nofiles' => true));
664
665    // wrap a list with the root level around the other namespaces
666    $item = array( 'level' => 0, 'id' => '',
667                   'open' =>'true', 'label' => '['.$lang['mediaroot'].']');
668
669    echo '<ul class="idx">';
670    echo media_nstree_li($item);
671    echo media_nstree_item($item);
672    echo html_buildlist($data,'idx','media_nstree_item','media_nstree_li');
673    echo '</li>';
674    echo '</ul>';
675}
676
677/**
678 * Userfunction for html_buildlist
679 *
680 * Prints a media namespace tree item
681 *
682 * @author Andreas Gohr <andi@splitbrain.org>
683 */
684function media_nstree_item($item){
685    $pos   = strrpos($item['id'], ':');
686    $label = substr($item['id'], $pos > 0 ? $pos + 1 : 0);
687    if(!$item['label']) $item['label'] = $label;
688
689    $ret  = '';
690    $ret .= '<a href="'.DOKU_BASE.'lib/exe/mediamanager.php?ns='.idfilter($item['id']).'" class="idx_dir">';
691    $ret .= $item['label'];
692    $ret .= '</a>';
693    return $ret;
694}
695
696/**
697 * Userfunction for html_buildlist
698 *
699 * Prints a media namespace tree item opener
700 *
701 * @author Andreas Gohr <andi@splitbrain.org>
702 */
703function media_nstree_li($item){
704    $class='media level'.$item['level'];
705    if($item['open']){
706        $class .= ' open';
707        $img   = DOKU_BASE.'lib/images/minus.gif';
708        $alt   = '&minus;';
709    }else{
710        $class .= ' closed';
711        $img   = DOKU_BASE.'lib/images/plus.gif';
712        $alt   = '+';
713    }
714    return '<li class="'.$class.'">'.
715           '<img src="'.$img.'" alt="'.$alt.'" />';
716}
717