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')) die('meh.'); 10if(!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 <matthiasgrimm@users.sourceforge.net> 19 */ 20function media_filesinuse($data,$id){ 21 global $lang; 22 echo '<h1>'.$lang['reference'].' <code>'.hsc(noNS($id)).'</code></h1>'; 23 echo '<p>'.hsc($lang['ref_inuse']).'</p>'; 24 25 $hidden=0; //count of hits without read permission 26 foreach($data as $row){ 27 if(auth_quickaclcheck($row) >= AUTH_READ && isVisiblePage($row)){ 28 echo '<div class="search_result">'; 29 echo '<span class="mediaref_ref">'.hsc($row).'</span>'; 30 echo '</div>'; 31 }else 32 $hidden++; 33 } 34 if ($hidden){ 35 print '<div class="mediaref_hidden">'.$lang['ref_hidden'].'</div>'; 36 } 37} 38 39/** 40 * Handles the saving of image meta data 41 * 42 * @author Andreas Gohr <andi@splitbrain.org> 43 * @author Kate Arzamastseva <pshns@ukr.net> 44 */ 45function media_metasave($id,$auth,$data){ 46 if($auth < AUTH_UPLOAD) return false; 47 if(!checkSecurityToken()) return false; 48 global $lang; 49 global $conf; 50 $src = mediaFN($id); 51 52 $meta = new JpegMeta($src); 53 $meta->_parseAll(); 54 55 foreach($data as $key => $val){ 56 $val=trim($val); 57 if(empty($val)){ 58 $meta->deleteField($key); 59 }else{ 60 $meta->setField($key,$val); 61 } 62 } 63 64 $old = @filemtime($src); 65 if(!@file_exists(mediaFN($id, $old)) && @file_exists($src)) { 66 // add old revision to the attic 67 media_saveOldRevision($id); 68 } 69 70 if($meta->save()){ 71 if($conf['fperm']) chmod($src, $conf['fperm']); 72 73 $new = @filemtime($src); 74 // add a log entry to the media changelog 75 addMediaLogEntry($new, $id, DOKU_CHANGE_TYPE_EDIT, $lang['media_meta_edited']); 76 77 msg($lang['metasaveok'],1); 78 return $id; 79 }else{ 80 msg($lang['metasaveerr'],-1); 81 return false; 82 } 83} 84 85/** 86 * Display the form to edit image meta data 87 * 88 * @author Andreas Gohr <andi@splitbrain.org> 89 * @author Kate Arzamastseva <pshns@ukr.net> 90 */ 91function media_metaform($id,$auth,$fullscreen = false){ 92 global $lang, $config_cascade; 93 94 if($auth < AUTH_UPLOAD) { 95 echo '<div class="nothing">'.$lang['media_perm_upload'].'</div>'.NL; 96 return false; 97 } 98 99 // load the field descriptions 100 static $fields = null; 101 if(is_null($fields)){ 102 $config_files = getConfigFiles('mediameta'); 103 foreach ($config_files as $config_file) { 104 if(@file_exists($config_file)) include($config_file); 105 } 106 } 107 108 $src = mediaFN($id); 109 110 // output 111 if (!$fullscreen) { 112 echo '<h1>'.hsc(noNS($id)).'</h1>'.NL; 113 $action = DOKU_BASE.'lib/exe/mediamanager.php'; 114 } else { 115 $action = media_managerURL(array('tab_details' => 'view'), '&'); 116 } 117 echo '<form action="'.$action.'" id="mediamanager__save_meta" accept-charset="utf-8" method="post" class="meta">'.NL; 118 119 formSecurityToken(); 120 foreach($fields as $key => $field){ 121 // get current value 122 if (empty($field[0])) continue; 123 $tags = array($field[0]); 124 if(is_array($field[3])) $tags = array_merge($tags,$field[3]); 125 $value = tpl_img_getTag($tags,'',$src); 126 $value = cleanText($value); 127 128 // prepare attributes 129 $p = array(); 130 $p['class'] = 'edit'; 131 $p['id'] = 'meta__'.$key; 132 $p['name'] = 'meta['.$field[0].']'; 133 134 // put label 135 echo '<div class="metafield">'; 136 echo '<label for="meta__'.$key.'">'; 137 echo ($lang[$field[1]]) ? $lang[$field[1]] : $field[1]; 138 echo ':</label>'; 139 140 // put input field 141 if($field[2] == 'text'){ 142 $p['value'] = $value; 143 $p['type'] = 'text'; 144 $att = buildAttributes($p); 145 echo "<input $att/>".NL; 146 }else{ 147 $att = buildAttributes($p); 148 echo "<textarea $att rows=\"6\" cols=\"50\">".formText($value).'</textarea>'.NL; 149 } 150 echo '</div>'.NL; 151 } 152 echo '<div class="buttons">'.NL; 153 echo '<input type="hidden" name="img" value="'.hsc($id).'" />'.NL; 154 if (!$fullscreen) { 155 $do = 'do'; 156 } else { 157 echo '<input type="hidden" name="mediado" value="save" />'; 158 $do = 'mediado'; 159 } 160 echo '<input name="'.$do.'[save]" type="submit" value="'.$lang['btn_save']. 161 '" title="'.$lang['btn_save'].' [S]" accesskey="s" class="button" />'.NL; 162 if (!$fullscreen) 163 echo '<input name="do[cancel]" type="submit" value="'.$lang['btn_cancel']. 164 '" title="'.$lang['btn_cancel'].' [C]" accesskey="c" class="button" />'.NL; 165 echo '</div>'.NL; 166 echo '</form>'.NL; 167} 168 169/** 170 * Convenience function to check if a media file is still in use 171 * 172 * @author Michael Klier <chi@chimeric.de> 173 */ 174function media_inuse($id) { 175 global $conf; 176 $mediareferences = array(); 177 if($conf['refcheck']){ 178 $mediareferences = ft_mediause($id,$conf['refshow']); 179 if(!count($mediareferences)) { 180 return false; 181 } else { 182 return $mediareferences; 183 } 184 } else { 185 return false; 186 } 187} 188 189define('DOKU_MEDIA_DELETED', 1); 190define('DOKU_MEDIA_NOT_AUTH', 2); 191define('DOKU_MEDIA_INUSE', 4); 192define('DOKU_MEDIA_EMPTY_NS', 8); 193 194/** 195 * Handles media file deletions 196 * 197 * If configured, checks for media references before deletion 198 * 199 * @author Andreas Gohr <andi@splitbrain.org> 200 * @return int One of: 0, 201 DOKU_MEDIA_DELETED, 202 DOKU_MEDIA_DELETED | DOKU_MEDIA_EMPTY_NS, 203 DOKU_MEDIA_NOT_AUTH, 204 DOKU_MEDIA_INUSE 205 */ 206function media_delete($id,$auth){ 207 global $lang; 208 if($auth < AUTH_DELETE) return DOKU_MEDIA_NOT_AUTH; 209 if(media_inuse($id)) return DOKU_MEDIA_INUSE; 210 211 $file = mediaFN($id); 212 213 // trigger an event - MEDIA_DELETE_FILE 214 $data['id'] = $id; 215 $data['name'] = basename($file); 216 $data['path'] = $file; 217 $data['size'] = (@file_exists($file)) ? filesize($file) : 0; 218 219 $data['unl'] = false; 220 $data['del'] = false; 221 $evt = new Doku_Event('MEDIA_DELETE_FILE',$data); 222 if ($evt->advise_before()) { 223 $old = @filemtime($file); 224 if(!@file_exists(mediaFN($id, $old)) && @file_exists($file)) { 225 // add old revision to the attic 226 media_saveOldRevision($id); 227 } 228 229 $data['unl'] = @unlink($file); 230 if($data['unl']){ 231 addMediaLogEntry(time(), $id, DOKU_CHANGE_TYPE_DELETE, $lang['deleted']); 232 $data['del'] = io_sweepNS($id,'mediadir'); 233 } 234 } 235 $evt->advise_after(); 236 unset($evt); 237 238 if($data['unl'] && $data['del']){ 239 return DOKU_MEDIA_DELETED | DOKU_MEDIA_EMPTY_NS; 240 } 241 242 return $data['unl'] ? DOKU_MEDIA_DELETED : 0; 243} 244 245/** 246 * Handles media file uploads 247 * 248 * @author Andreas Gohr <andi@splitbrain.org> 249 * @author Michael Klier <chi@chimeric.de> 250 * @return mixed false on error, id of the new file on success 251 */ 252function media_upload($ns,$auth){ 253 if(!checkSecurityToken()) return false; 254 global $lang; 255 256 // get file and id 257 $id = $_POST['mediaid']; 258 $file = $_FILES['upload']; 259 if(empty($id)) $id = $file['name']; 260 261 // check for errors (messages are done in lib/exe/mediamanager.php) 262 if($file['error']) return false; 263 264 // check extensions 265 list($fext,$fmime,$dl) = mimetype($file['name']); 266 list($iext,$imime,$dl) = mimetype($id); 267 if($fext && !$iext){ 268 // no extension specified in id - read original one 269 $id .= '.'.$fext; 270 $imime = $fmime; 271 }elseif($fext && $fext != $iext){ 272 // extension was changed, print warning 273 msg(sprintf($lang['mediaextchange'],$fext,$iext)); 274 } 275 276 $res = media_save(array('name' => $file['tmp_name'], 277 'mime' => $imime, 278 'ext' => $iext), $ns.':'.$id, 279 $_REQUEST['ow'], $auth, 'move_uploaded_file'); 280 if (is_array($res)) { 281 msg($res[0], $res[1]); 282 return false; 283 } 284 return $res; 285} 286 287/** 288 * This generates an action event and delegates to _media_upload_action(). 289 * Action plugins are allowed to pre/postprocess the uploaded file. 290 * (The triggered event is preventable.) 291 * 292 * Event data: 293 * $data[0] fn_tmp: the temporary file name (read from $_FILES) 294 * $data[1] fn: the file name of the uploaded file 295 * $data[2] id: the future directory id of the uploaded file 296 * $data[3] imime: the mimetype of the uploaded file 297 * $data[4] overwrite: if an existing file is going to be overwritten 298 * 299 * @triggers MEDIA_UPLOAD_FINISH 300 */ 301function media_save($file, $id, $ow, $auth, $move) { 302 if($auth < AUTH_UPLOAD) { 303 return array("You don't have permissions to upload files.", -1); 304 } 305 306 if (!isset($file['mime']) || !isset($file['ext'])) { 307 list($ext, $mime) = mimetype($id); 308 if (!isset($file['mime'])) { 309 $file['mime'] = $mime; 310 } 311 if (!isset($file['ext'])) { 312 $file['ext'] = $ext; 313 } 314 } 315 316 global $lang; 317 318 // get filename 319 $id = cleanID($id,false,true); 320 $fn = mediaFN($id); 321 322 // get filetype regexp 323 $types = array_keys(getMimeTypes()); 324 $types = array_map(create_function('$q','return preg_quote($q,"/");'),$types); 325 $regex = join('|',$types); 326 327 // because a temp file was created already 328 if(!preg_match('/\.('.$regex.')$/i',$fn)) { 329 return array($lang['uploadwrong'],-1); 330 } 331 332 //check for overwrite 333 $overwrite = @file_exists($fn); 334 if($overwrite && (!$ow || $auth < AUTH_DELETE)) { 335 return array($lang['uploadexist'], 0); 336 } 337 // check for valid content 338 $ok = media_contentcheck($file['name'], $file['mime']); 339 if($ok == -1){ 340 return array(sprintf($lang['uploadbadcontent'],'.' . $file['ext']),-1); 341 }elseif($ok == -2){ 342 return array($lang['uploadspam'],-1); 343 }elseif($ok == -3){ 344 return array($lang['uploadxss'],-1); 345 } 346 347 // prepare event data 348 $data[0] = $file['name']; 349 $data[1] = $fn; 350 $data[2] = $id; 351 $data[3] = $file['mime']; 352 $data[4] = $overwrite; 353 $data[5] = $move; 354 355 // trigger event 356 return trigger_event('MEDIA_UPLOAD_FINISH', $data, '_media_upload_action', true); 357} 358 359/** 360 * Callback adapter for media_upload_finish() 361 * @author Michael Klier <chi@chimeric.de> 362 */ 363function _media_upload_action($data) { 364 // fixme do further sanity tests of given data? 365 if(is_array($data) && count($data)===6) { 366 return media_upload_finish($data[0], $data[1], $data[2], $data[3], $data[4], $data[5]); 367 } else { 368 return false; //callback error 369 } 370} 371 372/** 373 * Saves an uploaded media file 374 * 375 * @author Andreas Gohr <andi@splitbrain.org> 376 * @author Michael Klier <chi@chimeric.de> 377 * @author Kate Arzamastseva <pshns@ukr.net> 378 */ 379function media_upload_finish($fn_tmp, $fn, $id, $imime, $overwrite, $move = 'move_uploaded_file') { 380 global $conf; 381 global $lang; 382 global $REV; 383 384 $old = @filemtime($fn); 385 if(!@file_exists(mediaFN($id, $old)) && @file_exists($fn)) { 386 // add old revision to the attic if missing 387 media_saveOldRevision($id); 388 } 389 390 // prepare directory 391 io_createNamespace($id, 'media'); 392 393 if($move($fn_tmp, $fn)) { 394 @clearstatcache(true,$fn); 395 $new = @filemtime($fn); 396 // Set the correct permission here. 397 // Always chmod media because they may be saved with different permissions than expected from the php umask. 398 // (Should normally chmod to $conf['fperm'] only if $conf['fperm'] is set.) 399 chmod($fn, $conf['fmode']); 400 msg($lang['uploadsucc'],1); 401 media_notify($id,$fn,$imime,$old); 402 // add a log entry to the media changelog 403 if ($REV){ 404 addMediaLogEntry($new, $id, DOKU_CHANGE_TYPE_REVERT, $lang['restored'], $REV); 405 } elseif ($overwrite) { 406 addMediaLogEntry($new, $id, DOKU_CHANGE_TYPE_EDIT); 407 } else { 408 addMediaLogEntry($new, $id, DOKU_CHANGE_TYPE_CREATE, $lang['created']); 409 } 410 return $id; 411 }else{ 412 return array($lang['uploadfail'],-1); 413 } 414} 415 416/** 417 * Moves the current version of media file to the media_attic 418 * directory 419 * 420 * @author Kate Arzamastseva <pshns@ukr.net> 421 * @param string $id 422 * @return int - revision date 423 */ 424function media_saveOldRevision($id){ 425 global $conf; 426 $oldf = mediaFN($id); 427 if(!@file_exists($oldf)) return ''; 428 $date = filemtime($oldf); 429 $newf = mediaFN($id,$date); 430 io_makeFileDir($newf); 431 if(copy($oldf, $newf)) { 432 // Set the correct permission here. 433 // Always chmod media because they may be saved with different permissions than expected from the php umask. 434 // (Should normally chmod to $conf['fperm'] only if $conf['fperm'] is set.) 435 chmod($newf, $conf['fmode']); 436 } 437 return $date; 438} 439 440/** 441 * This function checks if the uploaded content is really what the 442 * mimetype says it is. We also do spam checking for text types here. 443 * 444 * We need to do this stuff because we can not rely on the browser 445 * to do this check correctly. Yes, IE is broken as usual. 446 * 447 * @author Andreas Gohr <andi@splitbrain.org> 448 * @link http://www.splitbrain.org/blog/2007-02/12-internet_explorer_facilitates_cross_site_scripting 449 * @fixme check all 26 magic IE filetypes here? 450 */ 451function media_contentcheck($file,$mime){ 452 global $conf; 453 if($conf['iexssprotect']){ 454 $fh = @fopen($file, 'rb'); 455 if($fh){ 456 $bytes = fread($fh, 256); 457 fclose($fh); 458 if(preg_match('/<(script|a|img|html|body|iframe)[\s>]/i',$bytes)){ 459 return -3; 460 } 461 } 462 } 463 if(substr($mime,0,6) == 'image/'){ 464 $info = @getimagesize($file); 465 if($mime == 'image/gif' && $info[2] != 1){ 466 return -1; 467 }elseif($mime == 'image/jpeg' && $info[2] != 2){ 468 return -1; 469 }elseif($mime == 'image/png' && $info[2] != 3){ 470 return -1; 471 } 472 # fixme maybe check other images types as well 473 }elseif(substr($mime,0,5) == 'text/'){ 474 global $TEXT; 475 $TEXT = io_readFile($file); 476 if(checkwordblock()){ 477 return -2; 478 } 479 } 480 return 0; 481} 482 483/** 484 * Send a notify mail on uploads 485 * 486 * @author Andreas Gohr <andi@splitbrain.org> 487 */ 488function media_notify($id,$file,$mime,$old_rev=false){ 489 global $lang; 490 global $conf; 491 global $INFO; 492 if(empty($conf['notify'])) return; //notify enabled? 493 494 $ip = clientIP(); 495 496 $text = rawLocale('uploadmail'); 497 $text = str_replace('@DATE@',dformat(),$text); 498 $text = str_replace('@BROWSER@',$_SERVER['HTTP_USER_AGENT'],$text); 499 $text = str_replace('@IPADDRESS@',$ip,$text); 500 $text = str_replace('@HOSTNAME@',gethostsbyaddrs($ip),$text); 501 $text = str_replace('@DOKUWIKIURL@',DOKU_URL,$text); 502 $text = str_replace('@USER@',$_SERVER['REMOTE_USER'],$text); 503 $text = str_replace('@MIME@',$mime,$text); 504 $text = str_replace('@MEDIA@',ml($id,'',true,'&',true),$text); 505 $text = str_replace('@SIZE@',filesize_h(filesize($file)),$text); 506 if ($old_rev) { 507 $text = str_replace('@OLD@', ml($id, "rev=$old_rev", true, '&', true), $text); 508 } else { 509 $text = str_replace('@OLD@', '', $text); 510 } 511 512 if(empty($conf['mailprefix'])) { 513 $subject = '['.$conf['title'].'] '.$lang['mail_upload'].' '.$id; 514 } else { 515 $subject = '['.$conf['mailprefix'].'] '.$lang['mail_upload'].' '.$id; 516 } 517 518 mail_send($conf['notify'],$subject,$text,$conf['mailfrom']); 519} 520 521/** 522 * List all files in a given Media namespace 523 */ 524function media_filelist($ns,$auth=null,$jump='',$fullscreenview=false){ 525 global $conf; 526 global $lang; 527 $ns = cleanID($ns); 528 529 // check auth our self if not given (needed for ajax calls) 530 if(is_null($auth)) $auth = auth_quickaclcheck("$ns:*"); 531 532 if (!$fullscreenview) echo '<h1 id="media__ns">:'.hsc($ns).'</h1>'.NL; 533 534 if($auth < AUTH_READ){ 535 // FIXME: print permission warning here instead? 536 echo '<div class="nothing">'.$lang['nothingfound'].'</div>'.NL; 537 }else{ 538 if (!$fullscreenview) media_uploadform($ns, $auth); 539 540 $dir = utf8_encodeFN(str_replace(':','/',$ns)); 541 $data = array(); 542 search($data,$conf['mediadir'],'search_media', 543 array('showmsg'=>true,'depth'=>1),$dir); 544 545 if(!count($data)){ 546 echo '<div class="nothing">'.$lang['nothingfound'].'</div>'.NL; 547 }else foreach($data as $item){ 548 if (!$fullscreenview) media_printfile($item,$auth,$jump); 549 else media_printfile_thumbs($item,$auth,$jump); 550 } 551 } 552 if (!$fullscreenview) media_searchform($ns); 553} 554 555/** 556 * Prints mediamanager tab 557 * 558 * @author Kate Arzamastseva <pshns@ukr.net> 559 * @param string $link 560 * @param string $class 561 * @param string $name 562 * @param string $selected 563 */ 564function media_tab($link, $class, $name, $selected=false) { 565 if (!empty($selected) && $selected == $class) $class .= ' selected'; 566 $tab = '<a href="'.$link.'" class="'.$class.'" >'.$name.'</a>'; 567 echo $tab; 568} 569 570/** 571 * Prints tabs for files list actions 572 * 573 * @author Kate Arzamastseva <pshns@ukr.net> 574 * @param string $selected - opened tab 575 */ 576function media_tabs_files($selected=false){ 577 global $lang; 578 579 echo '<div class="mediamanager-tabs" id="mediamanager__tabs_files">'; 580 581 media_tab(media_managerURL(array('tab_files' => 'files')), 'files', $lang['mediaselect'], $selected); 582 media_tab(media_managerURL(array('tab_files' => 'upload')), 'upload', $lang['media_uploadtab'], $selected); 583 media_tab(media_managerURL(array('tab_files' => 'search')), 'search', $lang['media_searchtab'], $selected); 584 585 echo '<div class="clearer"></div>'; 586 echo '</div>'; 587} 588 589/** 590 * Prints tabs for files details actions 591 * 592 * @author Kate Arzamastseva <pshns@ukr.net> 593 * @param string $selected - opened tab 594 */ 595function media_tabs_details($image, $selected=false){ 596 global $lang; 597 598 echo '<div class="mediamanager-tabs" id="mediamanager__tabs_details">'; 599 600 media_tab(media_managerURL(array('tab_details' => 'view')), 'view', $lang['media_viewtab'], $selected); 601 602 list($ext, $mime) = mimetype($image); 603 if ($mime == 'image/jpeg') { 604 media_tab(media_managerURL(array('tab_details' => 'edit')), 'edit', $lang['media_edittab'], $selected); 605 } 606 media_tab(media_managerURL(array('tab_details' => 'history')), 'history', $lang['media_historytab'], $selected); 607 608 echo '<div class="clearer"></div>'; 609 echo '</div>'; 610} 611 612/** 613 * Prints options for the tab that displays a list of all files 614 * 615 * @author Kate Arzamastseva <pshns@ukr.net> 616 */ 617function media_tab_files_options($ns){ 618 global $lang; 619 620 echo '<div class="background-container">'; 621 echo $ns; 622 623 echo '<div id="mediamanager__tabs_list">'; 624 625 echo '<a href="'.media_managerURL(array('view' => 'thumbs')).'" id="mediamanager__link_thumbs" >'; 626 echo $lang['media_thumbsview']; 627 echo '</a>'; 628 629 echo '<a href="'.media_managerURL(array('view' => 'list')).'" id="mediamanager__link_list" >'; 630 echo $lang['media_listview']; 631 echo '</a>'; 632 633 echo '</div>'; 634 635 echo '<div id="mediamanager__sort">'; 636 echo $lang['media_sort']; 637 echo '</div>'; 638 639 echo '<div class="clearer"></div>'; 640 echo '</div>'; 641} 642 643/** 644 * Prints tab that displays a list of all files 645 * 646 * @author Kate Arzamastseva <pshns@ukr.net> 647 */ 648function media_tab_files($ns,$auth=null,$jump='') { 649 global $lang; 650 if(is_null($auth)) $auth = auth_quickaclcheck("$ns:*"); 651 652 media_tab_files_options($ns); 653 654 echo '<div class="scroll-container" >'; 655 $view = $_REQUEST['view']; 656 if($auth < AUTH_READ){ 657 echo '<div class="nothing">'.$lang['media_perm_read'].'</div>'.NL; 658 }else{ 659 if ($view == 'list') { 660 echo '<ul class="mediamanager-list" id="mediamanager__file_list">'; 661 } else { 662 echo '<ul class="mediamanager-thumbs" id="mediamanager__file_list">'; 663 } 664 media_filelist($ns,$auth,$jump,true); 665 echo '</ul>'; 666 } 667 echo '</div>'; 668} 669 670/** 671 * Prints tab that displays uploading form 672 * 673 * @author Kate Arzamastseva <pshns@ukr.net> 674 */ 675function media_tab_upload($ns,$auth=null,$jump='') { 676 global $lang; 677 if(is_null($auth)) $auth = auth_quickaclcheck("$ns:*"); 678 679 echo '<div class="background-container">'; 680 echo sprintf($lang['media_upload'], $ns); 681 echo '</div>'; 682 683 echo '<div class="scroll-container">'; 684 if ($auth >= AUTH_UPLOAD) echo '<div class="upload">' . $lang['mediaupload'] . '</div>'; 685 media_uploadform($ns, $auth, true); 686 echo '</div>'; 687} 688 689/** 690 * Prints tab that displays search form 691 * 692 * @author Kate Arzamastseva <pshns@ukr.net> 693 */ 694function media_tab_search($ns,$auth=null) { 695 global $lang; 696 697 $do = $_REQUEST['mediado']; 698 $query = $_REQUEST['q']; 699 if (!$query) $query = ''; 700 701 echo '<div class="background-container">'; 702 echo sprintf($lang['media_search'], $ns); 703 echo'</div>'; 704 705 echo '<div class="scroll-container">'; 706 media_searchform($ns, $query, true); 707 708 if($do == 'searchlist'){ 709 $view = $_REQUEST['view']; 710 if ($view == 'list') { 711 echo '<ul class="mediamanager-list" id="mediamanager__file_list">'; 712 } else { 713 echo '<ul class="mediamanager-thumbs" id="mediamanager__file_list">'; 714 } 715 media_searchlist($query,$ns,$auth,true); 716 echo '</ul>'; 717 } 718 echo '</div>'; 719} 720 721/** 722 * Prints tab that displays mediafile details 723 * 724 * @author Kate Arzamastseva <pshns@ukr.net> 725 */ 726function media_tab_view($image, $ns, $auth=null, $rev=false) { 727 global $lang, $conf; 728 if(is_null($auth)) $auth = auth_quickaclcheck("$ns:*"); 729 730 echo '<div class="background-container">'; 731 list($ext,$mime,$dl) = mimetype($image,false); 732 $class = preg_replace('/[^_\-a-z0-9]+/i','_',$ext); 733 $class = 'select mediafile mf_'.$class; 734 echo '<a class="'.$class.'" >'.$image.'</a>'; 735 echo '</div>'; 736 737 echo '<div class="scroll-container">'; 738 if ($image && $auth >= AUTH_READ) { 739 $meta = new JpegMeta(mediaFN($image, $rev)); 740 media_preview($image, $auth, $rev, $meta); 741 media_preview_buttons($image, $auth, $rev); 742 media_details($image, $auth, $rev, $meta); 743 744 } else { 745 echo '<div class="nothing">'.$lang['media_perm_read'].'</div>'; 746 } 747 echo '</div>'; 748} 749 750/** 751 * Prints tab that displays form for editing mediafile metadata 752 * 753 * @author Kate Arzamastseva <pshns@ukr.net> 754 */ 755function media_tab_edit($image, $ns, $auth=null) { 756 global $lang; 757 if(is_null($auth)) $auth = auth_quickaclcheck("$ns:*"); 758 759 echo '<div class="background-container">'; 760 echo $lang['media_edit']; 761 echo '</div>'; 762 763 echo '<div class="scroll-container">'; 764 if ($image) { 765 list($ext, $mime) = mimetype($image); 766 if ($mime == 'image/jpeg') media_metaform($image,$auth,true); 767 } 768 echo '</div>'; 769} 770 771/** 772 * Prints tab that displays mediafile revisions 773 * 774 * @author Kate Arzamastseva <pshns@ukr.net> 775 */ 776function media_tab_history($image, $ns, $auth=null) { 777 global $lang; 778 if(is_null($auth)) $auth = auth_quickaclcheck("$ns:*"); 779 $do = $_REQUEST['mediado']; 780 781 echo '<div class="background-container">'; 782 echo $lang['media_history']; 783 echo '</div>'; 784 785 echo '<div class="scroll-container">'; 786 if ($auth >= AUTH_READ && $image) { 787 if ($do == 'diff'){ 788 media_diff($image, $ns, $auth); 789 } else { 790 $first = isset($_REQUEST['first']) ? intval($_REQUEST['first']) : 0; 791 html_revisions($first, $image); 792 } 793 } else { 794 echo '<div class="nothing">'.$lang['media_perm_read'].'</div>'.NL; 795 } 796 echo '</div>'; 797} 798 799/** 800 * Prints mediafile details 801 * 802 * @author Kate Arzamastseva <pshns@ukr.net> 803 */ 804function media_preview($image, $auth, $rev=false, $meta=false) { 805 global $lang; 806 807 echo '<div id="mediamanager__preview">'; 808 809 $size = media_image_preview_size($image, $rev, $meta); 810 811 if ($size) { 812 $more = ''; 813 if ($rev) { 814 $more = "rev=$rev"; 815 } else { 816 $t = @filemtime(mediaFN($image)); 817 $more = "t=$t"; 818 } 819 820 $more .= '&w='.$size[0].'&h='.$size[1]; 821 822 $src = ml($image, $more); 823 echo '<img src="'.$src.'" alt="'.$image.'" style="max-width: '.$size[0].'px;" />'; 824 } 825 826 echo '</div>'; 827} 828 829/** 830 * Prints mediafile action buttons 831 * 832 * @author Kate Arzamastseva <pshns@ukr.net> 833 */ 834function media_preview_buttons($image, $auth, $rev=false) { 835 global $lang; 836 837 echo '<div id="mediamanager__preview_buttons">'; 838 839 $more = ''; 840 if ($rev) { 841 $more = "rev=$rev"; 842 } else { 843 $t = @filemtime(mediaFN($image)); 844 $more = "t=$t"; 845 } 846 $link = ml($image,$more,true,'&'); 847 848 // view original file button 849 $form = new Doku_Form(array('action'=>$link, 'target'=>'_blank')); 850 $form->addElement(form_makeButton('submit','',$lang['mediaview'])); 851 $form->printForm(); 852 853 if($auth >= AUTH_DELETE && !$rev){ 854 855 // delete button 856 $form = new Doku_Form(array('id' => 'mediamanager__btn_delete', 857 'action'=>media_managerURL(array('delete' => $image), '&'))); 858 $form->addElement(form_makeButton('submit','',$lang['btn_delete'])); 859 $form->printForm(); 860 861 // upload new version button 862 $form = new Doku_Form(array('id' => 'mediamanager__btn_update', 863 'action'=>media_managerURL(array('image' => $image, 'mediado' => 'update'), '&'))); 864 $form->addElement(form_makeButton('submit','',$lang['media_update'])); 865 $form->printForm(); 866 } 867 868 if($auth >= AUTH_DELETE && $rev){ 869 870 // restore button 871 $form = new Doku_Form(array('id' => 'mediamanager__btn_restore', 872 'action'=>media_managerURL(array('image' => $image), '&'))); 873 $form->addHidden('mediado','restore'); 874 $form->addHidden('rev',$rev); 875 $form->addElement(form_makeButton('submit','',$lang['media_restore'])); 876 $form->printForm(); 877 } 878 879 echo '</div>'; 880} 881 882/** 883 * Returns image width and height for mediamanager preview panel 884 * 885 * @author Kate Arzamastseva <pshns@ukr.net> 886 * @param string $image 887 * @param int $rev 888 * @param JpegMeta $meta 889 * @return array 890 */ 891function media_image_preview_size($image, $rev, $meta) { 892 if (!preg_match("/\.(jpe?g|gif|png)$/", $image)) return false; 893 894 $info = getimagesize(mediaFN($image, $rev)); 895 $w = (int) $info[0]; 896 $h = (int) $info[1]; 897 898 $size = 500; 899 if($meta && ($w > $size || $h > $size)){ 900 $ratio = $meta->getResizeRatio($size, $size); 901 $w = floor($w * $ratio); 902 $h = floor($h * $ratio); 903 } 904 return array($w, $h); 905} 906 907/** 908 * Returns the requested EXIF/IPTC tag from the image meta 909 * 910 * @author Kate Arzamastseva <pshns@ukr.net> 911 * @param array $tags 912 * @param JpegMeta $meta 913 * @param string $alt 914 * @return string 915 */ 916function media_getTag($tags,$meta,$alt=''){ 917 if($meta === false) return $alt; 918 $info = $meta->getField($tags); 919 if($info == false) return $alt; 920 return $info; 921} 922 923/** 924 * Returns mediafile tags 925 * 926 * @author Kate Arzamastseva <pshns@ukr.net> 927 * @param JpegMeta $meta 928 * @return array 929 */ 930function media_file_tags($meta) { 931 global $config_cascade; 932 933 // load the field descriptions 934 static $fields = null; 935 if(is_null($fields)){ 936 $config_files = getConfigFiles('mediameta'); 937 foreach ($config_files as $config_file) { 938 if(@file_exists($config_file)) include($config_file); 939 } 940 } 941 942 $tags = array(); 943 944 foreach($fields as $key => $tag){ 945 $t = array(); 946 if (!empty($tag[0])) $t = array($tag[0]); 947 if(is_array($tag[3])) $t = array_merge($t,$tag[3]); 948 $value = media_getTag($t, $meta); 949 $tags[] = array('tag' => $tag, 'value' => $value); 950 } 951 952 return $tags; 953} 954 955/** 956 * Prints mediafile tags 957 * 958 * @author Kate Arzamastseva <pshns@ukr.net> 959 */ 960function media_details($image, $auth, $rev=false, $meta=false) { 961 global $lang; 962 963 if (!$meta) $meta = new JpegMeta(mediaFN($image, $rev)); 964 $tags = media_file_tags($meta); 965 966 echo '<dl class="img_tags">'; 967 foreach($tags as $tag){ 968 if ($tag['value']) { 969 $value = cleanText($tag['value']); 970 echo '<dt>'.$lang[$tag['tag'][1]].':</dt><dd>'; 971 if ($tag['tag'][2] == 'date') echo dformat($value); 972 else echo hsc($value); 973 echo '</dd>'; 974 } 975 } 976 echo '</dl>'; 977} 978 979/** 980 * Shows difference between two revisions of file 981 * 982 * @author Kate Arzamastseva <pshns@ukr.net> 983 */ 984function media_diff($image, $ns, $auth) { 985 global $lang; 986 global $conf; 987 988 $rev1 = (int) $_REQUEST['rev']; 989 990 if(is_array($_REQUEST['rev2'])){ 991 $rev1 = (int) $_REQUEST['rev2'][0]; 992 $rev2 = (int) $_REQUEST['rev2'][1]; 993 994 if(!$rev1){ 995 $rev1 = $rev2; 996 unset($rev2); 997 } 998 }else{ 999 $rev2 = (int) $_REQUEST['rev2']; 1000 } 1001 if($rev1 && $rev2){ // two specific revisions wanted 1002 // make sure order is correct (older on the left) 1003 if($rev1 < $rev2){ 1004 $l_rev = $rev1; 1005 $r_rev = $rev2; 1006 }else{ 1007 $l_rev = $rev2; 1008 $r_rev = $rev1; 1009 } 1010 }elseif($rev1){ // single revision given, compare to current 1011 $r_rev = ''; 1012 $l_rev = $rev1; 1013 }else{ // no revision was given, compare previous to current 1014 $r_rev = ''; 1015 $revs = getRevisions($image, 0, 1, 8192, true); 1016 $l_rev = $revs[0]; 1017 } 1018 1019 // prepare event data 1020 $data[0] = $image; 1021 $data[1] = $l_rev; 1022 $data[2] = $r_rev; 1023 $data[3] = $ns; 1024 $data[4] = $auth; 1025 1026 // trigger event 1027 return trigger_event('MEDIA_DIFF', $data, '_media_file_diff', true); 1028 1029} 1030 1031function _media_file_diff($data) { 1032 if(is_array($data) && count($data)===5) { 1033 return media_file_diff($data[0], $data[1], $data[2], $data[3], $data[4]); 1034 } else { 1035 return false; 1036 } 1037} 1038 1039/** 1040 * Shows difference between two revisions of image 1041 * 1042 * @author Kate Arzamastseva <pshns@ukr.net> 1043 */ 1044function media_file_diff($image, $l_rev, $r_rev, $ns, $auth){ 1045 global $lang, $config_cascade; 1046 1047 echo '<ul id="mediamanager__diff_table">'; 1048 1049 echo '<li>'; 1050 media_preview($image, $auth, $l_rev, $l_meta); 1051 echo '</li>'; 1052 1053 echo '<li>'; 1054 media_preview($image, $auth, $r_rev, $r_meta); 1055 echo '</li>'; 1056 1057 echo '<li>'; 1058 media_preview_buttons($image, $auth, $l_rev); 1059 echo '</li>'; 1060 1061 echo '<li>'; 1062 media_preview_buttons($image, $auth, $r_rev); 1063 echo '</li>'; 1064 1065 $l_meta = new JpegMeta(mediaFN($image, $l_rev)); 1066 $r_meta = new JpegMeta(mediaFN($image, $r_rev)); 1067 1068 $l_tags = media_file_tags($l_meta); 1069 $r_tags = media_file_tags($r_meta); 1070 foreach ($l_tags as $key => $l_tag) { 1071 if ($l_tag['value'] != $r_tags[$key]['value']) { 1072 $r_tags[$key]['class'] = 'highlighted'; 1073 $l_tags[$key]['class'] = 'highlighted'; 1074 } else if (!$l_tag['value'] || !$r_tags[$key]['value']) { 1075 unset($r_tags[$key]); 1076 unset($l_tags[$key]); 1077 } 1078 } 1079 1080 foreach(array($l_tags,$r_tags) as $tags){ 1081 echo '<li><div>'; 1082 1083 echo '<dl class="img_tags">'; 1084 foreach($tags as $tag){ 1085 $value = cleanText($tag['value']); 1086 if (!$value) $value = '-'; 1087 echo '<dt>'.$lang[$tag['tag'][1]].':</dt>'; 1088 echo '<dd class="'.$tag['class'].'" >'; 1089 if ($tag['tag'][2] == 'date') echo dformat($value); 1090 else echo hsc($value); 1091 echo '</dd>'; 1092 } 1093 echo '</dl>'; 1094 1095 echo '</div></li>'; 1096 } 1097 1098 echo '</ul>'; 1099 1100 media_image_diff($image, $l_rev, $r_rev, $l_meta, 'opacity'); 1101 media_image_diff($image, $l_rev, $r_rev, $l_meta, 'portions'); 1102} 1103 1104/** 1105 * Prints two images side by side 1106 * and slider 1107 * 1108 * @author Kate Arzamastseva <pshns@ukr.net> 1109 * @param string $image 1110 * @param int $l_rev 1111 * @param int $r_rev 1112 * @param JpegMeta $meta 1113 */ 1114function media_image_diff($image, $l_rev, $r_rev, $meta, $type) { 1115 $l_size = media_image_preview_size($image, $l_rev, $meta); 1116 $r_size = media_image_preview_size($image, $r_rev, $meta); 1117 1118 if (!$l_size || !$r_size || $l_size != $r_size || $l_size[0] < 30) return ''; 1119 1120 echo '<div class="mediamanager-preview">'; 1121 1122 $l_more = 'rev='.$l_rev.'&h='.$l_size[1].'&w='.$l_size[0]; 1123 $r_more = 'rev='.$r_rev.'&h='.$l_size[1].'&w='.$l_size[0]; 1124 1125 $l_src = ml($image, $l_more); 1126 $r_src = ml($image, $r_more); 1127 1128 echo '<div id="mediamanager__diff_'.$type.'_image1" style="background-image: url(\''.$l_src.'\'); max-width: '.$l_size[0].'px; height: '.$l_size[1].'px; " >'; 1129 echo '<div id="mediamanager__diff_'.$type.'_image2" style="background-image: url(\''.$r_src.'\'); max-width: '.$l_size[0].'px; height: '.$l_size[1].'px; " >'; 1130 echo '</div>'; 1131 echo '</div>'; 1132 1133 echo '<div id="mediamanager__'.$type.'_slider" style="max-width: '.($l_size[0]-20).'px;" ></div>'; 1134 echo '</div>'; 1135} 1136 1137/** 1138 * Restores an old revision of a media file 1139 * 1140 * @param string $image 1141 * @param int $rev 1142 * @param int $auth 1143 * @return string - file's id 1144 * @author Kate Arzamastseva <pshns@ukr.net> 1145 */ 1146function media_restore($image, $rev, $auth){ 1147 if ($auth < AUTH_DELETE) return false; 1148 if (!$image || !file_exists(mediaFN($image))) return false; 1149 if (!$rev || !file_exists(mediaFN($image, $rev))) return false; 1150 list($iext,$imime,$dl) = mimetype($image); 1151 $res = media_upload_finish(mediaFN($image, $rev), 1152 mediaFN($image), 1153 $image, 1154 $imime, 1155 true, 1156 'copy'); 1157 if (is_array($res)) { 1158 msg($res[0], $res[1]); 1159 return false; 1160 } 1161 return $res; 1162} 1163 1164/** 1165 * List all files found by the search request 1166 * 1167 * @author Tobias Sarnowski <sarnowski@cosmocode.de> 1168 * @author Andreas Gohr <gohr@cosmocode.de> 1169 * @author Kate Arzamastseva <pshns@ukr.net> 1170 * @triggers MEDIA_SEARCH 1171 */ 1172function media_searchlist($query,$ns,$auth=null,$fullscreen=false){ 1173 global $conf; 1174 global $lang; 1175 1176 $ns = cleanID($ns); 1177 1178 if ($query) { 1179 $evdata = array( 1180 'ns' => $ns, 1181 'data' => array(), 1182 'query' => $query 1183 ); 1184 $evt = new Doku_Event('MEDIA_SEARCH', $evdata); 1185 if ($evt->advise_before()) { 1186 $dir = utf8_encodeFN(str_replace(':','/',$evdata['ns'])); 1187 $pattern = '/'.preg_quote($evdata['query'],'/').'/i'; 1188 search($evdata['data'], 1189 $conf['mediadir'], 1190 'search_media', 1191 array('showmsg'=>false,'pattern'=>$pattern), 1192 $dir); 1193 } 1194 $evt->advise_after(); 1195 unset($evt); 1196 } 1197 1198 if (!$fullscreen) { 1199 echo '<h1 id="media__ns">'.sprintf($lang['searchmedia_in'],hsc($ns).':*').'</h1>'.NL; 1200 media_searchform($ns,$query); 1201 } 1202 1203 if(!count($evdata['data'])){ 1204 echo '<div class="nothing">'.$lang['nothingfound'].'</div>'.NL; 1205 }else foreach($evdata['data'] as $item){ 1206 if (!$fullscreen) media_printfile($item,$item['perm'],'',true); 1207 else media_printfile_thumbs($item,$item['perm']); 1208 } 1209} 1210 1211/** 1212 * Print action links for a file depending on filetype 1213 * and available permissions 1214 */ 1215function media_fileactions($item,$auth){ 1216 global $lang; 1217 1218 // view button 1219 $link = ml($item['id'],'',true); 1220 echo ' <a href="'.$link.'" target="_blank"><img src="'.DOKU_BASE.'lib/images/magnifier.png" '. 1221 'alt="'.$lang['mediaview'].'" title="'.$lang['mediaview'].'" class="btn" /></a>'; 1222 1223 // no further actions if not writable 1224 if(!$item['writable']) return; 1225 1226 // delete button 1227 if($auth >= AUTH_DELETE){ 1228 $link = DOKU_BASE.'lib/exe/mediamanager.php?delete='.rawurlencode($item['id']). 1229 '&sectok='.getSecurityToken(); 1230 echo ' <a href="'.$link.'" class="btn_media_delete" title="'.$item['id'].'">'. 1231 '<img src="'.DOKU_BASE.'lib/images/trash.png" alt="'.$lang['btn_delete'].'" '. 1232 'title="'.$lang['btn_delete'].'" class="btn" /></a>'; 1233 } 1234 1235 // edit button 1236 if($auth >= AUTH_UPLOAD && $item['isimg'] && $item['meta']->getField('File.Mime') == 'image/jpeg'){ 1237 $link = DOKU_BASE.'lib/exe/mediamanager.php?edit='.rawurlencode($item['id']); 1238 echo ' <a href="'.$link.'">'. 1239 '<img src="'.DOKU_BASE.'lib/images/pencil.png" alt="'.$lang['metaedit'].'" '. 1240 'title="'.$lang['metaedit'].'" class="btn" /></a>'; 1241 } 1242 1243} 1244 1245/** 1246 * Formats and prints one file in the list 1247 */ 1248function media_printfile($item,$auth,$jump,$display_namespace=false){ 1249 global $lang; 1250 global $conf; 1251 1252 // Prepare zebra coloring 1253 // I always wanted to use this variable name :-D 1254 static $twibble = 1; 1255 $twibble *= -1; 1256 $zebra = ($twibble == -1) ? 'odd' : 'even'; 1257 1258 // Automatically jump to recent action 1259 if($jump == $item['id']) { 1260 $jump = ' id="scroll__here" '; 1261 }else{ 1262 $jump = ''; 1263 } 1264 1265 // Prepare fileicons 1266 list($ext,$mime,$dl) = mimetype($item['file'],false); 1267 $class = preg_replace('/[^_\-a-z0-9]+/i','_',$ext); 1268 $class = 'select mediafile mf_'.$class; 1269 1270 // Prepare filename 1271 $file = utf8_decodeFN($item['file']); 1272 1273 // Prepare info 1274 $info = ''; 1275 if($item['isimg']){ 1276 $info .= (int) $item['meta']->getField('File.Width'); 1277 $info .= '×'; 1278 $info .= (int) $item['meta']->getField('File.Height'); 1279 $info .= ' '; 1280 } 1281 $info .= '<i>'.dformat($item['mtime']).'</i>'; 1282 $info .= ' '; 1283 $info .= filesize_h($item['size']); 1284 1285 // output 1286 echo '<div class="'.$zebra.'"'.$jump.'>'.NL; 1287 if (!$display_namespace) { 1288 echo '<a name="h_:'.$item['id'].'" class="'.$class.'">'.hsc($file).'</a> '; 1289 } else { 1290 echo '<a name="h_:'.$item['id'].'" class="'.$class.'">'.hsc($item['id']).'</a><br/>'; 1291 } 1292 echo '<span class="info">('.$info.')</span>'.NL; 1293 media_fileactions($item,$auth); 1294 echo '<div class="example" id="ex_'.str_replace(':','_',$item['id']).'">'; 1295 echo $lang['mediausage'].' <code>{{:'.$item['id'].'}}</code>'; 1296 echo '</div>'; 1297 if($item['isimg']) media_printimgdetail($item); 1298 echo '<div class="clearer"></div>'.NL; 1299 echo '</div>'.NL; 1300} 1301 1302function media_printicon($filename){ 1303 list($ext,$mime,$dl) = mimetype(mediaFN($filename),false); 1304 1305 if (@file_exists(DOKU_INC.'lib/images/fileicons/'.$ext.'.png')) { 1306 $icon = DOKU_BASE.'lib/images/fileicons/'.$ext.'.png'; 1307 } else { 1308 $icon = DOKU_BASE.'lib/images/fileicons/file.png'; 1309 } 1310 1311 echo '<img src="'.$icon.'" alt="'.$filename.'" class="icon" />'; 1312 1313} 1314 1315/** 1316 * Formats and prints one file in the list in the thumbnails view 1317 * 1318 * @author Kate Arzamastseva <pshns@ukr.net> 1319 */ 1320function media_printfile_thumbs($item,$auth,$jump=false){ 1321 global $lang; 1322 global $conf; 1323 1324 // Prepare filename 1325 $file = utf8_decodeFN($item['file']); 1326 1327 // output 1328 echo '<li><div>'; 1329 1330 if($item['isimg']) { 1331 media_printimgdetail($item, true); 1332 1333 } else { 1334 echo '<a name="d_:'.$item['id'].'" class="image" title="'.$item['id'].'" href="'. 1335 media_managerURL(array('image' => hsc($item['id']))).'"><div>'; 1336 media_printicon($item['id']); 1337 echo '</div></a>'; 1338 } 1339 //echo '<input type=checkbox />'; 1340 echo '<a href="'.media_managerURL(array('image' => hsc($item['id']))).'" name= 1341 "h_:'.$item['id'].'" class="name">'.hsc($file).'</a>'; 1342 if($item['isimg']){ 1343 $size = ''; 1344 $size .= (int) $item['meta']->getField('File.Width'); 1345 $size .= '×'; 1346 $size .= (int) $item['meta']->getField('File.Height'); 1347 echo '<span class="size">'.$size.'</span>'; 1348 } else { 1349 echo '<span class="size"> </span>'; 1350 } 1351 $date = dformat($item['mtime']); 1352 echo '<span class="date">'.$date.'</span>'; 1353 $filesize = filesize_h($item['size']); 1354 echo '<span class="filesize">'.$filesize.'</span>'; 1355 echo '<div class="clearer"></div>'; 1356 echo '</div></li>'.NL; 1357} 1358 1359/** 1360 * Prints a thumbnail and metainfos 1361 */ 1362function media_printimgdetail($item, $fullscreen=false){ 1363 // prepare thumbnail 1364 if (!$fullscreen) { 1365 $size_array[] = 120; 1366 } else { 1367 $size_array = array(90, 40); 1368 } 1369 foreach ($size_array as $index => $size) { 1370 $w = (int) $item['meta']->getField('File.Width'); 1371 $h = (int) $item['meta']->getField('File.Height'); 1372 if($w>$size || $h>$size){ 1373 if (!$fullscreen) { 1374 $ratio = $item['meta']->getResizeRatio($size); 1375 } else { 1376 $ratio = $item['meta']->getResizeRatio($size,$size); 1377 } 1378 $w = floor($w * $ratio); 1379 $h = floor($h * $ratio); 1380 } 1381 $src = ml($item['id'],array('w'=>$w,'h'=>$h,'t'=>$item['mtime'])); 1382 $p = array(); 1383 if (!$fullscreen) { 1384 $p['width'] = $w; 1385 $p['height'] = $h; 1386 } 1387 $p['alt'] = $item['id']; 1388 $p['class'] = 'thumb'; 1389 $att = buildAttributes($p); 1390 1391 // output 1392 if ($fullscreen) { 1393 echo '<a name="d_:'.$item['id'].'" class="image'.$index.'" title="'.$item['id'].'" href="'. 1394 media_managerURL(array('image' => hsc($item['id']))).'">'; 1395 echo '<div><img src="'.$src.'" '.$att.' /></div>'; 1396 echo '</a>'; 1397 } 1398 } 1399 1400 if ($fullscreen) return ''; 1401 1402 echo '<div class="detail">'; 1403 echo '<div class="thumb">'; 1404 echo '<a name="d_:'.$item['id'].'" class="select">'; 1405 echo '<img src="'.$src.'" '.$att.' />'; 1406 echo '</a>'; 1407 echo '</div>'; 1408 1409 // read EXIF/IPTC data 1410 $t = $item['meta']->getField(array('IPTC.Headline','xmp.dc:title')); 1411 $d = $item['meta']->getField(array('IPTC.Caption','EXIF.UserComment', 1412 'EXIF.TIFFImageDescription', 1413 'EXIF.TIFFUserComment')); 1414 if(utf8_strlen($d) > 250) $d = utf8_substr($d,0,250).'...'; 1415 $k = $item['meta']->getField(array('IPTC.Keywords','IPTC.Category','xmp.dc:subject')); 1416 1417 // print EXIF/IPTC data 1418 if($t || $d || $k ){ 1419 echo '<p>'; 1420 if($t) echo '<strong>'.htmlspecialchars($t).'</strong><br />'; 1421 if($d) echo htmlspecialchars($d).'<br />'; 1422 if($t) echo '<em>'.htmlspecialchars($k).'</em>'; 1423 echo '</p>'; 1424 } 1425 echo '</div>'; 1426} 1427 1428/** 1429 * Build link based on the current, adding/rewriting 1430 * parameters 1431 * 1432 * @author Kate Arzamastseva <pshns@ukr.net> 1433 * @param array $params 1434 * @param string $amp - separator 1435 * @return string - link 1436 */ 1437function media_managerURL($params=false, $amp='&') { 1438 global $conf; 1439 global $ID; 1440 1441 $gets = array('do' => 'media'); 1442 $media_manager_params = array('tab_files', 'tab_details', 'image', 'ns', 'view'); 1443 foreach ($media_manager_params as $x) { 1444 if (isset($_REQUEST[$x])) $gets[$x] = $_REQUEST[$x]; 1445 } 1446 1447 if ($params) { 1448 foreach ($params as $k => $v) { 1449 $gets[$k] = $v; 1450 } 1451 } 1452 unset($gets['id']); 1453 if ($gets['delete']) { 1454 unset($gets['image']); 1455 unset($gets['tab_details']); 1456 } 1457 1458 return wl($ID,$gets,false,$amp); 1459} 1460 1461/** 1462 * Print the media upload form if permissions are correct 1463 * 1464 * @author Andreas Gohr <andi@splitbrain.org> 1465 * @author Kate Arzamastseva <pshns@ukr.net> 1466 */ 1467function media_uploadform($ns, $auth, $fullscreen = false){ 1468 global $lang; 1469 1470 if($auth < AUTH_UPLOAD) { 1471 echo '<div class="nothing">'.$lang['media_perm_upload'].'</div>'.NL; 1472 return; 1473 } 1474 1475 $update = false; 1476 $id = ''; 1477 if ($auth >= AUTH_DELETE && $fullscreen && $_REQUEST['mediado'] == 'update') { 1478 $update = true; 1479 $id = cleanID($_REQUEST['image']); 1480 } 1481 1482 // The default HTML upload form 1483 $params = array('id' => 'dw__upload', 1484 'enctype' => 'multipart/form-data'); 1485 if (!$fullscreen) { 1486 $params['action'] = DOKU_BASE.'lib/exe/mediamanager.php'; 1487 } else { 1488 $params['action'] = media_managerURL(array('tab_files' => 'files', 1489 'tab_details' => 'view'), '&'); 1490 } 1491 1492 $form = new Doku_Form($params); 1493 if (!$fullscreen) $form->addElement('<div class="upload">' . $lang['mediaupload'] . '</div>'); 1494 $form->addElement(formSecurityToken()); 1495 $form->addHidden('ns', hsc($ns)); 1496 $form->addElement(form_makeOpenTag('p')); 1497 $form->addElement(form_makeFileField('upload', $lang['txt_upload'].':', 'upload__file')); 1498 $form->addElement(form_makeCloseTag('p')); 1499 $form->addElement(form_makeOpenTag('p')); 1500 $form->addElement(form_makeTextField('mediaid', noNS($id), $lang['txt_filename'].':', 'upload__name')); 1501 $form->addElement(form_makeButton('submit', '', $lang['btn_upload'])); 1502 $form->addElement(form_makeCloseTag('p')); 1503 1504 if($auth >= AUTH_DELETE){ 1505 $form->addElement(form_makeOpenTag('p')); 1506 $attrs = array(); 1507 if ($update) $attrs['checked'] = 'checked'; 1508 $form->addElement(form_makeCheckboxField('ow', 1, $lang['txt_overwrt'], 'dw__ow', 'check', $attrs)); 1509 $form->addElement(form_makeCloseTag('p')); 1510 } 1511 html_form('upload', $form); 1512 1513 // prepare flashvars for multiupload 1514 $opt = array( 1515 'L_gridname' => $lang['mu_gridname'] , 1516 'L_gridsize' => $lang['mu_gridsize'] , 1517 'L_gridstat' => $lang['mu_gridstat'] , 1518 'L_namespace' => $lang['mu_namespace'] , 1519 'L_overwrite' => $lang['txt_overwrt'], 1520 'L_browse' => $lang['mu_browse'], 1521 'L_upload' => $lang['btn_upload'], 1522 'L_toobig' => $lang['mu_toobig'], 1523 'L_ready' => $lang['mu_ready'], 1524 'L_done' => $lang['mu_done'], 1525 'L_fail' => $lang['mu_fail'], 1526 'L_authfail' => $lang['mu_authfail'], 1527 'L_progress' => $lang['mu_progress'], 1528 'L_filetypes' => $lang['mu_filetypes'], 1529 'L_info' => $lang['mu_info'], 1530 'L_lasterr' => $lang['mu_lasterr'], 1531 1532 'O_ns' => ":$ns", 1533 'O_backend' => 'mediamanager.php?'.session_name().'='.session_id(), 1534 'O_maxsize' => php_to_byte(ini_get('upload_max_filesize')), 1535 'O_extensions'=> join('|',array_keys(getMimeTypes())), 1536 'O_overwrite' => ($auth >= AUTH_DELETE), 1537 'O_sectok' => getSecurityToken(), 1538 'O_authtok' => auth_createToken(), 1539 ); 1540 $var = buildURLparams($opt); 1541 // output the flash uploader 1542 ?> 1543 <div id="dw__flashupload" style="display:none"> 1544 <div class="upload"><?php echo $lang['mu_intro']?></div> 1545 <?php echo html_flashobject('multipleUpload.swf','500','190',null,$opt); ?> 1546 </div> 1547 <?php 1548} 1549 1550/** 1551 * Print the search field form 1552 * 1553 * @author Tobias Sarnowski <sarnowski@cosmocode.de> 1554 * @author Kate Arzamastseva <pshns@ukr.net> 1555 */ 1556function media_searchform($ns,$query='',$fullscreen=false){ 1557 global $lang; 1558 1559 // The default HTML search form 1560 $params = array('id' => 'dw__mediasearch'); 1561 if (!$fullscreen) $params['action'] = DOKU_BASE.'lib/exe/mediamanager.php'; 1562 else $params['action'] = media_managerURL(array(), '&'); 1563 $form = new Doku_Form($params); 1564 if (!$fullscreen) $form->addElement('<div class="upload">' . $lang['mediasearch'] . '</div>'); 1565 $form->addElement(formSecurityToken()); 1566 $form->addHidden('ns', $ns); 1567 if (!$fullscreen) $form->addHidden('do', 'searchlist'); 1568 else $form->addHidden('mediado', 'searchlist'); 1569 $form->addElement(form_makeOpenTag('p')); 1570 $form->addElement(form_makeTextField('q', $query,$lang['searchmedia'],'','',array('title'=>sprintf($lang['searchmedia_in'],hsc($ns).':*')))); 1571 $form->addElement(form_makeButton('submit', '', $lang['btn_search'])); 1572 $form->addElement(form_makeCloseTag('p')); 1573 html_form('searchmedia', $form); 1574} 1575 1576/** 1577 * Build a tree outline of available media namespaces 1578 * 1579 * @author Andreas Gohr <andi@splitbrain.org> 1580 */ 1581function media_nstree($ns){ 1582 global $conf; 1583 global $lang; 1584 1585 // currently selected namespace 1586 $ns = cleanID($ns); 1587 if(empty($ns)){ 1588 global $ID; 1589 $ns = dirname(str_replace(':','/',$ID)); 1590 if($ns == '.') $ns =''; 1591 } 1592 $ns = utf8_encodeFN(str_replace(':','/',$ns)); 1593 1594 $data = array(); 1595 search($data,$conf['mediadir'],'search_index',array('ns' => $ns, 'nofiles' => true)); 1596 1597 // wrap a list with the root level around the other namespaces 1598 array_unshift($data, array('level' => 0, 'id' => '', 'open' =>'true', 1599 'label' => '['.$lang['mediaroot'].']')); 1600 1601 echo html_buildlist($data,'idx','media_nstree_item','media_nstree_li'); 1602} 1603 1604/** 1605 * Userfunction for html_buildlist 1606 * 1607 * Prints a media namespace tree item 1608 * 1609 * @author Andreas Gohr <andi@splitbrain.org> 1610 */ 1611function media_nstree_item($item){ 1612 $pos = strrpos($item['id'], ':'); 1613 $label = substr($item['id'], $pos > 0 ? $pos + 1 : 0); 1614 if(!$item['label']) $item['label'] = $label; 1615 1616 $ret = ''; 1617 if (!($_REQUEST['do'] == 'media')) 1618 $ret .= '<a href="'.DOKU_BASE.'lib/exe/mediamanager.php?ns='.idfilter($item['id']).'" class="idx_dir">'; 1619 else $ret .= '<a href="'.media_managerURL(array('ns' => idfilter($item['id']), 'tab_files' => 'files')) 1620 .'" class="idx_dir">'; 1621 $ret .= $item['label']; 1622 $ret .= '</a>'; 1623 return $ret; 1624} 1625 1626/** 1627 * Userfunction for html_buildlist 1628 * 1629 * Prints a media namespace tree item opener 1630 * 1631 * @author Andreas Gohr <andi@splitbrain.org> 1632 */ 1633function media_nstree_li($item){ 1634 $class='media level'.$item['level']; 1635 if($item['open']){ 1636 $class .= ' open'; 1637 $img = DOKU_BASE.'lib/images/minus.gif'; 1638 $alt = '−'; 1639 }else{ 1640 $class .= ' closed'; 1641 $img = DOKU_BASE.'lib/images/plus.gif'; 1642 $alt = '+'; 1643 } 1644 // TODO: only deliver an image if it actually has a subtree... 1645 return '<li class="'.$class.'">'. 1646 '<img src="'.$img.'" alt="'.$alt.'" />'; 1647} 1648 1649/** 1650 * Resizes the given image to the given size 1651 * 1652 * @author Andreas Gohr <andi@splitbrain.org> 1653 */ 1654function media_resize_image($file, $ext, $w, $h=0){ 1655 global $conf; 1656 1657 $info = @getimagesize($file); //get original size 1658 if($info == false) return $file; // that's no image - it's a spaceship! 1659 1660 if(!$h) $h = round(($w * $info[1]) / $info[0]); 1661 1662 // we wont scale up to infinity 1663 if($w > 2000 || $h > 2000) return $file; 1664 1665 //cache 1666 $local = getCacheName($file,'.media.'.$w.'x'.$h.'.'.$ext); 1667 $mtime = @filemtime($local); // 0 if not exists 1668 1669 if( $mtime > filemtime($file) || 1670 media_resize_imageIM($ext,$file,$info[0],$info[1],$local,$w,$h) || 1671 media_resize_imageGD($ext,$file,$info[0],$info[1],$local,$w,$h) ){ 1672 if($conf['fperm']) chmod($local, $conf['fperm']); 1673 return $local; 1674 } 1675 //still here? resizing failed 1676 return $file; 1677} 1678 1679/** 1680 * Crops the given image to the wanted ratio, then calls media_resize_image to scale it 1681 * to the wanted size 1682 * 1683 * Crops are centered horizontally but prefer the upper third of an vertical 1684 * image because most pics are more interesting in that area (rule of thirds) 1685 * 1686 * @author Andreas Gohr <andi@splitbrain.org> 1687 */ 1688function media_crop_image($file, $ext, $w, $h=0){ 1689 global $conf; 1690 1691 if(!$h) $h = $w; 1692 $info = @getimagesize($file); //get original size 1693 if($info == false) return $file; // that's no image - it's a spaceship! 1694 1695 // calculate crop size 1696 $fr = $info[0]/$info[1]; 1697 $tr = $w/$h; 1698 if($tr >= 1){ 1699 if($tr > $fr){ 1700 $cw = $info[0]; 1701 $ch = (int) $info[0]/$tr; 1702 }else{ 1703 $cw = (int) $info[1]*$tr; 1704 $ch = $info[1]; 1705 } 1706 }else{ 1707 if($tr < $fr){ 1708 $cw = (int) $info[1]*$tr; 1709 $ch = $info[1]; 1710 }else{ 1711 $cw = $info[0]; 1712 $ch = (int) $info[0]/$tr; 1713 } 1714 } 1715 // calculate crop offset 1716 $cx = (int) ($info[0]-$cw)/2; 1717 $cy = (int) ($info[1]-$ch)/3; 1718 1719 //cache 1720 $local = getCacheName($file,'.media.'.$cw.'x'.$ch.'.crop.'.$ext); 1721 $mtime = @filemtime($local); // 0 if not exists 1722 1723 if( $mtime > filemtime($file) || 1724 media_crop_imageIM($ext,$file,$info[0],$info[1],$local,$cw,$ch,$cx,$cy) || 1725 media_resize_imageGD($ext,$file,$cw,$ch,$local,$cw,$ch,$cx,$cy) ){ 1726 if($conf['fperm']) chmod($local, $conf['fperm']); 1727 return media_resize_image($local,$ext, $w, $h); 1728 } 1729 1730 //still here? cropping failed 1731 return media_resize_image($file,$ext, $w, $h); 1732} 1733 1734/** 1735 * Download a remote file and return local filename 1736 * 1737 * returns false if download fails. Uses cached file if available and 1738 * wanted 1739 * 1740 * @author Andreas Gohr <andi@splitbrain.org> 1741 * @author Pavel Vitis <Pavel.Vitis@seznam.cz> 1742 */ 1743function media_get_from_URL($url,$ext,$cache){ 1744 global $conf; 1745 1746 // if no cache or fetchsize just redirect 1747 if ($cache==0) return false; 1748 if (!$conf['fetchsize']) return false; 1749 1750 $local = getCacheName(strtolower($url),".media.$ext"); 1751 $mtime = @filemtime($local); // 0 if not exists 1752 1753 //decide if download needed: 1754 if( ($mtime == 0) || // cache does not exist 1755 ($cache != -1 && $mtime < time()-$cache) // 'recache' and cache has expired 1756 ){ 1757 if(media_image_download($url,$local)){ 1758 return $local; 1759 }else{ 1760 return false; 1761 } 1762 } 1763 1764 //if cache exists use it else 1765 if($mtime) return $local; 1766 1767 //else return false 1768 return false; 1769} 1770 1771/** 1772 * Download image files 1773 * 1774 * @author Andreas Gohr <andi@splitbrain.org> 1775 */ 1776function media_image_download($url,$file){ 1777 global $conf; 1778 $http = new DokuHTTPClient(); 1779 $http->max_bodysize = $conf['fetchsize']; 1780 $http->timeout = 25; //max. 25 sec 1781 $http->header_regexp = '!\r\nContent-Type: image/(jpe?g|gif|png)!i'; 1782 1783 $data = $http->get($url); 1784 if(!$data) return false; 1785 1786 $fileexists = @file_exists($file); 1787 $fp = @fopen($file,"w"); 1788 if(!$fp) return false; 1789 fwrite($fp,$data); 1790 fclose($fp); 1791 if(!$fileexists and $conf['fperm']) chmod($file, $conf['fperm']); 1792 1793 // check if it is really an image 1794 $info = @getimagesize($file); 1795 if(!$info){ 1796 @unlink($file); 1797 return false; 1798 } 1799 1800 return true; 1801} 1802 1803/** 1804 * resize images using external ImageMagick convert program 1805 * 1806 * @author Pavel Vitis <Pavel.Vitis@seznam.cz> 1807 * @author Andreas Gohr <andi@splitbrain.org> 1808 */ 1809function media_resize_imageIM($ext,$from,$from_w,$from_h,$to,$to_w,$to_h){ 1810 global $conf; 1811 1812 // check if convert is configured 1813 if(!$conf['im_convert']) return false; 1814 1815 // prepare command 1816 $cmd = $conf['im_convert']; 1817 $cmd .= ' -resize '.$to_w.'x'.$to_h.'!'; 1818 if ($ext == 'jpg' || $ext == 'jpeg') { 1819 $cmd .= ' -quality '.$conf['jpg_quality']; 1820 } 1821 $cmd .= " $from $to"; 1822 1823 @exec($cmd,$out,$retval); 1824 if ($retval == 0) return true; 1825 return false; 1826} 1827 1828/** 1829 * crop images using external ImageMagick convert program 1830 * 1831 * @author Andreas Gohr <andi@splitbrain.org> 1832 */ 1833function media_crop_imageIM($ext,$from,$from_w,$from_h,$to,$to_w,$to_h,$ofs_x,$ofs_y){ 1834 global $conf; 1835 1836 // check if convert is configured 1837 if(!$conf['im_convert']) return false; 1838 1839 // prepare command 1840 $cmd = $conf['im_convert']; 1841 $cmd .= ' -crop '.$to_w.'x'.$to_h.'+'.$ofs_x.'+'.$ofs_y; 1842 if ($ext == 'jpg' || $ext == 'jpeg') { 1843 $cmd .= ' -quality '.$conf['jpg_quality']; 1844 } 1845 $cmd .= " $from $to"; 1846 1847 @exec($cmd,$out,$retval); 1848 if ($retval == 0) return true; 1849 return false; 1850} 1851 1852/** 1853 * resize or crop images using PHP's libGD support 1854 * 1855 * @author Andreas Gohr <andi@splitbrain.org> 1856 * @author Sebastian Wienecke <s_wienecke@web.de> 1857 */ 1858function media_resize_imageGD($ext,$from,$from_w,$from_h,$to,$to_w,$to_h,$ofs_x=0,$ofs_y=0){ 1859 global $conf; 1860 1861 if($conf['gdlib'] < 1) return false; //no GDlib available or wanted 1862 1863 // check available memory 1864 if(!is_mem_available(($from_w * $from_h * 4) + ($to_w * $to_h * 4))){ 1865 return false; 1866 } 1867 1868 // create an image of the given filetype 1869 if ($ext == 'jpg' || $ext == 'jpeg'){ 1870 if(!function_exists("imagecreatefromjpeg")) return false; 1871 $image = @imagecreatefromjpeg($from); 1872 }elseif($ext == 'png') { 1873 if(!function_exists("imagecreatefrompng")) return false; 1874 $image = @imagecreatefrompng($from); 1875 1876 }elseif($ext == 'gif') { 1877 if(!function_exists("imagecreatefromgif")) return false; 1878 $image = @imagecreatefromgif($from); 1879 } 1880 if(!$image) return false; 1881 1882 if(($conf['gdlib']>1) && function_exists("imagecreatetruecolor") && $ext != 'gif'){ 1883 $newimg = @imagecreatetruecolor ($to_w, $to_h); 1884 } 1885 if(!$newimg) $newimg = @imagecreate($to_w, $to_h); 1886 if(!$newimg){ 1887 imagedestroy($image); 1888 return false; 1889 } 1890 1891 //keep png alpha channel if possible 1892 if($ext == 'png' && $conf['gdlib']>1 && function_exists('imagesavealpha')){ 1893 imagealphablending($newimg, false); 1894 imagesavealpha($newimg,true); 1895 } 1896 1897 //keep gif transparent color if possible 1898 if($ext == 'gif' && function_exists('imagefill') && function_exists('imagecolorallocate')) { 1899 if(function_exists('imagecolorsforindex') && function_exists('imagecolortransparent')) { 1900 $transcolorindex = @imagecolortransparent($image); 1901 if($transcolorindex >= 0 ) { //transparent color exists 1902 $transcolor = @imagecolorsforindex($image, $transcolorindex); 1903 $transcolorindex = @imagecolorallocate($newimg, $transcolor['red'], $transcolor['green'], $transcolor['blue']); 1904 @imagefill($newimg, 0, 0, $transcolorindex); 1905 @imagecolortransparent($newimg, $transcolorindex); 1906 }else{ //filling with white 1907 $whitecolorindex = @imagecolorallocate($newimg, 255, 255, 255); 1908 @imagefill($newimg, 0, 0, $whitecolorindex); 1909 } 1910 }else{ //filling with white 1911 $whitecolorindex = @imagecolorallocate($newimg, 255, 255, 255); 1912 @imagefill($newimg, 0, 0, $whitecolorindex); 1913 } 1914 } 1915 1916 //try resampling first 1917 if(function_exists("imagecopyresampled")){ 1918 if(!@imagecopyresampled($newimg, $image, 0, 0, $ofs_x, $ofs_y, $to_w, $to_h, $from_w, $from_h)) { 1919 imagecopyresized($newimg, $image, 0, 0, $ofs_x, $ofs_y, $to_w, $to_h, $from_w, $from_h); 1920 } 1921 }else{ 1922 imagecopyresized($newimg, $image, 0, 0, $ofs_x, $ofs_y, $to_w, $to_h, $from_w, $from_h); 1923 } 1924 1925 $okay = false; 1926 if ($ext == 'jpg' || $ext == 'jpeg'){ 1927 if(!function_exists('imagejpeg')){ 1928 $okay = false; 1929 }else{ 1930 $okay = imagejpeg($newimg, $to, $conf['jpg_quality']); 1931 } 1932 }elseif($ext == 'png') { 1933 if(!function_exists('imagepng')){ 1934 $okay = false; 1935 }else{ 1936 $okay = imagepng($newimg, $to); 1937 } 1938 }elseif($ext == 'gif') { 1939 if(!function_exists('imagegif')){ 1940 $okay = false; 1941 }else{ 1942 $okay = imagegif($newimg, $to); 1943 } 1944 } 1945 1946 // destroy GD image ressources 1947 if($image) imagedestroy($image); 1948 if($newimg) imagedestroy($newimg); 1949 1950 return $okay; 1951} 1952 1953/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ 1954