1<?php 2/** 3 * This class is a backend to use the ownCloud database while running DokuWiki 4 * You can have a look to <ownCloud-Path>/lib/db.php for functions provided. 5 * Here is a description for developer to using the ownCloud database 6 * http://doc.owncloud.org/server/5.0/developer_manual/app/appframework/database.html 7 * 8 * @license GPL 3 (http://www.gnu.org/licenses/gpl.html) 9 * @author Martin Schulte <lebowski[at]corvus[dot]uberspace[dot]de>, 2013 10 */ 11// must be run within Dokuwiki 12if (!defined('DOKU_INC')) die(); 13 14//constants 15if (!defined('DOKU_LF')) define('DOKU_LF', "\n"); 16if (!defined('DOKU_TAB')) define('DOKU_TAB', "\t"); 17if (!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN', DOKU_INC.'lib/plugins/'); 18if(!defined('DOKU_CHANGE_TYPE_MOVE')) define('DOKU_CHANGE_TYPE_MOVE','M'); 19if(!defined('DOKU_CHANGE_TYPE_REPLACE')) define('DOKU_CHANGE_TYPE_REPLACE','R'); 20 21 22class helper_plugin_owncloud extends DokuWiki_Plugin 23{ 24 // The last query of type PDOStatementWrapper (see <ownCloud-Path>/lib/db.php) 25 protected $lastQuery; 26 protected $storageNr; 27 protected $lastfileid; 28 public $wiki = 'wiki'; 29 30 // id => filename 31 protected $fileIDCache = array(); 32 // filename => id 33 protected $filenameCache = array(); 34 35 /** 36 * Constructor to connect to db and check if ownCloud is installed 37 */ 38 public function helper_plugin_owncloud($db=true) { 39 if($db){ 40 global $conf; 41 include_once($this->getConf('pathtoowncloud').'/lib/base.php'); 42 // Check if ownCloud is installed or in maintenance (update) mode 43 if (!OC_Config::getValue('installed', false)) { 44 global $conf; 45 require_once('lang/'.$conf['lang'].'/settings.php'); 46 echo $lang['owncloudNotInstalled']; 47 exit(); 48 } 49 // This really should be replaced by public OC methods. Oh well. 50 $storageId = 'local::'.$conf['mediadir'].'/'; 51 if (strlen($storageId) > 64) { 52 $storageId = md5($storageId); 53 } 54 // Find Storage ID 55 $this->dbQuery('SELECT numeric_id FROM `*PREFIX*storages` WHERE `id` LIKE ?', array($storageId)); 56 $this->storageNr = $this->lastQuery->fetchOne(); 57 } 58 } 59 60 /** 61 * Prepares and executes a SQL query 62 * 63 * @param $sql String The SQL-Query (for syntax see http://doc.owncloud.org/server/5.0/developer_manual/app/appframework/database.html) 64 * @param $params array The parameters should be used in the sql-query 65 */ 66 public function dbQuery($sql, $params){ 67 $db = \OC_DB::prepare($sql); 68 $this->lastQuery = $db->execute($params); 69 70 } 71 72 73 // Returns the last query (last call of dbQuery) 74 public function getLastQuery(){ 75 return $this->lastQuery; 76 } 77 78 // Returns the last fileid 79 public function getLastfileid(){ 80 return $this->lastfileid; 81 } 82 83 /** 84 * Returns the path for the correspondig fileID (from table OC_filecache) 85 * 86 * @param $id integer The fileID 87 * @param $wikiID bool If true, slashes (/) will be replaced by colons (:) 88 */ 89 public function getFilenameForID($id, $wikiID=false){ 90 if(isset($this->fileidCache[$id])){// save db query 91 $path = $this->fileidCache[$id]; 92 }else{ 93 $this->dbQuery('SELECT `path` FROM `*PREFIX*filecache` WHERE fileid = ? AND storage = ?', array($id, $this->storageNr)); 94 if($this->lastQuery->numRows() == 0) return NULL; 95 $path = $this->lastQuery->fetchOne(); 96 } 97 $this->fileidCache[$id] = $path; 98 if($wikiID) return $this->pathToWikiID($path); 99 return $path; 100 } 101 102 /** replace / with / */ 103 public function pathToWikiID($path){ 104 return str_replace('/',':',$path); 105 } 106 107 /** replace : with / */ 108 public function wikiIDToPath($id){ 109 return str_replace(':','/',$id); 110 } 111 112 /** Returns true if the given path is a directory */ 113 public function isMediaDir($path){ 114 global $conf; 115 return is_dir($conf['mediadir'].'/'.trim($path,'/')); 116 } 117 118 119 /** 120 * Returns the fileid for the correspondig path (from table OC_filecache) 121 * 122 * @param $file string The path 123 * @return $id the fileID 124 */ 125 public function getIDForFilename($file){ 126 $file = trim($file,'/'); //Remove slashes at the beginning 127 // save db query 128 if(isset($this->filenameCache[$file])) return $this->filenameCache[$file]; 129 $this->dbQuery('SELECT `fileid` FROM `*PREFIX*filecache` WHERE path = ? AND storage = ?', array($file, $this->storageNr)); 130 $id = $this->lastQuery->fetchOne(); 131 $this->filenameCache[$file] = $id; 132 $this->lastfileid = $id; 133 return $id; 134 } 135 136 /** 137 * Returns the mimetype for the correspondig id (from table OC_filecache) 138 * 139 * @param $file string The path 140 */ 141 public function getMimetypeForID($id){ 142 $this->dbQuery('SELECT *PREFIX*mimetypes.mimetype FROM *PREFIX*filecache JOIN *PREFIX*mimetypes ON *PREFIX*filecache.mimetype = *PREFIX*mimetypes.id WHERE fileid = ? AND storage = ?', array($id, $this->storageNr)); 143 return $this->lastQuery->fetchOne(); 144 } 145 146 /** 147 * Returns the content of a folder specified by its id (from oc database) 148 * 149 * @param $id string the folderID 150 * @return @folderAndFiles folderID and filesID in the given dir 151 */ 152 public function getFolderContent($id){ 153 $this->dbQuery('SELECT `fileid`, `path`,*PREFIX*mimetypes.mimetype FROM *PREFIX*filecache JOIN *PREFIX*mimetypes ON *PREFIX*filecache.mimetype = *PREFIX*mimetypes.id WHERE parent=? AND storage = ? ORDER BY *PREFIX*filecache.path ASC', array($id, $this->storageNr)); 154 $rows = $this->lastQuery->numRows(); 155 $files = array(); 156 $folders = array(); 157 for($i = 1; $i <= $rows; $i++){ 158 $row = $this->lastQuery->fetchRow(); 159 if($row['mimetype'] == 'httpd/unix-directory'){ 160 array_push($folders, $row); 161 }else{ 162 array_push($files, $row); 163 } 164 } 165 return array($folders,$files); 166 } 167 168 /** 169 * Returns the media used on the page specified by $wikiid (from 170 * table OC_dokuwiki_media_used). It will be rendered as a orderd list 171 * 172 * @param $file string wikiid 173 * @return $string orderd list of media used on the page 174 */ 175 public function getMediaOfThisPage($wikiid){ 176 $this->dbQuery('SELECT `fileid`,`path` FROM `*PREFIX*dokuwiki_media_use` JOIN `*PREFIX*filecache` USING(`fileid`) WHERE `wikipage_hash` = ? ORDER BY `fileid` ASC', array(md5($wikiid))); 177 $rows = $this->lastQuery->numRows(); 178 if(empty($rows) || $rows == 0) return false; 179 $ret = '<p style="float:right;"><a href="#headingusedmedia" id="usemediadetail">'.$this->getLang('showfileinfo').'</a></p>'; 180 $ret .= DOKU_LF.'<ol id="usedmedia">'.DOKU_LF; 181 $ids = $this->lastQuery; 182 for($i = 1; $i <= $rows; $i++){ 183 $row = $ids->fetchRow(); 184 $ret .= DOKU_TAB.'<li class="mediaitem" fileid="'.$row['fileid'].'">'; 185 $ret .= $this->internalmedia($row['fileid'],"",(($row['path']!='')?$row['path']:'/'),NULL,16,NULL,NULL,'linkonly'); 186 $ret .= '</li>'.DOKU_LF; 187 } 188 $ret .= '</ol>'.DOKU_LF; 189 return $ret; 190 191 } 192 193 /** 194 * Returns formatted informations about the given $file or $id. The 195 * informations contain the time, the number of versions, the authors 196 * and the description. 197 * 198 * @param $file full filename or id 199 * @param $isid choose true, if the first parameter is a fileid 200 * @return $string html with file informations 201 */ 202 public function fileInfoToString($file, $isID = false){ 203 global $conf; 204 if($isID) $file = $this->getFilenameForID($file); 205 if($this->isMediaDir($file)) return ''; 206 list($authorsString,$desc,$count,$time) = $this->getAuthorsAndDescOfMediafile($file); 207 if(empty($count)) $count = 0; 208 return '<span class="filedesc" style=" font-size:90%;">'. 209 '<p style="margin-bottom:0px;padding-left:16px;"><span><b>'.$this->getLang('historyVersion').':</b> '.strftime($conf['dformat'],intval($time)).' ('.$count.' '.($count == 1?$this->getLang('version'):$this->getLang('versions')).')</span></b>'. 210 '<p style="margin-bottom:0px;padding-left:16px;"><span><b>'.$this->getLang('filelistAuthor').'</b>: '.$authorsString.'</span></p>'. 211 (($desc != '' && $desc != $lang['created'])?'<p style="margin-bottom:2px;padding-left:16px;"><b>'.$this->getLang('historyComment').'</b>: '.$desc.'</p>':'').'</span>'; 212 } 213 214 215 216 217 /** Returns the authors of the given mediafile as string. If plugin authorlist is enabled, 218 * authors will be linked as configured in this plugin. 219 */ 220 public function getAuthorsAndDescOfMediafile($file){ 221 global $ID; 222 if($this->getConf('linkAuthor') && !plugin_isdisabled('authorlist')){ 223 $authorlist = $this->loadHelper('authorlist',true); 224 $authorlist->setOptions($ID,array('displayaslist'=>false)); 225 } 226 $meta = $this->getMediaMeta($file); 227 if(!empty($meta)){ 228 $authors = array(); 229 $line =array(); 230 foreach($meta as $onemeta){ 231 $line = explode("\t", $onemeta); 232 if($line[4] != "" && !in_array($line[4],$authors)) array_push($authors,$line[4]); 233 } 234 if($authorlist){ 235 foreach($authors as &$author){ 236 $author=$authorlist->renderOneAuthor($author,$authorlist->getFullname($author)); 237 } 238 } 239 return array(implode(", ", $authors),$line[5],count($meta),$line[0]); // $line[5] is the latest filedescription 240 } 241 return ''; 242 } 243 244 /** Returns the meta data of the given mediafile */ 245 public function getMediaMeta($file){ 246 global $conf; 247 if(file_exists($conf['mediametadir'].'/'.$file.'.changes')) return file($conf['mediametadir'].'/'.$file.'.changes'); 248 return array(); 249 } 250 251 /** 252 * Builds a table for the mediameta information. The rest is done by 253 * jQuery 254 * 255 * @param $file file to find the metadata for 256 * @return $ret htmltable with included javascript 257 */ 258 public function mediaMetaStart($file){ 259 global $lang; 260 $ret = '<div class="historyOC">'.DOKU_LF; 261 $ret .= DOKU_TAB.'<div class="table"><table width="100%" class="inline">'.DOKU_LF; 262 $ret .= DOKU_TAB.DOKU_TAB.'<tr class="row0">'.DOKU_LF; 263 $ret .= DOKU_TAB.DOKU_TAB.DOKU_TAB.'<th class="col0" width="20%" >'.($this->getLang('historyVersion')).'</th><th width="20%" class="col1">'.($this->getLang('historyAuthor')).'</th><th width="10%" class="col2">'.($this->getLang('filelistSize')).'</th><th class="col3" width="45%">'.($this->getLang('historyComment')).'</th>'.DOKU_LF; 264 $ret .= DOKU_TAB.DOKU_TAB.'</tr>'.DOKU_LF; 265 $ret .= DOKU_TAB.DOKU_TAB.'<tr><td colspan="4" class="load"></td></tr>'.DOKU_LF; 266 $ret .= DOKU_TAB.'</table></div></div>'.DOKU_LF; 267 // To run javascript only if filelist is on this side 268 $ret .= DOKU_TAB.'<script type="text/javascript">filehistory.start("'.$file.'");</script>'.DOKU_LF; 269 $wikiid = $this->pathToWikiID($file); 270 $ns = getNS($wikiid); 271 $mediamanager = '<a class="mmLink" href="'.DOKU_URL.'doku.php?ns='.$ns.'&image='.$this->pathToWikiID($file).'&do=media&tab_details=history">'.$this->getLang('compare').'</a>'; 272 $ret .= '<p>'.$this->getLang('mediamanager_info').' '.$mediamanager.'</p>'; 273 return $ret; 274 275 276 } 277 278 /** 279 * Builds the innards for the table generated by mediaMetaStart() 280 * is called via jQuery. 281 * 282 * @param $file file to find the metadata for 283 * @return $ret html-table-rows with media meta 284 */ 285 public function mediaMetaAsTable($file){ 286 $ret = ""; 287 global $conf; 288 global $ID; 289 global $lang; 290 $meta = $this->getMediaMeta($file); 291 if(empty($meta)) return '<tr><td colspan="4" align="center">'.($this->getLang('noVersion')).'</td></tr>'; 292 $meta = array_reverse($meta); // Newest first. 293 $authorlist = false; 294 if($this->getConf('linkAuthor') && !plugin_isdisabled('authorlist')){ 295 $authorlist = $this->loadHelper('authorlist',true); 296 $authorlist->setOptions($ID,array('displayaslist'=>false)); 297 } 298 $oldmedia = $conf['mediaolddir']; 299 $nr = 1; 300 $fetch = DOKU_BASE.'lib/exe/fetch.php'; 301 foreach($meta as $onemeta){ 302 $line = explode("\t", $onemeta); 303 $time = strftime($conf['dformat'],intval($line[0])); 304 if($nr > 1){ // in attic 305 list($name, $ext) = $this->filenameAndExtension($file); 306 $path = $oldmedia.'/'.$name.'.'.$line[0].'.'.$ext; 307 $link = '<a title="'.$time.'" href="'.$fetch.'?media='.($this->pathToWikiID($file)).'&rev='.$line[0].'" target="_blank">'.$time.'</a>'; 308 }else{ 309 $path = $conf['mediadir'].'/'.$file; 310 $link = $time.' <small>('.$lang['current'].')<small>';; 311 312 } 313 $size = (file_exists($path)) ? filesize_h(filesize($path)) : '--'; 314 if(empty($line[4])) $author = $line[1]; // IP if no author 315 else $author = ($authorlist)?$authorlist->renderOneAuthor($line[4],$authorlist->getFullname($line[4])) : $line[4]; 316 //$author .= '<span class="ip">('.$line[1].')</span>'; 317 if($line[2] == DOKU_CHANGE_TYPE_MOVE) $extra = ' ('.$this->getLang('movedfrom').' '.hsc($line[6]).')'; 318 else $extra = ''; 319 320 321 $ret .= '<tr class=" row'.$nr.'">'; 322 $ret .= '<td class="col0" > '.$link.' </td><td class="col1">'.$author.'</td><td class="col2">'.$size.'</td><td class="col3">'.$line[5].$extra.'</td>'; 323 $ret .= '</tr>'; 324 $nr++; 325 } 326 return $ret; 327 328 329 } 330 331 /** 332 * Returns the filename and extension (Can be replaced by php nativ 333 * function pathinfo, only for compatibility 334 * 335 * @param $file file 336 * @return @array filename and extension 337 */ 338 public function filenameAndExtension($file){ 339 $extPos = strrpos($file, '.'); 340 $ext = substr($file, $extPos + 1); 341 $name = substr($file, 0, $extPos); 342 return array($name, $ext); 343 } 344 345 346 /** 347 * Returns true, if the given source starts with http, https or ftp 348 * otherwise false 349 * 350 * @param $src string 351 * @return bool true if http(s)/ftp otherwise false 352 */ 353 public function isExternal($src){ 354 if ( preg_match('#^(https?|ftp)#i',$src) ) { 355 return true; 356 } 357 return false; 358 } 359 360 /** 361 * Tests if an url match the the urls or pattern specified in the 362 * plugin configuration. 363 * 364 * @param $url URL 365 * @return bool true if allowed 366 */ 367 public function isAllowedExternalImage($url){ 368 if($this->getConf('allowExternalImages') == 1) return true; // all external images are allowed 369 $allowedImagesURL = explode(',',$this->getConf('allowedImagesURL')); 370 $match = false; 371 foreach($allowedImagesURL as $allowedURL){ 372 $allowedURL = trim($allowedURL); 373 if(empty($allowedURL)) continue; 374 if(strpos($url, $allowedURL) === 0 ){ 375 $match = true; 376 break; 377 } 378 } 379 if($match) return true; // save some time, if we have a match until here 380 $allowedImagesURLregexp = explode(',',$this->getConf('allowedImagesURLregexp')); 381 foreach($allowedImagesURLregexp as $pattern){ 382 $pattern = trim($pattern); 383 if(empty($pattern)) continue; 384 if(preg_match('#'.str_replace('#','\\#',$pattern).'#i',$url)){ 385 $match = true; 386 break; 387 } 388 } 389 return $match; 390 } 391 392 /** 393 * Renders an internal media link. This is nearly the same function as internalmedia(...) 394 * in inc/parser/xhtml.php extended to getting the filename from fileid. 395 * 396 * @author Harry Fuecks <hfuecks@gmail.com> 397 * @author Andreas Gohr <andi@splitbrain.org> 398 * @author Martin Schulte <lebowski[at]corvus[dot]uberspace[dot]de> 399 */ 400 public function internalmedia($fileid, $src, $title=NULL, $align=NULL, $width=NULL,$height=NULL, $cache=NULL, $linking=NULL) { 401 global $ID; 402 $filelist = false; 403 list($src,$hash) = explode('#',$src,2); 404 if($fileid != '' && $fileid > 0){ 405 $res = $this -> getFilenameForID($fileid, true); 406 } 407 if(isset($res)){ 408 $src = $res; 409 if($src == ''){ // we are at the top 410 $src = '/'; 411 if(empty($title)) $title = '/'; 412 } 413 $exists = true; 414 }else{ 415 $oldsrc = $src; 416 resolve_mediaid(getNS($ID),$src, $exists); 417 if($exists){ 418 $fileid = $this->fileIDForWikiID($src); 419 }else{// Maybe directory 420 $fileid = $this->fileIDForWikiID($oldsrc); 421 if($fileid != '' && $fileid > 0){ 422 $src = $oldsrc; 423 $exists = true; 424 } 425 } 426 } 427 $noLink = false; 428 $render = ($linking == 'linkonly') ? false : true; 429 // + fileid first parameter 430 $link = $this->_getMediaLinkConf($fileid,$src, $title, $align, $width, $height, $cache, $render); 431 432 list($ext,$mime,$dl) = mimetype($src,false); 433 if(substr($mime,0,5) == 'image' && $render){ 434 // + fileid & $this-> 435 $link['url'] = $this->ml($src,array('id'=>$ID,'cache'=>$cache,'fileid'=>$fileid),($linking=='direct')); 436 }elseif($mime == 'application/x-shockwave-flash' && $render){ 437 // don't link flash movies 438 $noLink = true; 439 }else{ 440 // add file icons 441 $class = preg_replace('/[^_\-a-z0-9]+/i','_',$ext); 442 // + mimetype folder 443 if(empty($ext)){ 444 if($this->getMimetypeForID($fileid) == 'httpd/unix-directory') { 445 $class = 'folder'; 446 if($linking =='direct') $filelist = true; 447 } 448 } 449 $link['class'] .= ' mediafile mf_'.$class; 450 // + fileid & $this-> 451 $link['url'] = $this->ml($src,array('id'=>$ID,'cache'=>$cache,'fileid'=>$fileid),($linking=='direct')); 452 // + no size if directory 453 if ($exists && $class != 'folder') $link['title'] .= ' (' . filesize_h(filesize(mediaFN($src))).')'; 454 } 455 456 if($hash) $link['url'] .= '#'.$hash; 457 458 //markup non existing files 459 if (!$exists) { 460 $link['class'] .= ' wikilink2'; 461 } 462 //output formatted 463 // + return instead of .= 464 if ($linking == 'nolink' || $noLink){ 465 return $link['name']; 466 }else{ 467 if(!$filelist){ 468 return $this->_formatLink($link); 469 }else{ 470 $link['name'] = $this->wikiIDToPath($src); 471 return $this->filelist($fileid); 472 } 473 } 474 475 476 } 477 478 /** 479 * Renders an external media link. This is the same function as externalmedia(...) 480 * in inc/parser/xhtml.php, here it returns the link and don't add it to the render doc 481 * 482 * @author Harry Fuecks <hfuecks@gmail.com> 483 * @author Andreas Gohr <andi@splitbrain.org> 484 */ 485 function externalmedia ($src, $title=NULL, $align=NULL, $width=NULL, 486 $height=NULL, $cache=NULL, $linking=NULL) { 487 list($src,$hash) = explode('#',$src,2); 488 $noLink = false; 489 $render = ($linking == 'linkonly') ? false : true; 490 // + -1 as fileid 491 $link = $this->_getMediaLinkConf(-1,$src, $title, $align, $width, $height, $cache, $render); 492 493 // use the originally ml function 494 $link['url'] = ml($src,array('cache'=>$cache)); 495 496 list($ext,$mime,$dl) = mimetype($src,false); 497 if(substr($mime,0,5) == 'image' && $render){ 498 // link only jpeg images 499 // if ($ext != 'jpg' && $ext != 'jpeg') $noLink = true; 500 }elseif($mime == 'application/x-shockwave-flash' && $render){ 501 // don't link flash movies 502 $noLink = true; 503 }else{ 504 // add file icons 505 $class = preg_replace('/[^_\-a-z0-9]+/i','_',$ext); 506 $link['class'] .= ' mediafile mf_'.$class; 507 } 508 509 if($hash) $link['url'] .= '#'.$hash; 510 511 //output formatted 512 if ($linking == 'nolink' || $noLink) return $link['name']; 513 else return $this->_formatLink($link); 514 } 515 516 /** Renders a list with all files of the given folder. Using jQuery (see script.js). 517 */ 518 public function filelist($folderid, $link){ 519 if(!isset($link)) $link = '<div class="filelistheader">'.($this->getLang('filelistHeader')).' '.$this->internalmedia($folderid,NULL,NULL, NULL, NULL,NULL, NULL, 'details').'</div>'; 520 $ret = '<div class="filelistOC fileid'.$folderid.'">'.$link.DOKU_LF; 521 $ret .= DOKU_TAB.'<div class="table"><table width="100%" class="inline">'.DOKU_LF; 522 $ret .= DOKU_TAB.DOKU_TAB.'<tr class="row0">'.DOKU_LF; 523 $ret .= DOKU_TAB.DOKU_TAB.DOKU_TAB.'<th class="col0">'.($this->getLang('filelistName')).'</th><th class="col1">'.($this->getLang('filelistAuthor')).'</th><th class="col2">'.($this->getLang('filelistDate')).'</th><th class="col3">'.($this->getLang('filelistSize')).'</th><th class="col4"></th>'.DOKU_LF; 524 $ret .= DOKU_TAB.DOKU_TAB.'</tr>'.DOKU_LF; 525 $ret .= DOKU_TAB.DOKU_TAB.'<tr><td colspan="5" class="load"></td></tr>'.DOKU_LF; 526 $ret .= DOKU_TAB.'</table></div></div>'.DOKU_LF; 527 // To run javascript only if filelist is on this side 528 $ret .= DOKU_TAB.'<script type="text/javascript"> window.filelistOnThisSide = true;</script>'.DOKU_LF; 529 return $ret; 530 } 531 532 533 /** 534 * This is nearly the same function as ml(...) in inc/common.php 535 * extended to getting the filename from fileid. 536 * 537 * Build a link to a media file 538 * 539 * Will return a link to the detail page if $direct is false 540 * 541 * The $more parameter should always be given as array, the function then 542 * will strip default parameters to produce even cleaner URLs 543 * 544 * This is nearly the code from inc/common.php. Replaced lib/exe/fetch.php 545 * with lib/plugins/owncloud/exe/fetch.php. 546 * 547 * @author Andreas Gohr <andi@splitbrain.org> 548 * @author Martin Schulte <lebowski[at]corvus[dot]uberspace[dot]de> 549 * 550 * @param string $id the media file id or URL 551 * @param mixed $more string or array with additional parameters 552 * @param bool $direct link to detail page if false 553 * @param string $sep URL parameter separator 554 * @param bool $abs Create an absolute URL 555 * @return string 556 */ 557 function ml($id = '', $more = '', $direct = true, $sep = '&', $abs = false) { 558 559 global $conf; 560 $isexternalimage = media_isexternal($id); 561 if(is_array($more)) { 562 // add token for resized images 563 if(!empty($more['w']) || !empty($more['h']) || $isexternalimage ){ 564 $more['tok'] = media_get_token($id,$more['w'],$more['h']); 565 } 566 // strip defaults for shorter URLs 567 if(isset($more['cache']) && $more['cache'] == 'cache') unset($more['cache']); 568 if(empty($more['w'])) unset($more['w']); 569 if(empty($more['h'])) unset($more['h']); 570 //+ fileid 571 if($more['fileid'] <1 || $more['fileid'] == '') unset($more['fileid']); 572 if(isset($more['id']) && $direct) unset($more['id']); 573 $more = buildURLparams($more, $sep); 574 } else { 575 $matches = array(); 576 if (preg_match_all('/\b(w|h)=(\d*)\b/',$more,$matches,PREG_SET_ORDER) || $isexternalimage){ 577 $resize = array('w'=>0, 'h'=>0); 578 foreach ($matches as $match){ 579 $resize[$match[1]] = $match[2]; 580 } 581 $more .= $more === '' ? '' : $sep; 582 $more .= 'tok='.media_get_token($id,$resize['w'],$resize['h']); 583 } 584 $more = str_replace('cache=cache', '', $more); //skip default 585 $more = str_replace(',,', ',', $more); 586 $more = str_replace(',', $sep, $more); 587 } 588 589 if($abs) { 590 $xlink = DOKU_URL; 591 } else { 592 $xlink = DOKU_BASE; 593 } 594 595 // external URLs are always direct without rewriting 596 if(preg_match('#^(https?|ftp)://#i', $id)) { 597 // + changed lib/exe to lib/plugins/owncloud/ 598 $xlink .= 'lib/plugins/owncloud/exe/fetch.php'; 599 // add hash: 600 $xlink .= '?hash='.substr(md5(auth_cookiesalt().$id), 0, 6); 601 if($more) { 602 $xlink .= $sep.$more; 603 $xlink .= $sep.'media='.rawurlencode($id); 604 } else { 605 $xlink .= $sep.'media='.rawurlencode($id); 606 } 607 return $xlink; 608 } 609 610 $id = idfilter($id); 611 612 // decide on scriptname 613 if($direct) { 614 if($conf['userewrite'] == 1) { 615 $script = '_media'; 616 } else { 617 // + changed lib/exe to lib/plugins/owncloud/ 618 $script = 'lib/plugins/owncloud/exe/fetch.php'; 619 } 620 } else { 621 if($conf['userewrite'] == 1) { 622 $script = '_detail'; 623 } else { 624 // + changed lib/exe to lib/plugins/owncloud/ 625 $script = 'lib/plugins/owncloud/exe/detail.php'; 626 } 627 } 628 629 // build URL based on rewrite mode 630 if($conf['userewrite']) { 631 $xlink .= $script.'/'.$id; 632 if($more) $xlink .= '?'.$more; 633 } else { 634 if($more) { 635 $xlink .= $script.'?'.$more; 636 $xlink .= $sep.'media='.$id; 637 } else { 638 $xlink .= $script.'?media='.$id; 639 } 640 } 641 642 return $xlink; 643 } 644 645 646 /** 647 * _getMediaLinkConf is a helperfunction to internalmedia() and externalmedia() 648 * which returns a basic link to a media (from inc/parser/xhtml.php). 649 * 650 * + fileid as first parameter 651 * 652 * @author Pierre Spring <pierre.spring@liip.ch> 653 * @param string $src 654 * @param string $title 655 * @param string $align 656 * @param string $width 657 * @param string $height 658 * @param string $cache 659 * @param string $render 660 * @access protected 661 * @return array 662 */ 663 function _getMediaLinkConf($fileid,$src, $title, $align, $width, $height, $cache, $render) 664 { 665 global $conf; 666 667 $link = array(); 668 $link['class'] = 'media'; 669 $link['style'] = ''; 670 $link['pre'] = ''; 671 $link['suf'] = ''; 672 $link['more'] = ''; 673 $link['target'] = $conf['target']['media']; 674 $link['title'] = $this->_xmlEntities($src); 675 // + fileid first parameter 676 $link['name'] = $this->_media($fileid, $src, $title, $align, $width, $height, $cache, $render); 677 678 return $link; 679 } 680 681 /** 682 * Renders internal and external media (from inc/parser/xhtml.php) 683 * 684 * add fileid as first parameter 685 * 686 * @author Andreas Gohr <andi@splitbrain.org> 687 */ 688 function _media($fileid, $src, $title=NULL, $align=NULL, $width=NULL, 689 $height=NULL, $cache=NULL, $render = true) { 690 691 $ret = ''; 692 693 list($ext,$mime,$dl) = mimetype($src); 694 if(substr($mime,0,5) == 'image'){ 695 // first get the $title 696 if (!is_null($title)) { 697 $title = $this->_xmlEntities($title); 698 }elseif($ext == 'jpg' || $ext == 'jpeg'){ 699 //try to use the caption from IPTC/EXIF 700 require_once(DOKU_INC.'inc/JpegMeta.php'); 701 $jpeg =new JpegMeta(mediaFN($src)); 702 if($jpeg !== false) $cap = $jpeg->getTitle(); 703 if($cap){ 704 $title = $this->_xmlEntities($cap); 705 } 706 } 707 if (!$render) { 708 // if the picture is not supposed to be rendered 709 // return the title of the picture 710 if (!$title) { 711 // just show the sourcename 712 $title = $this->_xmlEntities(utf8_basename(noNS($src))); 713 } 714 return $title; 715 } 716 //add image tag 717 // + $this 718 $ret .= '<img src="'.($this->ml($src,array('fileid'=>$fileid,'w'=>$width,'h'=>$height,'cache'=>$cache))).'"'; 719 $ret .= ' class="media'.$align.'"'; 720 721 if ($title) { 722 $ret .= ' title="' . $title . '"'; 723 $ret .= ' alt="' . $title .'"'; 724 }else{ 725 $ret .= ' alt=""'; 726 } 727 728 if ( !is_null($width) ) 729 $ret .= ' width="'.$this->_xmlEntities($width).'"'; 730 731 if ( !is_null($height) ) 732 $ret .= ' height="'.$this->_xmlEntities($height).'"'; 733 734 $ret .= ' />'; 735 736 }elseif($mime == 'application/x-shockwave-flash'){ 737 if (!$render) { 738 // if the flash is not supposed to be rendered 739 // return the title of the flash 740 if (!$title) { 741 // just show the sourcename 742 $title = utf8_basename(noNS($src)); 743 } 744 return $this->_xmlEntities($title); 745 } 746 747 $att = array(); 748 $att['class'] = "media$align"; 749 if($align == 'right') $att['align'] = 'right'; 750 if($align == 'left') $att['align'] = 'left'; 751 $ret .= html_flashobject(ml($src,array('cache'=>$cache),true,'&'),$width,$height, 752 array('quality' => 'high'), 753 null, 754 $att, 755 $this->_xmlEntities($title)); 756 }elseif($title){ 757 // well at least we have a title to display 758 $ret .= $this->_xmlEntities($title); 759 }else{ 760 // just show the sourcename 761 $ret .= $this->_xmlEntities(utf8_basename(noNS($src))); 762 } 763 764 return $ret; 765 } 766 767 768 769 770 /** 771 * (from inc/parser/xhtml.php) 772 */ 773 function _xmlEntities($string) { 774 return htmlspecialchars($string,ENT_QUOTES,'UTF-8'); 775 } 776 777 /** 778 * Build a link (from inc/xhtml) 779 * 780 * Assembles all parts defined in $link returns HTML for the link 781 * 782 * @author Andreas Gohr <andi@splitbrain.org> 783 */ 784 function _formatLink($link){ 785 //make sure the url is XHTML compliant (skip mailto) 786 if(substr($link['url'],0,7) != 'mailto:'){ 787 $link['url'] = str_replace('&','&',$link['url']); 788 $link['url'] = str_replace('&amp;','&',$link['url']); 789 } 790 //remove double encodings in titles 791 $link['title'] = str_replace('&amp;','&',$link['title']); 792 793 // be sure there are no bad chars in url or title 794 // (we can't do this for name because it can contain an img tag) 795 $link['url'] = strtr($link['url'],array('>'=>'%3E','<'=>'%3C','"'=>'%22')); 796 $link['title'] = strtr($link['title'],array('>'=>'>','<'=>'<','"'=>'"')); 797 798 $ret = ''; 799 $ret .= $link['pre']; 800 $ret .= '<a href="'.$link['url'].'"'; 801 if(!empty($link['class'])) $ret .= ' class="'.$link['class'].'"'; 802 if(!empty($link['target'])) $ret .= ' target="'.$link['target'].'"'; 803 if(!empty($link['title'])) $ret .= ' title="'.$link['title'].'"'; 804 if(!empty($link['style'])) $ret .= ' style="'.$link['style'].'"'; 805 if(!empty($link['rel'])) $ret .= ' rel="'.$link['rel'].'"'; 806 if(!empty($link['more'])) $ret .= ' '.$link['more']; 807 $ret .= '>'; 808 $ret .= $link['name']; 809 $ret .= '</a>'; 810 $ret .= $link['suf']; 811 return $ret; 812 } 813 814 /* Looking for a fileid when a wikiid is given 815 * 816 * @param String wikiid of the mediafile 817 * @return fileid for a wikiid 818 */ 819 public function fileIDForWikiID($src){ 820 $path = str_replace(':','/',$src); 821 return $this->getIDForFilename($path); 822 } 823 824 825 /* Returns a list with all pages using the given media 826 * 827 * @param String fileid of the mediafile 828 * @return String List with all pages using the specified media. 829 */ 830 public function mediaInUse($fileID){ 831 $this->dbQuery('SELECT `firstheading`,`wikipage` FROM `*PREFIX*dokuwiki_media_use` WHERE fileid = ?', array($fileID)); 832 $rows = $this->lastQuery->numRows(); 833 $ret = '<h3 class="sectionedit3">'.$this->getLang('mediaUsedIn').'</h3>'; 834 if(empty($rows) || $rows == 0) return '<h3 class="sectionedit3">'.$this->getLang('noUsage').'</h3>'; 835 $ret .= '<ul>'.DOKU_TAB; 836 for($i = 1; $i <= $rows; $i++){ 837 $row = $this->lastQuery->fetchRow(); 838 $title = ($row['firstheading']!='')?$row['firstheading'].' ('.$row['wikipage'].')':$row['wikipage']; 839 $ret .= DOKU_TAB.'<li><span class="curid"><a href="'.wl($row['wikipage']).'" class="wikilink1" title="'.$title.'">'.$title.'</a></span></li>'.DOKU_LF; 840 } 841 $ret .= '</ul>'.DOKU_LF; 842 return $ret; 843 } 844 845 846} 847