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 extensions 219 list($fext,$fmime) = mimetype($file['name']); 220 list($iext,$imime) = mimetype($id); 221 if($fext && !$iext){ 222 // no extension specified in id - read original one 223 $id .= '.'.$fext; 224 $imime = $fmime; 225 }elseif($fext && $fext != $iext){ 226 // extension was changed, print warning 227 msg(sprintf($lang['mediaextchange'],$fext,$iext)); 228 } 229 230 // get filename 231 $id = cleanID($ns.':'.$id); 232 $fn = mediaFN($id); 233 234 // get filetype regexp 235 $types = array_keys(getMimeTypes()); 236 $types = array_map(create_function('$q','return preg_quote($q,"/");'),$types); 237 $regex = join('|',$types); 238 239 // because a temp file was created already 240 if(preg_match('/\.('.$regex.')$/i',$fn)){ 241 //check for overwrite 242 if(@file_exists($fn) && (!$_REQUEST['ow'] || $auth < AUTH_DELETE)){ 243 msg($lang['uploadexist'],0); 244 return false; 245 } 246 // check for valid content 247 $ok = media_contentcheck($file['tmp_name'],$imime); 248 if($ok == -1){ 249 msg(sprintf($lang['uploadbadcontent'],".$iext"),-1); 250 return false; 251 }elseif($ok == -2){ 252 msg($lang['uploadspam'],-1); 253 return false; 254 }elseif($ok == -3){ 255 msg($lang['uploadxss'],-1); 256 return false; 257 } 258 259 // prepare event data 260 $data[0] = $file['tmp_name']; 261 $data[1] = $fn; 262 $data[2] = $id; 263 $data[3] = $imime; 264 265 // trigger event 266 return trigger_event('MEDIA_UPLOAD_FINISH', $data, '_media_upload_action', true); 267 268 }else{ 269 msg($lang['uploadwrong'],-1); 270 } 271 return false; 272} 273 274/** 275 * Callback adapter for media_upload_finish() 276 * @author Michael Klier <chi@chimeric.de> 277 */ 278function _media_upload_action($data) { 279 // fixme do further sanity tests of given data? 280 if(is_array($data) && count($data)===4) { 281 return media_upload_finish($data[0], $data[1], $data[2], $data[3]); 282 } else { 283 return false; //callback error 284 } 285} 286 287/** 288 * Saves an uploaded media file 289 * 290 * @author Andreas Gohr <andi@splitbrain.org> 291 * @author Michael Klier <chi@chimeric.de> 292 */ 293function media_upload_finish($fn_tmp, $fn, $id, $imime) { 294 global $conf; 295 global $lang; 296 297 // prepare directory 298 io_createNamespace($id, 'media'); 299 300 if(move_uploaded_file($fn_tmp, $fn)) { 301 // Set the correct permission here. 302 // Always chmod media because they may be saved with different permissions than expected from the php umask. 303 // (Should normally chmod to $conf['fperm'] only if $conf['fperm'] is set.) 304 chmod($fn, $conf['fmode']); 305 msg($lang['uploadsucc'],1); 306 media_notify($id,$fn,$imime); 307 return $id; 308 }else{ 309 msg($lang['uploadfail'],-1); 310 } 311} 312 313/** 314 * This function checks if the uploaded content is really what the 315 * mimetype says it is. We also do spam checking for text types here. 316 * 317 * We need to do this stuff because we can not rely on the browser 318 * to do this check correctly. Yes, IE is broken as usual. 319 * 320 * @author Andreas Gohr <andi@splitbrain.org> 321 * @link http://www.splitbrain.org/blog/2007-02/12-internet_explorer_facilitates_cross_site_scripting 322 * @fixme check all 26 magic IE filetypes here? 323 */ 324function media_contentcheck($file,$mime){ 325 global $conf; 326 if($conf['iexssprotect']){ 327 $fh = @fopen($file, 'rb'); 328 if($fh){ 329 $bytes = fread($fh, 256); 330 fclose($fh); 331 if(preg_match('/<(script|a|img|html|body|iframe)[\s>]/i',$bytes)){ 332 return -3; 333 } 334 } 335 } 336 if(substr($mime,0,6) == 'image/'){ 337 $info = @getimagesize($file); 338 if($mime == 'image/gif' && $info[2] != 1){ 339 return -1; 340 }elseif($mime == 'image/jpeg' && $info[2] != 2){ 341 return -1; 342 }elseif($mime == 'image/png' && $info[2] != 3){ 343 return -1; 344 } 345 # fixme maybe check other images types as well 346 }elseif(substr($mime,0,5) == 'text/'){ 347 global $TEXT; 348 $TEXT = io_readFile($file); 349 if(checkwordblock()){ 350 return -2; 351 } 352 } 353 return 0; 354} 355 356/** 357 * Send a notify mail on uploads 358 * 359 * @author Andreas Gohr <andi@splitbrain.org> 360 */ 361function media_notify($id,$file,$mime){ 362 global $lang; 363 global $conf; 364 if(empty($conf['notify'])) return; //notify enabled? 365 366 $text = rawLocale('uploadmail'); 367 $text = str_replace('@DATE@',strftime($conf['dformat']),$text); 368 $text = str_replace('@BROWSER@',$_SERVER['HTTP_USER_AGENT'],$text); 369 $text = str_replace('@IPADDRESS@',$_SERVER['REMOTE_ADDR'],$text); 370 $text = str_replace('@HOSTNAME@',gethostbyaddr($_SERVER['REMOTE_ADDR']),$text); 371 $text = str_replace('@DOKUWIKIURL@',DOKU_URL,$text); 372 $text = str_replace('@USER@',$_SERVER['REMOTE_USER'],$text); 373 $text = str_replace('@MIME@',$mime,$text); 374 $text = str_replace('@MEDIA@',ml($id,'',true,'&',true),$text); 375 $text = str_replace('@SIZE@',filesize_h(filesize($file)),$text); 376 377 $from = $conf['mailfrom']; 378 $from = str_replace('@USER@',$_SERVER['REMOTE_USER'],$from); 379 $from = str_replace('@NAME@',$INFO['userinfo']['name'],$from); 380 $from = str_replace('@MAIL@',$INFO['userinfo']['mail'],$from); 381 382 $subject = '['.$conf['title'].'] '.$lang['mail_upload'].' '.$id; 383 384 mail_send($conf['notify'],$subject,$text,$from); 385} 386 387/** 388 * List all files in a given Media namespace 389 */ 390function media_filelist($ns,$auth=null,$jump=''){ 391 global $conf; 392 global $lang; 393 $ns = cleanID($ns); 394 395 // check auth our self if not given (needed for ajax calls) 396 if(is_null($auth)) $auth = auth_quickaclcheck("$ns:*"); 397 398 echo '<h1 id="media__ns">:'.hsc($ns).'</h1>'.NL; 399 400 if($auth < AUTH_READ){ 401 // FIXME: print permission warning here instead? 402 echo '<div class="nothing">'.$lang['nothingfound'].'</div>'.NL; 403 return; 404 } 405 406 media_uploadform($ns, $auth); 407 408 $dir = utf8_encodeFN(str_replace(':','/',$ns)); 409 $data = array(); 410 search($data,$conf['mediadir'],'search_media',array('showmsg'=>true),$dir); 411 412 if(!count($data)){ 413 echo '<div class="nothing">'.$lang['nothingfound'].'</div>'.NL; 414 return; 415 } 416 417 foreach($data as $item){ 418 media_printfile($item,$auth,$jump); 419 } 420} 421 422/** 423 * Print action links for a file depending on filetype 424 * and available permissions 425 * 426 * @todo contains inline javascript 427 */ 428function media_fileactions($item,$auth){ 429 global $lang; 430 431 // view button 432 $link = ml($item['id'],'',true); 433 echo ' <a href="'.$link.'" target="_blank"><img src="'.DOKU_BASE.'lib/images/magnifier.png" '. 434 'alt="'.$lang['mediaview'].'" title="'.$lang['mediaview'].'" class="btn" /></a>'; 435 436 437 // no further actions if not writable 438 if(!$item['writable']) return; 439 440 // delete button 441 if($auth >= AUTH_DELETE){ 442 $ask = addslashes($lang['del_confirm']).'\\n'; 443 $ask .= addslashes($item['id']); 444 445 echo ' <a href="'.DOKU_BASE.'lib/exe/mediamanager.php?delete='.rawurlencode($item['id']). 446 '&sectok='.getSecurityToken().'" '. 447 'onclick="return confirm(\''.$ask.'\')" onkeypress="return confirm(\''.$ask.'\')">'. 448 '<img src="'.DOKU_BASE.'lib/images/trash.png" alt="'.$lang['btn_delete'].'" '. 449 'title="'.$lang['btn_delete'].'" class="btn" /></a>'; 450 } 451 452 // edit button 453 if($auth >= AUTH_UPLOAD && $item['isimg'] && $item['meta']->getField('File.Mime') == 'image/jpeg'){ 454 echo ' <a href="'.DOKU_BASE.'lib/exe/mediamanager.php?edit='.rawurlencode($item['id']).'">'. 455 '<img src="'.DOKU_BASE.'lib/images/pencil.png" alt="'.$lang['metaedit'].'" '. 456 'title="'.$lang['metaedit'].'" class="btn" /></a>'; 457 } 458 459} 460 461/** 462 * Formats and prints one file in the list 463 */ 464function media_printfile($item,$auth,$jump){ 465 global $lang; 466 global $conf; 467 468 // Prepare zebra coloring 469 // I always wanted to use this variable name :-D 470 static $twibble = 1; 471 $twibble *= -1; 472 $zebra = ($twibble == -1) ? 'odd' : 'even'; 473 474 // Automatically jump to recent action 475 if($jump == $item['id']) { 476 $jump = ' id="scroll__here" '; 477 }else{ 478 $jump = ''; 479 } 480 481 // Prepare fileicons 482 list($ext,$mime) = mimetype($item['file']); 483 $class = preg_replace('/[^_\-a-z0-9]+/i','_',$ext); 484 $class = 'select mediafile mf_'.$class; 485 486 // Prepare filename 487 $file = utf8_decodeFN($item['file']); 488 489 // Prepare info 490 $info = ''; 491 if($item['isimg']){ 492 $info .= (int) $item['meta']->getField('File.Width'); 493 $info .= '×'; 494 $info .= (int) $item['meta']->getField('File.Height'); 495 $info .= ' '; 496 } 497 $info .= '<i>'.strftime($conf['dformat'],$item['mtime']).'</i>'; 498 $info .= ' '; 499 $info .= filesize_h($item['size']); 500 501 // ouput 502 echo '<div class="'.$zebra.'"'.$jump.'>'.NL; 503 echo '<a name="h_'.$item['id'].'" class="'.$class.'">'.$file.'</a> '; 504 echo '<span class="info">('.$info.')</span>'.NL; 505 media_fileactions($item,$auth); 506 echo '<div class="example" id="ex_'.str_replace(':','_',$item['id']).'">'; 507 echo $lang['mediausage'].' <code>{{:'.$item['id'].'}}</code>'; 508 echo '</div>'; 509 if($item['isimg']) media_printimgdetail($item); 510 echo '<div class="clearer"></div>'.NL; 511 echo '</div>'.NL; 512} 513 514/** 515 * Prints a thumbnail and metainfos 516 */ 517function media_printimgdetail($item){ 518 // prepare thumbnail 519 $w = (int) $item['meta']->getField('File.Width'); 520 $h = (int) $item['meta']->getField('File.Height'); 521 if($w>120 || $h>120){ 522 $ratio = $item['meta']->getResizeRatio(120); 523 $w = floor($w * $ratio); 524 $h = floor($h * $ratio); 525 } 526 $src = ml($item['id'],array('w'=>$w,'h'=>$h)); 527 $p = array(); 528 $p['width'] = $w; 529 $p['height'] = $h; 530 $p['alt'] = $item['id']; 531 $p['class'] = 'thumb'; 532 $att = buildAttributes($p); 533 534 // output 535 echo '<div class="detail">'; 536 echo '<div class="thumb">'; 537 echo '<a name="d_'.$item['id'].'" class="select">'; 538 echo '<img src="'.$src.'" '.$att.' />'; 539 echo '</a>'; 540 echo '</div>'; 541 542 // read EXIF/IPTC data 543 $t = $item['meta']->getField(array('IPTC.Headline','xmp.dc:title')); 544 $d = $item['meta']->getField(array('IPTC.Caption','EXIF.UserComment', 545 'EXIF.TIFFImageDescription', 546 'EXIF.TIFFUserComment')); 547 if(utf8_strlen($d) > 250) $d = utf8_substr($d,0,250).'...'; 548 $k = $item['meta']->getField(array('IPTC.Keywords','IPTC.Category','xmp.dc:subject')); 549 550 // print EXIF/IPTC data 551 if($t || $d || $k ){ 552 echo '<p>'; 553 if($t) echo '<strong>'.htmlspecialchars($t).'</strong><br />'; 554 if($d) echo htmlspecialchars($d).'<br />'; 555 if($t) echo '<em>'.htmlspecialchars($k).'</em>'; 556 echo '</p>'; 557 } 558 echo '</div>'; 559} 560 561/** 562 * Print the media upload form if permissions are correct 563 * 564 * @author Andreas Gohr <andi@splitbrain.org> 565 */ 566function media_uploadform($ns, $auth){ 567 global $lang; 568 569 if($auth < AUTH_UPLOAD) return; //fixme print info on missing permissions? 570 571 // The default HTML upload form 572 $form = new Doku_Form('dw__upload', DOKU_BASE.'lib/exe/mediamanager.php', false, 'multipart/form-data'); 573 $form->addElement('<div class="upload">' . $lang['mediaupload'] . '</div>'); 574 $form->addElement(formSecurityToken()); 575 $form->addHidden('ns', hsc($ns)); 576 $form->addElement(form_makeOpenTag('p')); 577 $form->addElement(form_makeFileField('upload', $lang['txt_upload'].':', 'upload__file')); 578 $form->addElement(form_makeCloseTag('p')); 579 $form->addElement(form_makeOpenTag('p')); 580 $form->addElement(form_makeTextField('id', '', $lang['txt_filename'].':', 'upload__name')); 581 $form->addElement(form_makeButton('submit', '', $lang['btn_upload'])); 582 $form->addElement(form_makeCloseTag('p')); 583 584 if($auth >= AUTH_DELETE){ 585 $form->addElement(form_makeOpenTag('p')); 586 $form->addElement(form_makeCheckboxField('ow', 1, $lang['txt_overwrt'], 'dw__ow', 'check')); 587 $form->addElement(form_makeCloseTag('p')); 588 } 589 html_form('upload', $form); 590 591 // prepare flashvars for multiupload 592 $opt = array( 593 'L_gridname' => $lang['mu_gridname'] , 594 'L_gridsize' => $lang['mu_gridsize'] , 595 'L_gridstat' => $lang['mu_gridstat'] , 596 'L_namespace' => $lang['mu_namespace'] , 597 'L_overwrite' => $lang['txt_overwrt'], 598 'L_browse' => $lang['mu_browse'], 599 'L_upload' => $lang['btn_upload'], 600 'L_toobig' => $lang['mu_toobig'], 601 'L_ready' => $lang['mu_ready'], 602 'L_done' => $lang['mu_done'], 603 'L_fail' => $lang['mu_fail'], 604 'L_authfail' => $lang['mu_authfail'], 605 'L_progress' => $lang['mu_progress'], 606 'L_filetypes' => $lang['mu_filetypes'], 607 608 'O_ns' => ":$ns", 609 'O_backend' => 'mediamanager.php?'.session_name().'='.session_id(), 610 'O_size' => php_to_byte(ini_get('upload_max_filesize')), 611 'O_extensions'=> join('|',array_keys(getMimeTypes())), 612 'O_overwrite' => ($auth >= AUTH_DELETE), 613 'O_sectok' => getSecurityToken(), 614 'O_authtok' => auth_createToken(), 615 ); 616 $var = buildURLparams($opt,'&'); 617 // output the flash uploader 618 ?> 619 <div id="dw__flashupload" style="display:none"> 620 <div class="upload"><?php echo $lang['mu_intro']?></div> 621 <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="100%" height="100%" 622 codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab"> 623 <param name="movie" value="multipleUpload.swf?t=<?=time()?>" /> 624 <param name="quality" value="high" /> 625 <param name="bgcolor" value="#ffffff" /> 626 <param name="FlashVars" value="<?php echo $var?>" /> 627 <embed src="multipleUpload.swf?t=<?=time()?>" quality="high" bgcolor="#ffffff" 628 width="100%" height="100%" name="fileUpload" align="middle" 629 play="true" loop="false" quality="high" FlashVars="<?php echo $var?>" 630 allowScriptAccess="sameDomain" 631 type="application/x-shockwave-flash" 632 pluginspage="http://www.macromedia.com/go/getflashplayer"> 633 </embed> 634 </object> 635 </div> 636 <?php 637} 638 639/** 640 * Build a tree outline of available media namespaces 641 * 642 * @author Andreas Gohr <andi@splitbrain.org> 643 */ 644function media_nstree($ns){ 645 global $conf; 646 global $lang; 647 648 // currently selected namespace 649 $ns = cleanID($ns); 650 if(empty($ns)){ 651 $ns = dirname(str_replace(':','/',$ID)); 652 if($ns == '.') $ns =''; 653 } 654 $ns = utf8_encodeFN(str_replace(':','/',$ns)); 655 656 $data = array(); 657 search($data,$conf['mediadir'],'search_index',array('ns' => $ns, 'nofiles' => true)); 658 659 // wrap a list with the root level around the other namespaces 660 $item = array( 'level' => 0, 'id' => '', 661 'open' =>'true', 'label' => '['.$lang['mediaroot'].']'); 662 663 echo '<ul class="idx">'; 664 echo media_nstree_li($item); 665 echo media_nstree_item($item); 666 echo html_buildlist($data,'idx','media_nstree_item','media_nstree_li'); 667 echo '</li>'; 668 echo '</ul>'; 669} 670 671/** 672 * Userfunction for html_buildlist 673 * 674 * Prints a media namespace tree item 675 * 676 * @author Andreas Gohr <andi@splitbrain.org> 677 */ 678function media_nstree_item($item){ 679 $pos = strrpos($item['id'], ':'); 680 $label = substr($item['id'], $pos > 0 ? $pos + 1 : 0); 681 if(!$item['label']) $item['label'] = $label; 682 683 $ret = ''; 684 $ret .= '<a href="'.DOKU_BASE.'lib/exe/mediamanager.php?ns='.idfilter($item['id']).'" class="idx_dir">'; 685 $ret .= $item['label']; 686 $ret .= '</a>'; 687 return $ret; 688} 689 690/** 691 * Userfunction for html_buildlist 692 * 693 * Prints a media namespace tree item opener 694 * 695 * @author Andreas Gohr <andi@splitbrain.org> 696 */ 697function media_nstree_li($item){ 698 $class='media level'.$item['level']; 699 if($item['open']){ 700 $class .= ' open'; 701 $img = DOKU_BASE.'lib/images/minus.gif'; 702 $alt = '−'; 703 }else{ 704 $class .= ' closed'; 705 $img = DOKU_BASE.'lib/images/plus.gif'; 706 $alt = '+'; 707 } 708 return '<li class="'.$class.'">'. 709 '<img src="'.$img.'" alt="'.$alt.'" />'; 710} 711