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