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