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