[ Index ]

PHP Cross Reference of DokuWiki

title

Body

[close]

/inc/ -> media.php (source)

   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  if(!defined('DOKU_INC')) define('DOKU_INC',fullpath(dirname(__FILE__).'/../').'/');
  10  if(!defined('NL')) define('NL',"\n");
  11  
  12  require_once (DOKU_INC.'inc/html.php');
  13  require_once (DOKU_INC.'inc/search.php');
  14  require_once (DOKU_INC.'inc/JpegMeta.php');
  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  function media_filesinuse($data,$id){
  25      global $lang;
  26      echo '<h1>'.$lang['reference'].' <code>'.hsc(noNS($id)).'</code></h1>';
  27      echo '<p>'.hsc($lang['ref_inuse']).'</p>';
  28  
  29      $hidden=0; //count of hits without read permission
  30      foreach($data as $row){
  31          if(auth_quickaclcheck($row) >= AUTH_READ && isVisiblePage($row)){
  32              echo '<div class="search_result">';
  33              echo '<span class="mediaref_ref">'.hsc($row).'</span>';
  34              echo '</div>';
  35          }else
  36          $hidden++;
  37      }
  38      if ($hidden){
  39        print '<div class="mediaref_hidden">'.$lang['ref_hidden'].'</div>';
  40      }
  41  }
  42  
  43  /**
  44   * Handles the saving of image meta data
  45   *
  46   * @author Andreas Gohr <andi@splitbrain.org>
  47   */
  48  function media_metasave($id,$auth,$data){
  49      if($auth < AUTH_UPLOAD) return false;
  50      if(!checkSecurityToken()) return false;
  51      global $lang;
  52      global $conf;
  53      $src = mediaFN($id);
  54  
  55      $meta = new JpegMeta($src);
  56      $meta->_parseAll();
  57  
  58      foreach($data as $key => $val){
  59          $val=trim($val);
  60          if(empty($val)){
  61              $meta->deleteField($key);
  62          }else{
  63              $meta->setField($key,$val);
  64          }
  65      }
  66  
  67      if($meta->save()){
  68          if($conf['fperm']) chmod($src, $conf['fperm']);
  69          msg($lang['metasaveok'],1);
  70          return $id;
  71      }else{
  72          msg($lang['metasaveerr'],-1);
  73          return false;
  74      }
  75  }
  76  
  77  /**
  78   * Display the form to edit image meta data
  79   *
  80   * @author Andreas Gohr <andi@splitbrain.org>
  81   */
  82  function media_metaform($id,$auth){
  83      if($auth < AUTH_UPLOAD) return false;
  84      global $lang;
  85  
  86      // load the field descriptions
  87      static $fields = null;
  88      if(is_null($fields)){
  89          include(DOKU_CONF.'mediameta.php');
  90          if(@file_exists(DOKU_CONF.'mediameta.local.php')){
  91              include(DOKU_CONF.'mediameta.local.php');
  92          }
  93      }
  94  
  95      $src = mediaFN($id);
  96  
  97      // output
  98      echo '<h1>'.hsc(noNS($id)).'</h1>'.NL;
  99      echo '<form action="'.DOKU_BASE.'lib/exe/mediamanager.php" accept-charset="utf-8" method="post" class="meta">'.NL;
 100      formSecurityToken();
 101      foreach($fields as $key => $field){
 102          // get current value
 103          $tags = array($field[0]);
 104          if(is_array($field[3])) $tags = array_merge($tags,$field[3]);
 105          $value = tpl_img_getTag($tags,'',$src);
 106          $value = cleanText($value);
 107  
 108          // prepare attributes
 109          $p = array();
 110          $p['class'] = 'edit';
 111          $p['id']    = 'meta__'.$key;
 112          $p['name']  = 'meta['.$field[0].']';
 113  
 114          // put label
 115          echo '<div class="metafield">';
 116          echo '<label for="meta__'.$key.'">';
 117          echo ($lang[$field[1]]) ? $lang[$field[1]] : $field[1];
 118          echo ':</label>';
 119  
 120          // put input field
 121          if($field[2] == 'text'){
 122              $p['value'] = $value;
 123              $p['type']  = 'text';
 124              $att = buildAttributes($p);
 125              echo "<input $att/>".NL;
 126          }else{
 127              $att = buildAttributes($p);
 128              echo "<textarea $att rows=\"6\" cols=\"50\">".formText($value).'</textarea>'.NL;
 129          }
 130          echo '</div>'.NL;
 131      }
 132      echo '<div class="buttons">'.NL;
 133      echo '<input type="hidden" name="img" value="'.hsc($id).'" />'.NL;
 134      echo '<input name="do[save]" type="submit" value="'.$lang['btn_save'].
 135           '" title="'.$lang['btn_save'].' [S]" accesskey="s" class="button" />'.NL;
 136      echo '<input name="do[cancel]" type="submit" value="'.$lang['btn_cancel'].
 137           '" title="'.$lang['btn_cancel'].' [C]" accesskey="c" class="button" />'.NL;
 138      echo '</div>'.NL;
 139      echo '</form>'.NL;
 140  }
 141  
 142  
 143  /**
 144   * Handles media file deletions
 145   *
 146   * If configured, checks for media references before deletion
 147   *
 148   * @author Andreas Gohr <andi@splitbrain.org>
 149   * @return mixed false on error, true on delete or array with refs
 150   */
 151  function media_delete($id,$auth){
 152      if($auth < AUTH_DELETE) return false;
 153      if(!checkSecurityToken()) return false;
 154      global $conf;
 155      global $lang;
 156  
 157      // check for references if needed
 158      $mediareferences = array();
 159      if($conf['refcheck']){
 160          require_once (DOKU_INC.'inc/fulltext.php');
 161          $mediareferences = ft_mediause($id,$conf['refshow']);
 162      }
 163  
 164      if(!count($mediareferences)){
 165          $file = mediaFN($id);
 166  
 167          // trigger an event - MEDIA_DELETE_FILE
 168          $data['name'] = basename($file);
 169          $data['path'] = $file;
 170          $data['size'] = (@file_exists($file)) ? filesize($file) : 0;
 171          $evt = new Doku_Event('MEDIA_DELETE_FILE',$data);
 172          if ($evt->advise_before()) {
 173              if(@unlink($file)){
 174                  msg(str_replace('%s',noNS($id),$lang['deletesucc']),1);
 175                  $del = io_sweepNS($id,'mediadir');
 176                  if($del){
 177                      // current namespace was removed. redirecting to root ns passing msg along
 178                      header('Location: '.DOKU_URL.'lib/exe/mediamanager.php?msg1='.
 179                              rawurlencode(str_replace('%s',noNS($id),$lang['deletesucc'])));
 180                      exit;
 181                  }
 182                  return true;
 183              }
 184          }
 185          $evt->advise_after();
 186          unset($evt);
 187  
 188          //something went wrong
 189          msg(str_replace('%s',$file,$lang['deletefail']),-1);
 190          return false;
 191      }elseif(!$conf['refshow']){
 192          msg(str_replace('%s',noNS($id),$lang['mediainuse']),0);
 193          return false;
 194      }
 195  
 196      return $mediareferences;
 197  }
 198  
 199  /**
 200   * Handles media file uploads
 201   *
 202   * This generates an action event and delegates to _media_upload_action().
 203   * Action plugins are allowed to pre/postprocess the uploaded file.
 204   * (The triggered event is preventable.)
 205   *
 206   * Event data:
 207   * $data[0]     fn_tmp: the temporary file name (read from $_FILES)
 208   * $data[1]     fn: the file name of the uploaded file
 209   * $data[2]     id: the future directory id of the uploaded file
 210   * $data[3]     imime: the mimetype of the uploaded file
 211   *
 212   * @triggers MEDIA_UPLOAD_FINISH
 213   * @author Andreas Gohr <andi@splitbrain.org>
 214   * @author Michael Klier <chi@chimeric.de>
 215   * @return mixed false on error, id of the new file on success
 216   */
 217  function media_upload($ns,$auth){
 218      if($auth < AUTH_UPLOAD) return false;
 219      if(!checkSecurityToken()) return false;
 220      require_once (DOKU_INC.'inc/confutils.php');
 221      global $lang;
 222      global $conf;
 223  
 224      // get file and id
 225      $id   = $_POST['id'];
 226      $file = $_FILES['upload'];
 227      if(empty($id)) $id = $file['name'];
 228  
 229      // check for data
 230      if(!@filesize($file['tmp_name'])){
 231          msg('No data uploaded. Disk full?',-1);
 232          return false;
 233      }
 234  
 235      // check extensions
 236      list($fext,$fmime) = mimetype($file['name']);
 237      list($iext,$imime) = mimetype($id);
 238      if($fext && !$iext){
 239          // no extension specified in id - read original one
 240          $id   .= '.'.$fext;
 241          $imime = $fmime;
 242      }elseif($fext && $fext != $iext){
 243          // extension was changed, print warning
 244          msg(sprintf($lang['mediaextchange'],$fext,$iext));
 245      }
 246  
 247      // get filename
 248      $id   = cleanID($ns.':'.$id,false,true);
 249      $fn   = mediaFN($id);
 250  
 251      // get filetype regexp
 252      $types = array_keys(getMimeTypes());
 253      $types = array_map(create_function('$q','return preg_quote($q,"/");'),$types);
 254      $regex = join('|',$types);
 255  
 256      // because a temp file was created already
 257      if(preg_match('/\.('.$regex.')$/i',$fn)){
 258          //check for overwrite
 259          if(@file_exists($fn) && (!$_REQUEST['ow'] || $auth < AUTH_DELETE)){
 260              msg($lang['uploadexist'],0);
 261              return false;
 262          }
 263          // check for valid content
 264          $ok = media_contentcheck($file['tmp_name'],$imime);
 265          if($ok == -1){
 266              msg(sprintf($lang['uploadbadcontent'],".$iext"),-1);
 267              return false;
 268          }elseif($ok == -2){
 269              msg($lang['uploadspam'],-1);
 270              return false;
 271          }elseif($ok == -3){
 272              msg($lang['uploadxss'],-1);
 273              return false;
 274          }
 275  
 276          // prepare event data
 277          $data[0] = $file['tmp_name'];
 278          $data[1] = $fn;
 279          $data[2] = $id;
 280          $data[3] = $imime;
 281  
 282          // trigger event
 283          return trigger_event('MEDIA_UPLOAD_FINISH', $data, '_media_upload_action', true);
 284  
 285      }else{
 286          msg($lang['uploadwrong'],-1);
 287      }
 288      return false;
 289  }
 290  
 291  /**
 292   * Callback adapter for media_upload_finish()
 293   * @author Michael Klier <chi@chimeric.de>
 294   */
 295  function _media_upload_action($data) {
 296      // fixme do further sanity tests of given data?
 297      if(is_array($data) && count($data)===4) {
 298          return media_upload_finish($data[0], $data[1], $data[2], $data[3]);
 299      } else {
 300          return false; //callback error
 301      }
 302  }
 303  
 304  /**
 305   * Saves an uploaded media file
 306   *
 307   * @author Andreas Gohr <andi@splitbrain.org>
 308   * @author Michael Klier <chi@chimeric.de>
 309   */
 310  function media_upload_finish($fn_tmp, $fn, $id, $imime) {
 311      global $conf;
 312      global $lang;
 313  
 314      // prepare directory
 315      io_createNamespace($id, 'media');
 316  
 317      if(move_uploaded_file($fn_tmp, $fn)) {
 318          // Set the correct permission here.
 319          // Always chmod media because they may be saved with different permissions than expected from the php umask.
 320          // (Should normally chmod to $conf['fperm'] only if $conf['fperm'] is set.)
 321          chmod($fn, $conf['fmode']);
 322          msg($lang['uploadsucc'],1);
 323          media_notify($id,$fn,$imime);
 324          return $id;
 325      }else{
 326          msg($lang['uploadfail'],-1);
 327      }
 328  }
 329  
 330  /**
 331   * This function checks if the uploaded content is really what the
 332   * mimetype says it is. We also do spam checking for text types here.
 333   *
 334   * We need to do this stuff because we can not rely on the browser
 335   * to do this check correctly. Yes, IE is broken as usual.
 336   *
 337   * @author Andreas Gohr <andi@splitbrain.org>
 338   * @link   http://www.splitbrain.org/blog/2007-02/12-internet_explorer_facilitates_cross_site_scripting
 339   * @fixme  check all 26 magic IE filetypes here?
 340   */
 341  function media_contentcheck($file,$mime){
 342      global $conf;
 343      if($conf['iexssprotect']){
 344          $fh = @fopen($file, 'rb');
 345          if($fh){
 346              $bytes = fread($fh, 256);
 347              fclose($fh);
 348              if(preg_match('/<(script|a|img|html|body|iframe)[\s>]/i',$bytes)){
 349                  return -3;
 350              }
 351          }
 352      }
 353      if(substr($mime,0,6) == 'image/'){
 354          $info = @getimagesize($file);
 355          if($mime == 'image/gif' && $info[2] != 1){
 356              return -1;
 357          }elseif($mime == 'image/jpeg' && $info[2] != 2){
 358              return -1;
 359          }elseif($mime == 'image/png' && $info[2] != 3){
 360              return -1;
 361          }
 362          # fixme maybe check other images types as well
 363      }elseif(substr($mime,0,5) == 'text/'){
 364          global $TEXT;
 365          $TEXT = io_readFile($file);
 366          if(checkwordblock()){
 367              return -2;
 368          }
 369      }
 370      return 0;
 371  }
 372  
 373  /**
 374   * Send a notify mail on uploads
 375   *
 376   * @author Andreas Gohr <andi@splitbrain.org>
 377   */
 378  function media_notify($id,$file,$mime){
 379      global $lang;
 380      global $conf;
 381      if(empty($conf['notify'])) return; //notify enabled?
 382  
 383      $text = rawLocale('uploadmail');
 384      $text = str_replace('@DATE@',strftime($conf['dformat']),$text);
 385      $text = str_replace('@BROWSER@',$_SERVER['HTTP_USER_AGENT'],$text);
 386      $text = str_replace('@IPADDRESS@',$_SERVER['REMOTE_ADDR'],$text);
 387      $text = str_replace('@HOSTNAME@',gethostbyaddr($_SERVER['REMOTE_ADDR']),$text);
 388      $text = str_replace('@DOKUWIKIURL@',DOKU_URL,$text);
 389      $text = str_replace('@USER@',$_SERVER['REMOTE_USER'],$text);
 390      $text = str_replace('@MIME@',$mime,$text);
 391      $text = str_replace('@MEDIA@',ml($id,'',true,'&',true),$text);
 392      $text = str_replace('@SIZE@',filesize_h(filesize($file)),$text);
 393  
 394      $from = $conf['mailfrom'];
 395      $from = str_replace('@USER@',$_SERVER['REMOTE_USER'],$from);
 396      $from = str_replace('@NAME@',$INFO['userinfo']['name'],$from);
 397      $from = str_replace('@MAIL@',$INFO['userinfo']['mail'],$from);
 398  
 399      $subject = '['.$conf['title'].'] '.$lang['mail_upload'].' '.$id;
 400  
 401      mail_send($conf['notify'],$subject,$text,$from);
 402  }
 403  
 404  /**
 405   * List all files in a given Media namespace
 406   */
 407  function media_filelist($ns,$auth=null,$jump=''){
 408      global $conf;
 409      global $lang;
 410      $ns = cleanID($ns);
 411  
 412      // check auth our self if not given (needed for ajax calls)
 413      if(is_null($auth)) $auth = auth_quickaclcheck("$ns:*");
 414  
 415      echo '<h1 id="media__ns">:'.hsc($ns).'</h1>'.NL;
 416  
 417      if($auth < AUTH_READ){
 418          // FIXME: print permission warning here instead?
 419          echo '<div class="nothing">'.$lang['nothingfound'].'</div>'.NL;
 420          return;
 421      }
 422  
 423      media_uploadform($ns, $auth);
 424  
 425      $dir = utf8_encodeFN(str_replace(':','/',$ns));
 426      $data = array();
 427      search($data,$conf['mediadir'],'search_media',array('showmsg'=>true),$dir);
 428  
 429      if(!count($data)){
 430          echo '<div class="nothing">'.$lang['nothingfound'].'</div>'.NL;
 431          return;
 432      }
 433  
 434      foreach($data as $item){
 435          media_printfile($item,$auth,$jump);
 436      }
 437  }
 438  
 439  /**
 440   * Print action links for a file depending on filetype
 441   * and available permissions
 442   *
 443   * @todo contains inline javascript
 444   */
 445  function media_fileactions($item,$auth){
 446      global $lang;
 447  
 448      // view button
 449      $link = ml($item['id'],'',true);
 450      echo ' <a href="'.$link.'" target="_blank"><img src="'.DOKU_BASE.'lib/images/magnifier.png" '.
 451           'alt="'.$lang['mediaview'].'" title="'.$lang['mediaview'].'" class="btn" /></a>';
 452  
 453  
 454      // no further actions if not writable
 455      if(!$item['writable']) return;
 456  
 457      // delete button
 458      if($auth >= AUTH_DELETE){
 459          echo ' <a href="'.DOKU_BASE.'lib/exe/mediamanager.php?delete='.rawurlencode($item['id']).
 460               '&amp;sectok='.getSecurityToken().'" class="btn_media_delete" title="'.$item['id'].'">'.
 461               '<img src="'.DOKU_BASE.'lib/images/trash.png" alt="'.$lang['btn_delete'].'" '.
 462               'title="'.$lang['btn_delete'].'" class="btn" /></a>';
 463      }
 464  
 465      // edit button
 466      if($auth >= AUTH_UPLOAD && $item['isimg'] && $item['meta']->getField('File.Mime') == 'image/jpeg'){
 467          echo ' <a href="'.DOKU_BASE.'lib/exe/mediamanager.php?edit='.rawurlencode($item['id']).'">'.
 468               '<img src="'.DOKU_BASE.'lib/images/pencil.png" alt="'.$lang['metaedit'].'" '.
 469               'title="'.$lang['metaedit'].'" class="btn" /></a>';
 470      }
 471  
 472  }
 473  
 474  /**
 475   * Formats and prints one file in the list
 476   */
 477  function media_printfile($item,$auth,$jump){
 478      global $lang;
 479      global $conf;
 480  
 481      // Prepare zebra coloring
 482      // I always wanted to use this variable name :-D
 483      static $twibble = 1;
 484      $twibble *= -1;
 485      $zebra = ($twibble == -1) ? 'odd' : 'even';
 486  
 487      // Automatically jump to recent action
 488      if($jump == $item['id']) {
 489          $jump = ' id="scroll__here" ';
 490      }else{
 491          $jump = '';
 492      }
 493  
 494      // Prepare fileicons
 495      list($ext,$mime) = mimetype($item['file']);
 496      $class = preg_replace('/[^_\-a-z0-9]+/i','_',$ext);
 497      $class = 'select mediafile mf_'.$class;
 498  
 499      // Prepare filename
 500      $file = utf8_decodeFN($item['file']);
 501  
 502      // Prepare info
 503      $info = '';
 504      if($item['isimg']){
 505          $info .= (int) $item['meta']->getField('File.Width');
 506          $info .= '&#215;';
 507          $info .= (int) $item['meta']->getField('File.Height');
 508          $info .= ' ';
 509      }
 510      $info .= '<i>'.strftime($conf['dformat'],$item['mtime']).'</i>';
 511      $info .= ' ';
 512      $info .= filesize_h($item['size']);
 513  
 514      // ouput
 515      echo '<div class="'.$zebra.'"'.$jump.'>'.NL;
 516      echo '<a name="h_'.$item['id'].'" class="'.$class.'">'.$file.'</a> ';
 517      echo '<span class="info">('.$info.')</span>'.NL;
 518