[ Index ]
 

Code source de Serendipity 1.2

Accédez au Source d'autres logiciels libres

title

Body

[fermer]

/include/ -> functions_images.inc.php (source)

   1  <?php # $Id: functions_images.inc.php 1816 2007-08-06 10:18:39Z garvinhicking $
   2  # Copyright (c) 2003-2005, Jannis Hermanns (on behalf the Serendipity Developer Team)
   3  # All rights reserved.  See LICENSE file for licensing details
   4  
   5  if (IN_serendipity !== true) {
   6      die ("Don't hack!");
   7  }
   8  
   9  if (defined('S9Y_FRAMEWORK_IMAGES')) {
  10      return;
  11  }
  12  @define('S9Y_FRAMEWORK_IMAGES', true);
  13  
  14  /**
  15   * Check if an uploaded file is "evil"
  16   *
  17   * @access public
  18   * @param   string  Input filename
  19   * @return boolean
  20   */
  21  function serendipity_isActiveFile($file) {
  22      if (preg_match('@^\.@', $file)) {
  23          return true;
  24      }
  25  
  26      return preg_match('@\.(php[345]?|[psj]html?|aspx?|cgi|jsp|py|pl)$@i', $file);
  27  }
  28  
  29  /**
  30   * Gets a list of media items from our media database
  31   *
  32   * LONG
  33   *
  34   * @access public
  35   * @param   int     The offset to start fetching media files
  36   * @param   int     How many items to fetch
  37   * @param   int     The number (referenced varaible) of fetched items
  38   * @param   string  The "ORDER BY" sql part when fetching items
  39   * @param   string  Order by DESC or ASC
  40   * @param   string  Only fetch files from a specific directory
  41   * @param   string  Only fetch specific filenames
  42   * @param   string  Only fetch media with specific keyword
  43   * @param   array   An array of restricting filter sets
  44   * @param   boolean Apply strict directory checks, or include subdirectories?
  45   * @return  array   Resultset of images
  46   */
  47  function serendipity_fetchImagesFromDatabase($start=0, $limit=0, &$total, $order = false, $ordermode = false, $directory = '', $filename = '', $keywords = '', $filter = array(), $strict_directory = false) {
  48      global $serendipity;
  49  
  50      $cond = array(
  51          'joinparts' => array(),
  52          'parts'     => array(),
  53      );
  54  
  55      $orderfields = serendipity_getImageFields();
  56      if (empty($order) || !isset($orderfields[$order])) {
  57          $order = 'i.date';
  58      }
  59  
  60      if (!is_array($filter)) {
  61          $filter = array();
  62      }
  63  
  64      if (empty($ordermode) || ($ordermode != 'DESC' && $ordermode != 'ASC')) {
  65          $ordermode = 'DESC';
  66      }
  67  
  68      if ($order == 'name') {
  69          $order = 'realname ' . $ordermode . ', name';
  70      }
  71  
  72      if ($limit != 0) {
  73          $limitsql = serendipity_db_limit_sql(serendipity_db_limit($start, $limit));
  74      }
  75  
  76      if ($strict_directory) {
  77          $cond['parts']['directory'] = " AND i.path = '" . serendipity_db_escape_string($directory) . "'\n";
  78      } elseif (!empty($directory)) {
  79          $cond['parts']['directory'] = " AND i.path LIKE '" . serendipity_db_escape_string($directory) . "%'\n";
  80      }
  81  
  82      if (!empty($filename)) {
  83          $cond['parts']['filename'] = " AND (i.name     like '%" . serendipity_db_escape_string($filename) . "%' OR
  84                    i.realname like '%" . serendipity_db_escape_string($filename) . "%')\n";
  85      }
  86  
  87      if (!is_array($keywords)) {
  88          if (!empty($keywords)) {
  89              $keywords = explode(';', $keywords);
  90          } else {
  91              $keywords = array();
  92          }
  93      }
  94  
  95      if (count($keywords) > 0) {
  96          $cond['parts']['keywords'] = " AND (mk.property IN ('" . serendipity_db_implode("', '", $keywords, 'string') . "'))\n";
  97          $cond['joinparts']['keywords'] = true;
  98      }
  99  
 100      foreach($filter AS $f => $fval) {
 101          if (!isset($orderfields[$f]) || empty($fval)) {
 102              continue;
 103          }
 104  
 105          if (is_array($fval)) {
 106              if (empty($fval['from']) || empty($fval['to'])) {
 107                  continue;
 108              }
 109  
 110              if ($orderfields[$f]['type'] == 'date') {
 111                  $fval['from'] = serendipity_convertToTimestamp(trim($fval['from']));
 112                  $fval['to']   = serendipity_convertToTimestamp(trim($fval['to']));
 113              }
 114  
 115              if (substr($f, 0, 3) === 'bp.') {
 116                  $realf = substr($f, 3);
 117                  $cond['parts']['filter'] .= " AND (bp2.property = '$realf' AND bp2.value >= " . (int)$fval['from'] . " AND bp2.value <= " . (int)$fval['to'] . ")\n";
 118              } else {
 119                  $cond['parts']['filter'] .= " AND ($f >= " . (int)$fval['from'] . " AND $f <= " . (int)$fval['to'] . ")\n";
 120              }
 121          } elseif ($f == 'i.authorid') {
 122              $cond['parts']['filter'] .= " AND (
 123                                      (hp.property = 'authorid' AND hp.value = " . (int)$fval . ")
 124                                      OR
 125                                      (i.authorid = " . (int)$fval . ")
 126                                  )\n";
 127              $cond['joinparts']['hiddenproperties'] = true;
 128          } elseif ($orderfields[$f]['type'] == 'int') {
 129              if (substr($f, 0, 3) === 'bp.') {
 130                  $realf = substr($f, 3);
 131                  $cond['parts']['filter'] .= " AND (bp2.property = '$realf' AND bp2.value = '" . serendipity_db_escape_string(trim($fval)) . "')\n";
 132              } else {
 133                  $cond['parts']['filter'] .= " AND ($f = '" . serendipity_db_escape_string(trim($fval)) . "')\n";
 134              }
 135          } else {
 136              if (substr($f, 0, 3) === 'bp.') {
 137                  $realf = substr($f, 3);
 138                  $cond['parts']['filter'] .= " AND (bp2.property = '$realf' AND bp2.value LIKE '%" . serendipity_db_escape_string(trim($fval)) . "%')\n";
 139              } else {
 140                  $cond['parts']['filter'] .= " AND ($f LIKE '%" . serendipity_db_escape_string(trim($fval)) . "%')\n";
 141              }
 142          }
 143          $cond['joinparts']['filterproperties'] = true;
 144      }
 145  
 146      if (isset($serendipity['authorid']) && !serendipity_checkPermission('adminImagesViewOthers')) {
 147          $cond['parts']['authorid'] .= " AND (i.authorid = 0 OR i.authorid = " . (int)$serendipity['authorid'] . ")\n";
 148      }
 149  
 150      $cond['and']  = 'WHERE 1=1 ' . implode("\n", $cond['parts']);
 151      $cond['args'] = func_get_args();
 152      serendipity_plugin_api::hook_event('fetch_images_sql', $cond);
 153      serendipity_ACL_SQL($cond, false, 'directory');
 154  
 155      if ($cond['joinparts']['keywords']) {
 156          $cond['joins'] .= "\n LEFT OUTER JOIN {$serendipity['dbPrefix']}mediaproperties AS mk
 157                                          ON (mk.mediaid = i.id AND mk.property_group = 'base_keyword')\n";
 158      }
 159  
 160      if (substr($order, 0, 3) === 'bp.') {
 161          $cond['orderproperty'] = substr($order, 3);
 162          $cond['orderkey']   = 'bp.value';
 163          $order              = 'bp.value';
 164          $cond['joinparts']['properties'] = true;
 165      } else {
 166          $cond['orderkey'] = "''";
 167      }
 168  
 169      if ($cond['joinparts']['properties']) {
 170          $cond['joins'] .= "\n LEFT OUTER JOIN {$serendipity['dbPrefix']}mediaproperties AS bp
 171                                          ON (bp.mediaid = i.id AND bp.property_group = 'base_property' AND bp.property = '{$cond['orderproperty']}')\n";
 172      }
 173  
 174      if ($cond['joinparts']['filterproperties']) {
 175          $cond['joins'] .= "\n LEFT OUTER JOIN {$serendipity['dbPrefix']}mediaproperties AS bp2
 176                                          ON (bp2.mediaid = i.id AND bp2.property_group = 'base_property')\n";
 177      }
 178  
 179      if ($cond['joinparts']['hiddenproperties']) {
 180          $cond['joins'] .= "\n LEFT OUTER JOIN {$serendipity['dbPrefix']}mediaproperties AS hp
 181                                          ON (hp.mediaid = i.id AND hp.property_group = 'base_hidden')\n";
 182      }
 183  
 184      if ($serendipity['dbType'] == 'postgres' ||
 185          $serendipity['dbType'] == 'pdo-postgres') {
 186          $cond['group']    = '';
 187          $cond['distinct'] = 'DISTINCT';
 188      } else {
 189          $cond['group']    = 'GROUP BY i.id';
 190          $cond['distinct'] = '';
 191      }
 192  
 193      $basequery = "FROM {$serendipity['dbPrefix']}images AS i
 194         LEFT OUTER JOIN {$serendipity['dbPrefix']}authors AS a
 195                      ON i.authorid = a.authorid
 196                         {$cond['joins']}
 197  
 198                         {$cond['and']}";
 199  
 200      $query = "SELECT {$cond['distinct']} i.id, {$cond[orderkey]} AS orderkey, i.name, i.extension, i.mime, i.size, i.dimensions_width, i.dimensions_height, i.date, i.thumbnail_name, i.authorid, i.path, i.hotlink, i.realname,
 201                       a.realname AS authorname
 202                       $basequery
 203                       {$cond['group']}
 204              ORDER BY $order $ordermode $limitsql";
 205  
 206      $rs = serendipity_db_query($query, false, 'assoc');
 207  
 208      if (!is_array($rs) && $rs !== true && $rs !== 1) {
 209          echo '<div>' . $rs . '</div>';
 210          return array();
 211      } elseif (!is_array($rs)) {
 212          return array();
 213      }
 214  
 215      $total_query = "SELECT count(i.id)
 216                             $basequery
 217                             GROUP BY i.id";
 218      $total_rs = serendipity_db_query($total_query, false, 'num');
 219      if (is_array($total_rs)) {
 220          $total = count($total_rs);
 221      }
 222  
 223      return $rs;
 224  }
 225  
 226  /**
 227   * Fetch a specific media item from the mediadatabase
 228   *
 229   * @access public
 230   * @param   int     The ID of an media item
 231   * @return  array   The media info data
 232   */
 233  function serendipity_fetchImageFromDatabase($id, $mode = 'read') {
 234      global $serendipity;
 235  
 236      if (is_array($id)) {
 237          $cond = array(
 238              'and' => "WHERE i.id IN (" . serendipity_db_implode(',', $id) . ")"
 239          );
 240          $single   = false;
 241          $assocKey = 'id';
 242          $assocVal = false;
 243      } else {
 244          $cond = array(
 245              'and' => "WHERE i.id = " . (int)$id
 246          );
 247          $single   = true;
 248          $assocKey = false;
 249          $assocVal = false;
 250      }
 251  
 252      if ($serendipity['dbType'] == 'postgres' ||
 253          $serendipity['dbType'] == 'pdo-postgres') {
 254          $cond['group']    = '';
 255          $cond['distinct'] = 'DISTINCT';
 256      } else {
 257          $cond['group']    = 'GROUP BY i.id';
 258          $cond['distinct'] = '';
 259      }
 260  
 261      if ($mode != 'discard') {
 262          serendipity_ACL_SQL($cond, false, 'directory', $mode);
 263      }
 264  
 265      $rs = serendipity_db_query("SELECT {$cond['distinct']} i.id, i.name, i.extension, i.mime, i.size, i.dimensions_width, i.dimensions_height, i.date, i.thumbnail_name, i.authorid, i.path, i.hotlink, i.realname
 266                                    FROM {$serendipity['dbPrefix']}images AS i
 267                                         {$cond['joins']}
 268                                         {$cond['and']}
 269                                         {$cond['group']}", $single, 'assoc', false, $assocKey, $assocVal);
 270      return $rs;
 271  }
 272  
 273  /**
 274   * Update a media item
 275   *
 276   * @access public
 277   * @param   array       An array of columns to update
 278   * @param   int         The ID of an media item to update
 279   * @return  boolean
 280   */
 281  function serendipity_updateImageInDatabase($updates, $id) {
 282      global $serendipity;
 283  
 284      $admin = '';
 285      if (!serendipity_checkPermission('adminImagesAdd')) {
 286          $admin = ' AND (authorid = ' . $serendipity['authorid'] . ' OR authorid = 0)';
 287      }
 288  
 289      $i=0;
 290      if (sizeof($updates) > 0) {
 291          foreach ($updates as $k => $v) {
 292              $q[] = $k ." = '" . serendipity_db_escape_string($v) . "'";
 293          }
 294          serendipity_db_query("UPDATE {$serendipity['dbPrefix']}images SET ". implode($q, ',') ." WHERE id = " . (int)$id . " $admin");
 295          $i++;
 296      }
 297      return $i;
 298  }
 299  
 300  /**
 301   * Delete a media item
 302   *
 303   * @access public
 304   * @param   int     The ID of a media item to delete
 305   * @return
 306   */
 307  function serendipity_deleteImage($id) {
 308      global $serendipity;
 309      $dThumb = array();
 310  
 311      $file   = serendipity_fetchImageFromDatabase($id);
 312  
 313      if (!is_array($file)) {
 314          printf(FILE_NOT_FOUND . '<br />', $id);
 315          return false;
 316      }
 317  
 318      $dFile  = $file['path'] . $file['name'] . '.' . $file['extension'];
 319  
 320      $dThumb = array(array(
 321          'fthumb' => $file['thumbnail_name']
 322      ));
 323  
 324      if (!serendipity_checkPermission('adminImagesDelete')) {
 325          return;
 326      }
 327  
 328      if (!serendipity_checkPermission('adminImagesMaintainOthers') && $file['authorid'] != '0' && $file['authorid'] != $serendipity['authorid']) {
 329          // A non-admin user may not delete private files from other users.
 330          return;
 331      }
 332  
 333      if (!$file['hotlink']) {
 334          if (file_exists($serendipity['serendipityPath'] . $serendipity['uploadPath'] . $dFile)) {
 335              if (@unlink($serendipity['serendipityPath'] . $serendipity['uploadPath'] . $dFile)) {
 336                  printf(DELETE_FILE . '<br />', $dFile);
 337              } else {
 338                  printf(DELETE_FILE_FAIL . '<br />', $dFile);
 339              }
 340  
 341              serendipity_plugin_api::hook_event('backend_media_delete', $dThumb);
 342              foreach($dThumb as $thumb) {
 343                  $dfnThumb = $file['path'] . $file['name'] . (!empty($thumb['fthumb']) ? '.' . $thumb['fthumb'] : '') . '.' . $file['extension'];
 344                  $dfThumb  = $serendipity['serendipityPath'] . $serendipity['uploadPath'] . $dfnThumb;
 345  
 346                  if (@unlink($dfThumb)) {
 347                      printf(DELETE_THUMBNAIL . '<br />', $dfnThumb);
 348                  }
 349              }
 350          } else {
 351              printf(FILE_NOT_FOUND . '<br />', $dFile);
 352          }
 353      } else {
 354          printf(DELETE_HOTLINK_FILE . '<br />', $file['name']);
 355      }
 356  
 357      serendipity_db_query("DELETE FROM {$serendipity['dbPrefix']}images WHERE id = ". (int)$id);
 358      serendipity_db_query("DELETE FROM {$serendipity['dbPrefix']}mediaproperties WHERE mediaid = ". (int)$id);
 359  }
 360  
 361  /**
 362   * Open a directory and fetch all existing media items
 363   *
 364   * @access public
 365   * @param   boolean     deprecated
 366   * @param   int         deprecated
 367   * @param   int         deprecated
 368   * @param   array       Array list of found items
 369   * @param   string      sub-directory to investigate [recursive use]
 370   * @return  array       List of media items
 371   */
 372  function serendipity_fetchImages($group = false, $start = 0, $end = 20, $images = '', $odir = '') {
 373      global $serendipity;
 374  
 375      // Open directory
 376      $basedir = $serendipity['serendipityPath'] . $serendipity['uploadPath'];
 377      $images = array();
 378      if ($dir = @opendir($basedir . $odir)) {
 379          $aTempArray = array();
 380          while (($file = @readdir($dir)) !== false) {
 381              if ($file == '.svn' || $file == 'CVS' || $file == '.' || $file == '..') {
 382                  continue;
 383              }
 384              array_push($aTempArray, $file);
 385          }
 386          @closedir($dir);
 387          sort($aTempArray);
 388          foreach($aTempArray as $f) {
 389              if (strpos($f, $serendipity['thumbSuffix']) !== false) {
 390                  // This is a s9y thumbnail, skip it.
 391                  continue;
 392              }
 393  
 394              $cdir = ($odir != '' ? $odir . '/' : '');
 395              if (is_dir($basedir . $odir . '/' . $f)) {
 396                  $temp = serendipity_fetchImages($group, $start, $end, $images, $cdir . $f);
 397                  foreach($temp AS $tkey => $tval) {
 398                      array_push($images, $tval);
 399                  }
 400              } else {
 401                  array_push($images, $cdir . $f);
 402              }
 403          }
 404      }
 405      natsort($images);
 406  
 407      /* BC */
 408      $serendipity['imageList'] = $images;
 409      return $images;
 410  }
 411  
 412  /**
 413   * Inserts a hotlinked media file
 414   *
 415   * hotlinks are files that are only linked in your database, and not really stored on your server
 416   *
 417   * @access public
 418   * @param   string      The filename to hotlink
 419   * @param   string      The URL to hotlink with
 420   * @param   int         The owner of the hotlinked media item
 421   * @param   int         The timestamp of insertion (unix second)
 422   * @param   string      A temporary filename for fetching the file to investigate it
 423   * @return  int         The ID of the inserted media item
 424   */
 425  function serendipity_insertHotlinkedImageInDatabase($filename, $url, $authorid = 0, $time = NULL, $tempfile = NULL) {
 426      global $serendipity;
 427  
 428      if (is_null($time)) {
 429          $time = time();
 430      }
 431  
 432      list($filebase, $extension) = serendipity_parseFileName($filename);
 433  
 434      if ($tempfile && file_exists($tempfile)) {
 435          $filesize = @filesize($tempfile);
 436          $fdim     = @serendipity_getimagesize($tempfile, '', $extension);
 437          $width    = $fdim[0];
 438          $height   = $fdim[1];
 439          $mime     = $fdim['mime'];
 440          @unlink($tempfile);
 441      }
 442  
 443      $query = sprintf(
 444        "INSERT INTO {$serendipity['dbPrefix']}images (
 445                      name,
 446                      date,
 447                      authorid,
 448                      extension,
 449                      mime,
 450                      size,
 451                      dimensions_width,
 452                      dimensions_height,
 453                      path,
 454                      hotlink,
 455                      realname
 456                     ) VALUES (
 457                      '%s',
 458                      %s,
 459                      %s,
 460                      '%s',
 461                      '%s',
 462                      %s,
 463                      %s,
 464                      %s,
 465                      '%s',
 466                      1,
 467                      '%s'
 468                     )",
 469        serendipity_db_escape_string($filebase),
 470        (int)$time,
 471        (int)$authorid,
 472        serendipity_db_escape_string($extension),
 473        serendipity_db_escape_string($mime),
 474        (int)$filesize,
 475        (int)$width,
 476        (int)$height,
 477        serendipity_db_escape_string($url),
 478        serendipity_db_escape_string($filename)
 479      );
 480  
 481      $sql = serendipity_db_query($query);
 482      if (is_string($sql)) {
 483          echo $query . '<br />';
 484          echo $sql . '<br />';
 485      }
 486  
 487      $image_id = serendipity_db_insert_id('images', 'id');
 488      if ($image_id > 0) {
 489          return $image_id;
 490      }
 491  
 492      return 0;
 493  }
 494  
 495  /**
 496   * Insert a media item in the database
 497   *
 498   * @access public
 499   * @param   string      The filename of the media item
 500   * @param   string      The path to the media item
 501   * @param   int         The owner author of the item
 502   * @param   int         The timestamp of when the media item was inserted
 503   * @return  int         The new media ID
 504   */
 505  function serendipity_insertImageInDatabase($filename, $directory, $authorid = 0, $time = NULL, $realname = NULL) {
 506      global $serendipity;
 507  
 508      if (is_null($time)) {
 509          $time = time();
 510      }
 511  
 512      if (is_null($realname)) {
 513          $realname = $filename;
 514      }
 515  
 516      $filepath = $serendipity['serendipityPath'] . $serendipity['uploadPath'] . $directory . $filename;
 517      $filesize = @filesize($filepath);
 518  
 519      list($filebase, $extension) = serendipity_parseFileName($filename);
 520  
 521      $thumbpath = $serendipity['serendipityPath'] . $serendipity['uploadPath'] . $directory . $filebase . '.'. $serendipity['thumbSuffix'] . '.'. $extension;
 522      $thumbnail = (file_exists($thumbpath) ? $serendipity['thumbSuffix'] : '');
 523  
 524      $fdim = @serendipity_getimagesize($filepath, '', $extension);
 525      $width = $fdim[0];
 526      $height = $fdim[1];
 527      $mime = $fdim['mime'];
 528  
 529  
 530      $query = sprintf(
 531        "INSERT INTO {$serendipity['dbPrefix']}images (
 532                      name,
 533                      extension,
 534                      mime,
 535                      size,
 536                      dimensions_width,
 537                      dimensions_height,
 538                      thumbnail_name,
 539                      date,
 540                      authorid,
 541                      path,
 542                      realname
 543                     ) VALUES (
 544                      '%s',
 545                      '%s',
 546                      '%s',
 547                      %s,
 548                      %s,
 549                      %s,
 550                      '%s',
 551                      %s,
 552                      %s,
 553                      '%s',
 554                      '%s'
 555                     )",
 556        serendipity_db_escape_string($filebase),
 557        serendipity_db_escape_string($extension),
 558        serendipity_db_escape_string($mime),
 559        (int)$filesize,
 560        (int)$width,
 561        (int)$height,
 562        serendipity_db_escape_string($thumbnail),
 563        (int)$time,
 564        (int)$authorid,
 565        serendipity_db_escape_string($directory),
 566        serendipity_db_escape_string($realname)
 567      );
 568  
 569      $sql = serendipity_db_query($query);
 570      if (is_string($sql)) {
 571          echo $query . '<br />';
 572          echo $sql . '<br />';
 573      }
 574  
 575      $image_id = serendipity_db_insert_id('images', 'id');
 576      if ($image_id > 0) {
 577          return $image_id;
 578      }
 579  
 580      return 0;
 581  }
 582  
 583  
 584  /**
 585   * Create a thumbnail for an image
 586   *
 587   * LONG
 588   *
 589   * @access public
 590   * @param   string      The input image filename
 591   * @param   string      The directory to the image file
 592   * @param   string      The target size of the thumbnail (2-dimensional array width,height)
 593   * @param   string      Name of the thumbnail
 594   * @param   bool        Store thumbnail in temporary place?
 595   * @param   bool        Force enlarging of small images?
 596   * @return  array       The result size of the thumbnail
 597   */
 598  function serendipity_makeThumbnail($file, $directory = '', $size = false, $thumbname = false, $is_temporary = false, $force_resize = false) {
 599      global $serendipity;
 600  
 601      if ($size === false) {
 602          $size = $serendipity['thumbSize'];
 603      }
 604  
 605      if ($thumbname === false) {
 606          $thumbname = $serendipity['thumbSuffix'];
 607      }
 608  
 609      $t       = serendipity_parseFileName($file);
 610      $f       = $t[0];
 611      $suf     = $t[1];
 612  
 613  
 614      $infile  = $serendipity['serendipityPath'] . $serendipity['uploadPath'] . $directory . $file;
 615  #    echo 'From: ' . $infile . '<br />';
 616      if ($is_temporary) {
 617          $temppath = dirname($thumbname);
 618          if (!is_dir($temppath)) {
 619              @mkdir($temppath);
 620          }
 621          $outfile = $thumbname;
 622      } else {
 623          $outfile = $serendipity['serendipityPath'] . $serendipity['uploadPath'] . $directory . $f . '.' . $thumbname . '.' . $suf;
 624      }
 625      $serendipity['last_outfile'] = $outfile;
 626  #    echo 'To: ' . $outfile . '<br />';
 627  
 628      $fdim    = @serendipity_getimagesize($infile, '', $suf);
 629      if (isset($fdim['noimage'])) {
 630          $r = array(0, 0);
 631      } else {
 632          if ($serendipity['magick'] !== true) {
 633              if (is_array($size)) {
 634                  $r = serendipity_resize_image_gd($infile, $outfile, $size['width'], $size['height']);
 635              } else {
 636                  $r = serendipity_resize_image_gd($infile, $outfile, $size);
 637              }
 638          } else {
 639              if (is_array($size)) {
 640                  $r = $size;
 641              } else {
 642                  $r = array('width' => $size, 'height' => $size);
 643              }
 644              $newSize = $r['width'] . 'x' . $r['height'];
 645              if ($fdim['mime'] == 'application/pdf') {
 646                  $cmd     = escapeshellcmd($serendipity['convert']) . ' -antialias -flatten -scale '. serendipity_escapeshellarg($newSize) .' '. serendipity_escapeshellarg($infile) .' '. serendipity_escapeshellarg($outfile . '.png');
 647              } else {
 648                  if (!$force_resize && serendipity_ini_bool(ini_get('safe_mode')) === false) {
 649                      $newSize .= '>'; // Tell imagemagick to not enlarge small images, only works if safe_mode is off (safe_mode turns > in to \>)
 650                  }
 651                  $cmd     = escapeshellcmd($serendipity['convert']) . ' -antialias -resize '. serendipity_escapeshellarg($newSize) .' '. serendipity_escapeshellarg($infile) .' '. serendipity_escapeshellarg($outfile);
 652              }
 653              exec($cmd, $output, $result);
 654              if ($result != 0) {
 655                  echo '<div class="serendipityAdminMsgError"><img style="width: 22px; height: 22px; border: 0px; padding-right: 4px; vertical-align: middle" src="' . serendipity_getTemplateFile('admin/img/admin_msg_error.png') . '" alt="" />' . sprintf(IMAGICK_EXEC_ERROR, $cmd, $output[0], $result) .'</div>';
 656                  $r = false; // return failure
 657              } else {
 658                 touch($outfile);
 659              }
 660              unset($output, $result);
 661          }
 662      }
 663  
 664      return $r;
 665  }
 666  
 667  /**
 668   * Scale an image
 669   *
 670   * LONG
 671   *
 672   * @access public
 673   * @param   int     The ID of an image
 674   * @param   int     The target width
 675   * @param   int     The target height
 676   * @return true
 677   */
 678  function serendipity_scaleImg($id, $width, $height) {
 679      global $serendipity;
 680  
 681      $file = serendipity_fetchImageFromDatabase($id);
 682      if (!is_array($file)) {
 683          return false;
 684      }
 685  
 686      $admin = '';
 687      if (!serendipity_checkPermission('adminImagesMaintainOthers') && $file['authorid'] != '0' && $file['authorid'] != $serendipity['authorid']) {
 688          return;
 689      }
 690  
 691      $infile = $outfile = $serendipity['serendipityPath'] . $serendipity['uploadPath'] . $file['path'] . $file['name'] . '.' . $file['extension'];
 692  
 693      if ($serendipity['magick'] !== true) {
 694          serendipity_resize_image_gd($infile, $outfile, $width, $height);
 695      } else {
 696          $cmd = escapeshellcmd($serendipity['convert']) . ' -scale ' .  serendipity_escapeshellarg($width . 'x' . $height) . ' ' . serendipity_escapeshellarg($infile) . ' ' . serendipity_escapeshellarg($outfile);
 697          exec($cmd, $output, $result);
 698          if ( $result != 0 ) {
 699              echo '<div class="serendipityAdminMsgError"><img style="width: 22px; height: 22px; border: 0px; padding-right: 4px; vertical-align: middle" src="' . serendipity_getTemplateFile('admin/img/admin_msg_error.png') . '" alt="" />' . sprintf(IMAGICK_EXEC_ERROR, $cmd, $output[0], $result) .'</div>';
 700          }
 701          unset($output, $result);
 702      }
 703  
 704      serendipity_updateImageInDatabase(array('dimensions_width' => $width, 'dimensions_height' => $height, 'size' => @filesize($outfile)), $id);
 705      return true;
 706  }
 707  
 708  /**
 709   * Rotate an image
 710   *
 711   * LONG
 712   *
 713   * @access public
 714   * @param   int     The ID of an image
 715   * @param   int     Number of degrees to rotate
 716   * @return boolean
 717   */
 718  function serendipity_rotateImg($id, $degrees) {
 719      global $serendipity;
 720  
 721      $file = serendipity_fetchImageFromDatabase($id);
 722      if (!is_array($file)) {
 723          return false;
 724      }
 725  
 726      $admin = '';
 727      if (!serendipity_checkPermission('adminImagesMaintainOthers') && $file['authorid'] != '0' && $file['authorid'] != $serendipity['authorid']) {
 728          // A non-admin user may not delete private files from other users.
 729          return false;
 730      }
 731  
 732      $infile = $outfile = $serendipity['serendipityPath'] . $serendipity['uploadPath'] . $file['path'] . $file['name'] . '.' . $file['extension'];
 733      $infileThumb = $outfileThumb = $serendipity['serendipityPath'] . $serendipity['uploadPath'] . $file['path'] . $file['name'] . (!empty($file['thumbnail_name']) ? '.' . $file['thumbnail_name'] : '') . '.' . $file['extension'];
 734  
 735      if ($serendipity['magick'] !== true) {
 736          serendipity_rotate_image_gd($infile, $outfile, $degrees);
 737          serendipity_rotate_image_gd($infileThumb, $outfileThumb, $degrees);
 738      } else {
 739          /* Why can't we just all agree on the rotation direction? */
 740          $degrees = (360 - $degrees);
 741  
 742          /* Resize main image */
 743          $cmd = escapeshellcmd($serendipity['convert']) . ' -rotate ' . serendipity_escapeshellarg($degrees) . ' ' . serendipity_escapeshellarg($infile) . ' ' . serendipity_escapeshellarg($outfile);
 744          exec($cmd, $output, $result);
 745          if ( $result != 0 ) {
 746              echo '<div class="serendipityAdminMsgError"><img style="width: 22px; height: 22px; border: 0px; padding-right: 4px; vertical-align: middle" src="' . serendipity_getTemplateFile('admin/img/admin_msg_error.png') . '" alt="" />' . sprintf(IMAGICK_EXEC_ERROR, $cmd, $output[0], $result) .'</div>';
 747          }
 748          unset($output, $result);
 749  
 750          /* Resize thumbnail */
 751          $cmd = escapeshellcmd($serendipity['convert']) . ' -rotate ' . serendipity_escapeshellarg($degrees) . ' ' . serendipity_escapeshellarg($infileThumb) . ' ' . serendipity_escapeshellarg($outfileThumb);
 752          exec($cmd, $output, $result);
 753          if ( $result != 0 ) {
 754              echo '<div class="serendipityAdminMsgError"><img style="width: 22px; height: 22px; border: 0px; padding-right: 4px; vertical-align: middle" src="' . serendipity_getTemplateFile('admin/img/admin_msg_error.png') . '" alt="" />'. sprintf(IMAGICK_EXEC_ERROR, $cmd, $output[0], $result) .'</div>';
 755          }
 756          unset($output, $result);
 757  
 758      }
 759  
 760      $fdim = @getimagesize($outfile);
 761  
 762      serendipity_updateImageInDatabase(array('dimensions_width' => $fdim[0], 'dimensions_height' => $fdim[1]), $id);
 763  
 764      return true;
 765  }
 766  
 767  
 768  /**
 769   * Creates thumbnails for all images in the upload dir
 770   *
 771   * @access public
 772   * @return  int Number of created thumbnails
 773   */
 774  function serendipity_generateThumbs() {
 775      global $serendipity;
 776  
 777      $i=0;
 778      $serendipity['imageList'] = serendipity_fetchImagesFromDatabase(0, 0, $total);
 779  
 780      foreach ($serendipity['imageList'] as $k => $file) {
 781          $is_image = serendipity_isImage($file);
 782  
 783          if ($is_image && !$file['hotlink']) {
 784              $update   = false;
 785              $filename = $file['path'] . $file['name'] .'.'. $file['extension'];
 786              $ffull    = $serendipity['serendipityPath'] . $serendipity['uploadPath'] . $filename;
 787  
 788              if (!file_exists($ffull)) {
 789                  serendipity_deleteImage($file['id']);
 790                  continue;
 791              }
 792  
 793              if (empty($file['thumbnail_name'])) {
 794                  $file['thumbnail_name'] = $serendipity['thumbSuffix'];
 795              }
 796  
 797              $oldThumb = $serendipity['serendipityPath'] . $serendipity['uploadPath'] . $file['path'] . $file['name'] . '.' . $file['thumbnail_name'] . '.' . $file['extension'];
 798              $newThumb = $serendipity['serendipityPath'] . $serendipity['uploadPath'] . $file['path'] . $file['name'] . '.' . $serendipity['thumbSuffix'] . '.' . $file['extension'];
 799              $fdim = @getimagesize($ffull);
 800  
 801              if (!file_exists($oldThumb) && !file_exists($newThumb) && ($fdim[0] > $serendipity['thumbSize'] || $fdim[1] > $serendipity['thumbSize'])) {
 802                  $returnsize = serendipity_makeThumbnail($file['name'] . '.' . $file['extension'], $file['path']);
 803                  if ($returnsize !== false ) {
 804                      printf(RESIZE_BLAHBLAH, $filename . ': ' . $returnsize[0] . 'x' . $returnsize[1]);
 805                      if (!file_exists($newThumb)) {
 806                          printf('<div class="serendipityAdminMsgError"><img style="width: 22px; height: 22px; border: 0px; padding-right: 4px; vertical-align: middle" src="' . serendipity_getTemplateFile('admin/img/admin_msg_error.png') . '" alt="" />' . THUMBNAIL_FAILED_COPY . '</div><br />', $filename);
 807                      } else {
 808                          $update = true;
 809                      }
 810                  }
 811              } elseif (!file_exists($oldThumb) && !file_exists($newThumb) && $fdim[0] <= $serendipity['thumbSize'] && $fdim[1] <= $serendipity['thumbSize']) {
 812                  $res = @copy($ffull, $newThumb);
 813                  if (@$res === true) {
 814                      printf(THUMBNAIL_USING_OWN . '<br />', $filename);
 815                      $update = true;
 816                  } else {
 817                      printf('<div class="serendipityAdminMsgError"><img style="width: 22px; height: 22px; border: 0px; padding-right: 4px; vertical-align: middle" src="' . serendipity_getTemplateFile('admin/img/admin_msg_error.png') . '" alt="" />' . THUMBNAIL_FAILED_COPY . '</div><br />', $filename);
 818                  }
 819              }
 820  
 821              if ($update) {
 822                  $i++;
 823                  $updates = array('thumbnail_name' => $serendipity['thumbSuffix']);
 824                  serendipity_updateImageInDatabase($updates, $file['id']);
 825              }
 826          } else {
 827              // Currently, non-image files have no thumbnail.
 828          }
 829      }
 830  
 831      return $i;
 832  }
 833  
 834  /**
 835   * Guess the MIME type of a file
 836   *
 837   * @access public
 838   * @param   string  Filename extension
 839   * @return  string  Mimetype
 840   */
 841  function serendipity_guessMime($extension) {
 842      $mime = '';
 843      switch (strtolower($extension)) {
 844          case 'jpg':
 845          case 'jpeg':
 846              $mime = 'image/jpeg';
 847          break;
 848  
 849          case 'aiff':
 850          case 'aif':
 851              $mime = 'audio/x-aiff';
 852              break;
 853  
 854          case 'gif':
 855              $mime = 'image/gif';
 856          break;
 857  
 858          case 'png':
 859              $mime = 'image/png';
 860          break;
 861  
 862          case 'pdf':
 863              $mime = 'application/pdf';
 864              break;
 865  
 866          case 'doc':
 867              $mime = 'application/msword';
 868              break;
 869  
 870          case 'rtf':
 871              $mime = 'application/rtf';
 872              break;
 873  
 874          case 'wav':
 875          case 'wave':
 876              $mime = 'audio/x-wav';
 877              break;
 878  
 879          case 'mp2':
 880          case 'mpg':
 881          case 'mpeg':
 882              $mime = 'video/x-mpeg';
 883              break;
 884  
 885          case 'avi':
 886              $mime = 'video/x-msvideo';
 887              break;
 888  
 889          case 'mp3':
 890              $mime = 'audio/x-mpeg3';
 891              break;
 892  
 893          case 'xlm':
 894          case 'xlb':
 895          case 'xll':
 896          case 'xla':
 897          case 'xlw':
 898          case 'xlc':
 899          case 'xls':
 900          case 'xlt':
 901              $mime = 'application/vnd.ms-excel';
 902              break;
 903  
 904          case 'ppt':
 905          case 'pps':
 906              $mime = 'application/vnd.ms-powerpoint';
 907              break;
 908  
 909          case 'html':
 910          case 'htm':
 911              $mime = 'text/html';
 912              break;
 913  
 914          case 'xsl':
 915          case 'xslt':
 916          case 'xml':
 917          case 'wsdl':
 918          case 'xsd':
 919              $mime = 'text/xml';
 920              break;
 921  
 922          case 'zip':
 923              $mime = 'application/zip';
 924              break;
 925  
 926          case 'tar':
 927              $mime = 'application/x-tar';
 928              break;
 929  
 930          case 'tgz':
 931          case 'gz':
 932              $mime = 'application/x-gzip';
 933              break;
 934  
 935          case 'swf':
 936              $mime = 'application/x-shockwave-flash';
 937              break;
 938  
 939          case 'rm':
 940          case 'ra':
 941          case 'ram':
 942              $mime = 'application/vnd.rn-realaudio';
 943              break;
 944  
 945          case 'exe':
 946              $mime = 'application/octet-stream';
 947              break;
 948  
 949          case 'mov':
 950          case 'qt':
 951              $mime = 'video/x-quicktime';
 952              break;
 953  
 954          case 'midi':
 955          case 'mid':
 956              $mime = 'audio/x-midi';
 957              break;
 958  
 959          case 'txt':
 960              $mime = 'text/plain';
 961              break;
 962  
 963          case 'qcp':
 964              $mime = 'audio/vnd.qcelp';
 965              break;
 966  
 967          case 'emf':
 968              $mime = 'image/x-emf';
 969              break;
 970  
 971          case 'wmf':
 972              $mime = 'image/x-wmf';
 973              break;
 974  
 975          case 'snd':
 976              $mime = 'audio/basic';
 977              break;
 978  
 979          case 'pmd':
 980              $mime = 'application/x-pmd';
 981              break;
 982  
 983          case 'wbmp':
 984              $mime = 'image/vnd.wap.wbmp';
 985              break;
 986  
 987          case 'gcd':
 988              $mime = 'text/x-pcs-gcd';
 989              break;
 990  
 991          case 'mms':
 992              $mime = 'application/vnd.wap.mms-message';
 993              break;
 994  
 995          case 'ogg':
 996          case 'ogm':
 997              $mime = 'application/ogg';
 998              break;
 999  
1000          case 'rv':
1001              $mime = 'video/vnd.rn-realvideo';
1002              break;
1003  
1004          case 'wmv':
1005              $mime = 'video/x-ms-wmv';
1006              break;
1007  
1008          case 'wma':
1009              $mime = 'audio/x-ms-wma';
1010              break;
1011  
1012          case 'qcp':
1013              $mime = 'audio/vnd.qcelp';
1014              break;
1015  
1016          case 'jad':
1017              $mime = 'text/vnd.sun.j2me.app-descriptor';
1018              break;
1019  
1020          case '3g2':
1021          case '3gp':
1022              $mime = 'video/3gpp';
1023              break;
1024  
1025          case 'jar':
1026              $mime = 'application/java-archive';
1027              break;
1028  
1029          case 'ico':
1030              $mime = 'image/x-icon';
1031              break;
1032  
1033          default:
1034              $mime = 'application/octet-stream';
1035              break;
1036      }
1037  
1038      return $mime;
1039  }
1040  
1041  /**
1042   * Check all existing thumbnails if they are the right size, insert missing thumbnails
1043   *
1044   * LONG
1045   *
1046   * @access public
1047   * @return  int     Number of updated thumbnails
1048   */
1049  function serendipity_syncThumbs() {
1050      global $serendipity;
1051  
1052      $i=0;
1053      $files = serendipity_fetchImages();
1054  
1055      $fcount = count($files);
1056      for ($x = 0; $x < $fcount; $x++) {
1057          $update = array();
1058          $f      = serendipity_parseFileName($files[$x]);
1059          if (empty($f[1]) || $f[1] == $files[$x]) {
1060              // No extension means bad file most probably. Skip it.
1061              printf(SKIPPING_FILE_EXTENSION . '<br />', $files[$x]);
1062              continue;
1063          }
1064  
1065          $ffull   = $serendipity['serendipityPath'] . $serendipity['uploadPath'] . $files[$x];
1066          $fthumb  = $serendipity['serendipityPath'] . $serendipity['uploadPath'] . $f[0] . '.' . $serendipity['thumbSuffix'] . '.' . $f[1];
1067          $fbase   = basename($f[0]);
1068          $fdir    = dirname($f[0]) . '/';
1069          if ($fdir == './') {
1070              $fdir = '';
1071          }
1072  
1073          if (!is_readable($ffull) || filesize($ffull) == 0) {
1074              printf(SKIPPING_FILE_UNREADABLE . '<br />', $files[$x]);
1075              continue;
1076          }
1077  
1078          $ft_mime = serendipity_guessMime($f[1]);
1079          $fdim    = serendipity_getimagesize($ffull, $ft_mime);
1080  
1081          $cond = array(
1082              'and' => "WHERE name = '" . serendipity_db_escape_string($fbase) . "'
1083                              " . ($fdir != '' ? "AND path = '" . serendipity_db_escape_string($fdir) . "'" : '') . "
1084                              AND mime = '" . serendipity_db_escape_string($fdim['mime']) . "'"
1085          );
1086          serendipity_ACL_SQL($cond, false, 'directory');
1087  
1088          $rs = serendipity_db_query("SELECT *
1089                                        FROM {$serendipity['dbPrefix']}images AS i
1090                                             {$cond['joins']}
1091  
1092                                             {$cond['and']}", true, 'assoc');
1093          if (is_array($rs)) {
1094              $update    = array();
1095              $checkfile = $serendipity['serendipityPath'] . $serendipity['uploadPath'] . $rs['path'] . $rs['name'] . '.' . $rs['thumbnail_name'] . '.' . $rs['extension'];
1096              if (isset($fdim[0]) && $rs['dimensions_width'] != $fdim[0]) {
1097                  $update['dimensions_width'] = $fdim[0];
1098              }
1099  
1100              if (isset($fdim[1]) && $rs['dimensions_height'] != $fdim[1]) {
1101                  $update['dimensions_height'] = $fdim[1];
1102              }
1103  
1104              if ($rs['size'] != filesize($ffull)) {
1105                  $update['size'] = filesize($ffull);
1106              }
1107  
1108              if (!file_exists($checkfile) && file_exists($fthumb)) {
1109                  $update['thumbnail_name'] = $serendipity['thumbSuffix'];
1110              }
1111  
1112              /* Do the database update, if needed */
1113              if (sizeof($update) != 0) {
1114                  printf(FOUND_FILE . '<br />', $files[$x]);
1115                  serendipity_updateImageInDatabase($update, $rs['id']);
1116                  $i++;
1117              }
1118          } else {
1119              printf(FOUND_FILE . '<br />', $files[$x]);
1120              serendipity_insertImageInDatabase($fbase . '.' . $f[1], $fdir, 0, filemtime($ffull));
1121              $i++;
1122          }
1123      }
1124      return $i;
1125  }
1126  
1127  /**
1128   * Wrapper for GDLib functions
1129   *
1130   * @access public
1131   * @param   string      Filename to operate on
1132   * @return string       Functionname to execute
1133   */
1134  function serendipity_functions_gd($infilename) {
1135      if (!function_exists('imagecopyresampled')) {
1136          return false;
1137      }
1138  
1139      $func = array();
1140      $inf  = pathinfo(strtolower($infilename));
1141      switch ($inf['extension']) {
1142      case 'gif':
1143          $func['load'] = 'imagecreatefromgif';
1144          $func['save'] = 'imagegif';
1145          $func['qual'] = 100;
1146          break;
1147  
1148      case 'jpeg':
1149      case 'jpg':
1150      case 'jfif':
1151          $func['load'] = 'imagecreatefromjpeg';
1152          $func['save'] = 'imagejpeg';
1153          $func['qual'] = 100;
1154          break;
1155  
1156      case 'png':
1157          $func['load'] = 'imagecreatefrompng';
1158          $func['save'] = 'imagepng';
1159          $func['qual'] = 9;
1160          break;
1161  
1162      default:
1163          return false;
1164      }
1165  
1166      /* If our loader does not exist, we are doomed */
1167      if (!function_exists($func['load'])) {
1168          return false;
1169      }
1170  
1171      /* If the save function does not exist (i.e. read-only GIF), we want to output it as PNG */
1172      if (!function_exists($func['save'])) {
1173          if (function_exists('imagepng')) {
1174              $func['save'] = 'imagepng';
1175          } else {
1176              return false;
1177          }
1178      }
1179  
1180      return $func;
1181  }
1182  
1183  /**
1184   * Rotate an image (GDlib)
1185   *
1186   * @access public
1187   * @param   string      Source Filename to rotate
1188   * @param   string      Target file
1189   * @param   int         Degress to rotate
1190   * @return  array       New width/height of the image
1191   */
1192  function serendipity_rotate_image_gd($infilename, $outfilename, $degrees)
1193  {
1194      $func = serendipity_functions_gd($infilename);
1195      if (!is_array($func)) {
1196          return false;
1197      }
1198  
1199      $in        = $func['load']($infilename);
1200  
1201      $out       = imagerotate($in, $degrees, 0);
1202      $func['save']($out, $outfilename, $func['qual']);
1203  
1204      $newwidth  = imagesx($out);
1205      $newheight = imagesy($out);
1206  
1207      $out       = null;
1208      $in        = null;
1209  
1210      return array($newwidth, $newheight);
1211  }
1212  
1213  
1214  /**
1215   * Resize an image (GDLib)
1216   *
1217   * @access public
1218   * @param   string      Source Filename to resize
1219   * @param   string      Target file
1220   * @param   int         New width
1221   * @return  int         New height (can be autodetected)
1222   * @return  array       New image size
1223   */
1224  function serendipity_resize_image_gd($infilename, $outfilename, $newwidth, $newheight=null)
1225  {
1226      $func = serendipity_functions_gd($infilename);
1227      if (!is_array($func)) {
1228          return false;
1229      }
1230  
1231      $in = $func['load']($infilename);
1232      $width = imagesx($in);
1233      $height = imagesy($in);
1234  
1235      if (is_null($newheight)) {
1236          $newsizes = serendipity_calculate_aspect_size($width, $height, $newwidth);
1237          $newwidth = $newsizes[0];
1238          $newheight = $newsizes[1];
1239      }
1240  
1241      if (is_null($newwidth)) {
1242          $newsizes  = serendipity_calculate_aspect_size($width, $height, null, $newheight);
1243          $newwidth  = $newsizes[0];
1244          $newheight = $newsizes[1];
1245      }
1246  
1247      $out = imagecreatetruecolor($newwidth, $newheight);
1248  
1249      /* Attempt to copy transparency information, this really only works for PNG */
1250      if (function_exists('imagesavealpha')) {
1251          imagealphablending($out, false);
1252          imagesavealpha($out, true);
1253      }
1254  
1255      imagecopyresampled($out, $in, 0, 0, 0, 0, $newwidth, $newheight, $width, $height);
1256      @umask(0000);
1257      touch($outfilename);  // safe_mode requirement
1258      $func['save']($out, $outfilename, $func['qual']);
1259      @chmod($outfilename, 0664);
1260      $out = null;
1261      $in  = null;
1262  
1263      return array($newwidth, $newheight);
1264  }
1265  
1266  /**
1267   * Calculate aspect ratio of an image
1268   *
1269   * @access public
1270   * @param   int     Image width
1271   * @param   int     Image height
1272   * @param   int     Target width
1273   * @return  int     Target height
1274   */
1275  function serendipity_calculate_aspect_size($width, $height, $orig_newwidth, $orig_newheight = null) {
1276  
1277      // calculate aspect ratio
1278      if (!is_null($orig_newheight)) {
1279          $div_width  = $width  / $orig_newheight;
1280          $div_height = $height / $orig_newheight;
1281      } else {
1282          $div_width  = $width  / $orig_newwidth;
1283          $div_height = $height / $orig_newwidth;
1284      }
1285  
1286      if ($div_width <= 1 && $div_height <= 1) {
1287          // do not scale small images where both sides are smaller than the thumbnail dimensions
1288          $newheight = $height;
1289          $newwidth  = $width;
1290      } elseif (is_null($orig_newheight) &&  $div_width >= $div_height) {
1291          // max width - calculate height, keep width as scaling base
1292          $newheight = round($height / $div_width);
1293          // make sure the height is at least 1 pixel for extreme images
1294          $newheight = ($newheight >= 1 ? $newheight : 1);
1295          $newwidth = $orig_newwidth;
1296      } elseif (is_null($orig_newwidth) && $div_width >= $div_height) {
1297          // max width - calculate height, keep width as scaling base
1298          $newwidth = round($width / $div_height);
1299          // make sure the height is at least 1 pixel for extreme images
1300          $newwidth = ($newwidth >= 1 ? $newwidth : 1);
1301          $newheight = $orig_newheight;
1302      } elseif (is_null($orig_newheight)) {
1303          // max height - calculate width, keep height as scaling base
1304          $newheight = $orig_newwidth;
1305          $newwidth  = round($width / $div_height);
1306          // make sure the width is at least 1 pixel for extreme images
1307          $newwidth  = ($newwidth >= 1 ? $newwidth : 1);
1308      } else {
1309          // max height - calculate width, keep height as scaling base
1310          $newwidth = $orig_newheight;
1311          $newheight  = round($height / $div_width);
1312          // make sure the width is at least 1 pixel for extreme images
1313          $newheight = ($newheight >= 1 ? $newheight : 1);
1314      }
1315  
1316      return array($newwidth, $newheight);
1317  }
1318  
1319  /**
1320   * Display the list of images in our database
1321   *
1322   * @access public
1323   * @param   int     The current page number
1324   * @param   string  The HTML linebreak to use after a row of images
1325   * @param   boolean Should the toolbar for editing media files be shown?
1326   * @param   string  The URL to use for pagination
1327   * @param   boolean Show the "upload media item" feature?
1328   * @param   boolean Restrict viewing images to a specific directory
1329   * @param   boolean  If TRUE, will echo Smarty output.
1330   * @return  string   Smarty block name
1331   */
1332  function serendipity_displayImageList($page = 0, $lineBreak = NULL, $manage = false, $url = NULL, $show_upload = false, $limit_path = NULL, $smarty_display = true) {
1333      global $serendipity;
1334      static $debug = false;
1335  
1336      $sortParams        = array('perpage', 'order', 'ordermode');
1337      $importParams      = array('adminModule', 'htmltarget', 'filename_only', 'textarea', 'subpage',  'keywords');
1338      $extraParems       = '';
1339      $filterParams      = array('only_path', 'only_filename');
1340  
1341      foreach($importParams AS $importParam) {
1342          if (isset($serendipity['GET'][$importParam])) {
1343              $extraParems .= 'serendipity[' . $importParam . ']='. $serendipity['GET'][$importParam] .'&amp;';
1344          }
1345      }
1346  
1347      foreach($sortParams AS $sortParam) {
1348          serendipity_restoreVar($serendipity['COOKIE']['sortorder_' . $sortParam], $serendipity['GET']['sortorder'][$sortParam]);
1349          serendipity_JSsetCookie('sortorder_' . $sortParam, $serendipity['GET']['sortorder'][$sortParam]);
1350          $extraParems .= 'serendipity[sortorder]['. $sortParam .']='. $serendipity['GET']['sortorder'][$sortParam] .'&amp;';
1351      }
1352  
1353      foreach($filterParams AS $filterParam) {
1354          serendipity_restoreVar($serendipity['COOKIE'][$filterParam], $serendipity['GET'][$filterParam]);
1355          serendipity_JSsetCookie($filterParam, $serendipity['GET'][$filterParam]);
1356          if (!empty($serendipity['GET'][$filterParam])) {
1357              $extraParems .= 'serendipity[' . $filterParam . ']='. $serendipity['GET'][$filterParam] .'&amp;';
1358          }
1359      }
1360  
1361      $serendipity['GET']['only_path']     = serendipity_uploadSecure($limit_path . $serendipity['GET']['only_path'], true);
1362      $serendipity['GET']['only_filename'] = str_replace(array('*', '?'), array('%', '_'), $serendipity['GET']['only_filename']);
1363  
1364      $perPage = (!empty($serendipity['GET']['sortorder']['perpage']) ? $serendipity['GET']['sortorder']['perpage'] : 8);
1365      while ($perPage % $lineBreak !== 0) {
1366          $perPage++;
1367      }
1368      $start   = ($page-1) * $perPage;
1369  
1370      if ($manage && $limit_path == NULL) {
1371          ## SYNCH START ##
1372          $aExclude = array("CVS" => true, ".svn" => true);
1373          serendipity_plugin_api::hook_event('backend_media_path_exclude_directories', $aExclude);
1374          $paths        = array();
1375          $aFilesOnDisk = array();
1376  
1377          $aResultSet   = serendipity_traversePath(
1378              $serendipity['serendipityPath'] . $serendipity['uploadPath']. $limit_path,
1379              '',
1380              false,
1381              NULL,
1382              1,
1383              NULL,
1384              FALSE,
1385              $aExclude
1386          );
1387          foreach ($aResultSet AS $sKey => $sFile) {
1388                  if ($sFile['directory']) {
1389                      if ($debug) echo "{$sFile['relpath']} is a directory.<br />";
1390                      array_push($paths, $sFile);
1391                  } else {
1392                      if ($debug) echo "{$sFile['relpath']} is a file.<br />";
1393                      // Store the file in our array, remove any ending slashes
1394                      $aFilesOnDisk[$sFile['relpath']] = 1;
1395                  }
1396                  unset($aResultSet[$sKey]);
1397          }
1398  
1399          usort($paths, 'serendipity_sortPath');
1400  
1401          if ($debug) echo "<p>Got files: <pre>" . print_r($aFilesOnDisk, true) . "</pre></p>";
1402          $serendipity['current_image_hash'] = md5(serialize($aFilesOnDisk));
1403  
1404          $nTimeStart = microtime_float();
1405          // MTG 21/01/06: request all images from the database, delete any which don't exist
1406          // on the filesystem, and mark off files from the file list which are already
1407          // in the database
1408  
1409          $nCount = 0;
1410          if ($serendipity['onTheFlySynch'] && serendipity_checkPermission('adminImagesSync') && $serendipity['current_image_hash'] != $serendipity['last_image_hash']) {
1411              $aResultSet = serendipity_db_query("SELECT path, name, extension, thumbnail_name, id
1412                                                  FROM {$serendipity['dbPrefix']}images", false, 'assoc');
1413              if ($debug) echo "<p>Got images: <pre>" . print_r($aResultSet, true) . "</pre></p>";
1414              if (is_array($aResultSet)) {
1415                  foreach ($aResultSet AS $sKey => $sFile) {
1416                      serendipity_plugin_api::hook_event('backend_thumbnail_filename_select', $sFile);
1417                      $sThumbNailFile = '';
1418                      if (isset($sFile['thumbnail_filename'])) {
1419                          $sThumbNailFile = $sFile['thumbnail_filename'];
1420                      } else {
1421                          $sThumbNailFile = $sFile['path'] . $sFile['name'] . '.' . $sFile['thumbnail_name'] . '.' . $sFile['extension'];
1422                      }
1423  
1424                      $sFileName = $sFile['path'] . $sFile['name'] . '.' . $sFile['extension'];
1425                      if ($debug) echo "<p>File name is $sFileName,<br />thumbnail is $sThumbNailFile</p>";
1426                      unset($aResultSet[$sKey]);
1427  
1428                      if (isset($aFilesOnDisk[$sFileName])) {
1429                          unset($aFilesOnDisk[$sFileName]);
1430                      } else {
1431                          if ($debug) "Deleting Image {$sFile['id']}<br />\n";
1432                          serendipity_deleteImage($sFile['id']);
1433                          ++$nCount;
1434                      }
1435                      unset($aFilesOnDisk[$sThumbNailFile]);
1436                  }
1437              }
1438  
1439              if ($nCount > 0){
1440                  if ($debug) echo "<p>Cleaned up ".$nCount." database entries</p>";
1441              }
1442  
1443              serendipity_set_config_var('last_image_hash', $serendipity['current_image_hash'], 0);
1444              $aUnmatchedOnDisk = array_keys($aFilesOnDisk);
1445              if ($debug) echo "<p>Got unmatched files: <pre>" . print_r($aUnmatchedOnDisk, true) . "</pre></p>";
1446              $nCount = 0;
1447              foreach ($aUnmatchedOnDisk AS $sFile) {
1448                  if (preg_match('@\.' . $serendipity['thumbSuffix'] . '\.@', $sFile)) {
1449                      if ($debug) echo "<p>Skipping thumbnailed file $sFile</p>";
1450                      continue;
1451                  } else {
1452                      if ($debug) echo "<p>Checking $sFile</p>";
1453                  }
1454  
1455                  // MTG: 21/01/06: put files which have just 'turned up' into the database
1456                  $aImageData = serendipity_getImageData($sFile);
1457                  if (serendipity_isImage($aImageData)) {
1458                      $nPos = strrpos($sFile, "/");
1459                      if (is_bool($nPos) && !$nPos) {
1460                         $sFileName  = $sFile;
1461                         $sDirectory = "";
1462                      } else {
1463                         ++$nPos;
1464                         $sFileName  = substr($sFile, $nPos);
1465                         $sDirectory = substr($sFile, 0, $nPos);
1466                      }
1467                      if ($debug) echo "<p>Inserting image $sFileName from $sDirectory <pre>" . print_r($aImageData, true) . "</pre> into database</p>";
1468                      # TODO: Check if the thumbnail generation goes fine with Marty's code
1469                      serendipity_makeThumbnail($sFileName, $sDirectory);
1470                      serendipity_insertImageInDatabase($sFileName, $sDirectory);
1471                      ++$nCount;
1472                  }
1473              }
1474  
1475              if ($nCount > 0) {
1476                  if ($debug) echo "<p>Inserted ".$nCount." images into the database</p>";
1477              }
1478          } else {
1479              if ($debug) echo "<p>Media Gallery database is up to date</p>";
1480          }
1481  
1482           /*
1483           $nTimeEnd = microtime_float ( );
1484           $nDifference = $nTimeEnd - $nTimeStart;
1485           echo "<p> total time taken was " . $nDifference . "</p>";
1486          */
1487          ## SYNCH FINISHED ##
1488      }
1489  
1490      ## Aply ACL afterwards:
1491      serendipity_directoryACL($paths, 'read');
1492  
1493      $serendipity['imageList'] = serendipity_fetchImagesFromDatabase(
1494                                    $start,
1495                                    $perPage,
1496                                    $totalImages, // Passed by ref
1497                                    (isset($serendipity['GET']['sortorder']['order']) ? $serendipity['GET']['sortorder']['order'] : false),
1498                                    (isset($serendipity['GET']['sortorder']['ordermode']) ? $serendipity['GET']['sortorder']['ordermode'] : false),
1499                                    (isset($serendipity['GET']['only_path']) ? $serendipity['GET']['only_path'] : ''),
1500                                    (isset($serendipity['GET']['only_filename']) ? $serendipity['GET']['only_filename'] : ''),
1501                                    (isset($serendipity['GET']['keywords']) ? $serendipity['GET']['keywords'] : ''),
1502                                    (isset($serendipity['GET']['filter']) ? $serendipity['GET']['filter'] : '')
1503      );
1504  
1505      $pages         = ceil($totalImages / $perPage);
1506      $linkPrevious  = '?' . $extraParems . 'serendipity[page]=' . ($page-1);
1507      $linkNext      = '?' . $extraParems . 'serendipity[page]=' . ($page+1);
1508      if (is_null($lineBreak)) {
1509          $lineBreak = floor(750 / ($serendipity['thumbSize'] + 20));
1510      }
1511  
1512      $dprops = $keywords = array();
1513      if ($serendipity['parseMediaOverview']) {
1514          $ids = array();
1515          foreach ($serendipity['imageList'] as $k => $file) {
1516              $ids[] = $file['id'];
1517          }
1518          $allprops =& serendipity_fetchMediaProperties($ids);
1519      }
1520  
1521      if (count($serendipity['imageList']) > 0) {
1522          foreach ($serendipity['imageList'] as $k => $file) {
1523              if (!($serendipity['authorid'] == $file['authorid'] || $file['authorid'] == '0' || serendipity_checkPermission('adminImagesViewOthers'))) {
1524                  // This is a fail-safe continue. Basically a non-matching file should already be filtered in SQL.
1525                  continue;
1526              }
1527  
1528              serendipity_prepareMedia($serendipity['imageList'][$k], $url);
1529  
1530              if ($serendipity['parseMediaOverview']) {
1531                  $serendipity['imageList'][$k]['props'] =& $allprops[$file['id']];
1532                  if (!is_array($serendipity['imageList'][$k]['props']['base_metadata'])) {
1533                      $serendipity['imageList'][$k]['metadata'] =& serendipity_getMetaData($serendipity['imageList'][$k]['realfile'], $serendipity['imageList'][$k]['header']);
1534                  } else {
1535                      $serendipity['imageList'][$k]['metadata'] = $serendipity['imageList'][$k]['props']['base_metadata'];
1536                      serendipity_plugin_api::hook_event('media_getproperties_cached', $serendipity['imageList'][$k]['metadata'], $serendipity['imageList'][$k]['realfile']);
1537                  }
1538                  serendipity_parseMediaProperties($dprops, $keywords, $serendipity['imageList'][$k], $serendipity['imageList'][$k]['props'], 3, false);
1539              }
1540          }
1541      }
1542  
1543      $smarty_vars = array(
1544          'limit_path'    => $limit_path,
1545          'perPage'       => $perPage,
1546          'show_upload'   => $show_upload,
1547          'page'          => $page,
1548          'pages'         => $pages,
1549          'linkNext'      => $linkNext,
1550          'linkPrevious'  => $linkPrevious,
1551          'extraParems'   => $extraParems
1552      );
1553      return serendipity_showMedia(
1554          $serendipity['imageList'],
1555          $paths,
1556          $url,
1557          $manage,
1558          $lineBreak,
1559          true,
1560          $smarty_vars,
1561          $smarty_display
1562      );
1563  } // End serendipity_displayImageList()
1564  
1565  /**
1566   * Check if a media item is an image
1567   *
1568   * @access public
1569   * @param   array       File information
1570   * @param   boolean     Use a strict check that does not list PDFs as an image?
1571   * @return  boolean     True if the file is an image
1572   */
1573  function serendipity_isImage(&$file, $strict = false) {
1574      global $serendipity;
1575  
1576      $file['displaymime'] = $file['mime'];
1577  
1578      // Strip HTTP path out of imgsrc
1579      $file['location'] = $serendipity['serendipityPath'] . preg_replace('@^(' . preg_quote($serendipity['serendipityHTTPPath']) . ')@i', '', $file['imgsrc']);
1580  
1581      // File is PDF -> Thumb is PNG
1582      if ($file['mime'] == 'application/pdf' && file_exists($file['location'] . '.png') && $strict == false) {
1583          $file['imgsrc']     .= '.png';
1584          $file['displaymime'] = 'image/png';
1585      }
1586  
1587      return (0 === strpos(strtolower($file['displaymime']), 'image/'));
1588  }
1589  
1590  /**
1591   * Recursively delete a directory tree
1592   *
1593   * @access public
1594   * @param   string      The originating directory
1595   * @param   string      The subdirectory
1596   * @param   boolean     Force deleting an directory even if there are files left in it?
1597   * @return true
1598   */
1599  function serendipity_killPath($basedir, $directory = '', $forceDelete = false) {
1600      static $n = "<br />\n";
1601      static $serious = true;
1602  
1603      if ($handle = @opendir($basedir . $directory)) {
1604          while (false !== ($file = @readdir($handle))) {
1605              if ($file != '.' && $file != '..') {
1606                  if (is_dir($basedir . $directory . $file)) {
1607                      serendipity_killPath($basedir, $directory . $file . '/', $forceDelete);
1608                  } else {
1609                      $filestack[$file] = $directory . $file;
1610                  }
1611              }
1612          }
1613          @closedir($handle);
1614  
1615          printf(CHECKING_DIRECTORY . "<br />\n", $directory);
1616  
1617          // No, we just don't kill files the easy way. We sort them out properly from the database
1618          // and preserve files not entered therein.
1619          $files = serendipity_fetchImagesFromDatabase(0, 0, $total, false, false, $directory);
1620          if (is_array($files)) {
1621              echo "<ul>\n";
1622              foreach($files AS $f => $file) {
1623                  echo "<li>\n";
1624                  if ($serious) {
1625                      serendipity_deleteImage($file['id']);
1626                  } else {
1627                      echo $file['name'] . '.' . $file['extension'];
1628                  }
1629                  echo "</li>\n";
1630  
1631                  unset($filestack[$file['name'] . '.' . $file['extension']]);
1632                  unset($filestack[$file['name'] . (!empty($file['thumbnail_name']) ? '.' . $file['thumbnail_name'] : '') . '.' . $file['extension']]);
1633              }
1634              echo "</ul>\n";
1635          }
1636  
1637          if (count($filestack) > 0) {
1638              if ($forceDelete) {
1639                  echo "<ul>\n";
1640                  foreach($filestack AS $f => $file) {
1641                      if ($serious && @unlink($basedir . $file)) {
1642                          printf('<li>' . DELETING_FILE . $n . DONE . "</li>\n", $file);
1643                      } else {
1644                          printf('<li>' . DELETING_FILE . $n . ERROR . "</li>\n", $file);
1645                      }
1646                  }
1647                  echo "</ul>\n";
1648              } else {
1649                  echo ERROR_DIRECTORY_NOT_EMPTY . $n;
1650                  echo "<ul>\n";
1651                  foreach($filestack AS $f => $file) {
1652                      echo '<li>' . $file . "</li>\n";
1653                  }
1654                  echo "</ul>\n";
1655              }
1656          }
1657  
1658          echo '<strong>';
1659          if ($serious && !empty($directory) && !preg_match('@^.?/?$@', $directory) && @rmdir($basedir . $directory)) {
1660              printf(DIRECTORY_DELETE_SUCCESS . $n, $directory);
1661          } else {
1662              printf(DIRECTORY_DELETE_FAILED . $n, $directory);
1663          }
1664          echo '</strong>';
1665      }
1666  
1667      return true;
1668  }
1669  
1670  
1671  /**
1672   * Recursively walk a directory tree
1673   *
1674   *
1675   * @access public
1676   * @param   string      The core directory
1677   * @param   string      The subdirectory
1678   * @param   boolean     Only return directories instead of files as well?
1679   * @param   string      A regexp patter to include files
1680   * @param   int         Level of nesting (recursive use)
1681   * @param   int         The maximum level of nesting (recursive use)
1682   * @param   mixed       Toggle whether to apply serendipity_directoryACL (false / 'read' / 'write')
1683   * @param   array       An array of directories to skip [passed by plugins, for example]
1684   * @return  array       Array of files/directories
1685   */
1686  function serendipity_traversePath($basedir, $dir='', $onlyDirs = true, $pattern = NULL, $depth = 1, $max_depth = NULL, $apply_ACL = false, $aExcludeDirs = NULL) {
1687  
1688      if ($aExcludeDirs === null) {
1689          $aExcludeDirs = array("CVS" => true, ".svn" => true);
1690      }
1691  
1692      $odir = serendipity_dirSlash('end', $basedir) . serendipity_dirSlash('end', $dir);
1693      $dh = @opendir($odir);
1694      if (!$dh) {
1695          return array();
1696      }
1697  
1698      $files = array();
1699      while (($file = @readdir($dh)) !== false) {
1700          if ($file != '.' && $file != '..') {
1701              $bPatternMatch = (is_null($pattern) || preg_match($pattern, $file));
1702              $sFullPath     = $odir . $file;
1703              $bIsDir        = is_dir($sFullPath);
1704              if ($onlyDirs === false || $bIsDir) {
1705                  if ($bPatternMatch &&
1706                      (!$bIsDir || $aExcludeDirs == null || !isset($aExcludeDirs[$file]))) {
1707                      $files[] = array(
1708                          'name'      => $file,
1709                          'depth'     => $depth,
1710                          'relpath'   => ltrim(str_replace('\\', '/', serendipity_dirSlash('end', $dir)) . basename($file) . ($bIsDir ? '/' : ''), '/'),
1711                          'directory' => $bIsDir
1712                      );
1713                  }
1714              }
1715  
1716              if ($bIsDir &&
1717                  ($max_depth === null || $depth < $max_depth) &&
1718                  ($aExcludeDirs == null || !isset($aExcludeDirs[$file]))) {
1719                  $next_dir = serendipity_dirSlash('end', $dir) . basename($file);
1720                  $files = array_merge($files, serendipity_traversePath($basedir, $next_dir, $onlyDirs, $pattern, ($depth+1), $max_depth, $apply_ACL, $aExcludeDirs));
1721              }
1722          }
1723      }
1724  
1725      @closedir($dh);
1726  
1727      if ($depth == 1 && $apply_ACL !== FALSE) {
1728          serendipity_directoryACL($files, $apply_ACL);
1729      }
1730  
1731      return $files;
1732  }
1733  
1734  /**
1735   * Custom usort() function that properly sorts a path
1736   *
1737   * @access public
1738   * @param   array      First array
1739   * @param   array      Second array
1740   * @return
1741   */
1742  function serendipity_sortPath($a, $b) {
1743      return strcasecmp($a['relpath'], $b['relpath']);
1744  }
1745  
1746  /**
1747   * Delete a directory with all its files
1748   *
1749   * @access public
1750   * @param   string      The directory to delete
1751   * @return
1752   */
1753  function serendipity_deletePath($dir) {
1754      $d = dir($dir);
1755      if ($d) {
1756          while ($f = $d->read() ){
1757              if ($f != '.' && $f != '..') {
1758                  if (is_dir($dir . $f)){
1759                      serendipity_deletePath($dir . $f . '/');
1760                      rmdir($dir . $f);
1761                  }
1762  
1763                  if (is_file($dir . $f)) {
1764                      unlink($dir . $f);
1765                  }
1766              }
1767          }
1768  
1769          $d->close();
1770      }
1771  }
1772  
1773  /**
1774   * Check if a entered HTTP upload path is valid
1775   *
1776   * @access public
1777   * @param   string      The input filename
1778   * @param   boolean     Shall all paths be stripped?
1779   * @param   boolean     Shall a trailing slash be appended?
1780   * @return  string      The condom-wrapped path/file info
1781   */
1782  function serendipity_uploadSecure($var, $strip_paths = true, $append_slash = false) {
1783      $var = preg_replace('@[^0-9a-z\._/-]@i', '', $var);
1784      if ($strip_paths) {
1785          $var = preg_replace('@(\.+[/\\\\]+)@', '/', $var);
1786      }
1787  
1788      $var = preg_replace('@^(/+)@', '', $var);
1789  
1790      if ($append_slash) {
1791          if (!empty($var) && substr($var, -1, 1) != '/') {
1792              $var .= '/';
1793          }
1794      }
1795  
1796      return $var;
1797  }
1798  
1799  /**
1800   * Get the imagesize for a file
1801   *
1802   * @access public
1803   * @param   string      The filename of the image
1804   * @param   string      The mimetype of an image (can be autodetected)
1805   * @param   string      The file extension of an image
1806   * @return  array       The width/height of the file
1807   */
1808  function serendipity_getimagesize($file, $ft_mime = '', $suf = '') {
1809      if (empty($ft_mime) && !empty($suf)) {
1810          $ft_mime = serendipity_guessMime($suf);
1811      }
1812  
1813      if ($ft_mime == 'application/pdf') {
1814          $fdim = array(1000,1000,24, '', 'bits'=> 24, 'channels' => '3', 'mime' => 'application/pdf');
1815      } else {
1816          $fdim = @getimagesize($file);
1817      }
1818  
1819      if (is_array($fdim)) {
1820          if (empty($fdim['mime'])) {
1821              $fdim['mime'] = $ft_mime;
1822          }
1823  
1824          if ($fdim['mime'] == 'image/vnd.wap.wbmp' && $ft_mime == 'video/x-quicktime') {
1825              // PHP Versions prior to 4.3.9 reported .mov files wrongly as WAP. Fix this and mark the file as 'non-image' with 0x0 dimensions
1826              $fdim['mime'] = $ft_mime;
1827          }
1828      } else {
1829          // The file is no image. Return a fake array so that files are inserted (but without a thumb)
1830          $fdim = array(
1831              0         => 0,
1832              1         => 0,
1833              'mime'    => $ft_mime,
1834              'noimage' => true
1835          );
1836      }
1837  
1838      return $fdim;
1839  }
1840  
1841  /**
1842   * Get the available fields of the media database
1843   *
1844   * @access public
1845   * @return array    Array with available, sortable fields
1846   */
1847  function serendipity_getImageFields() {
1848      global $serendipity;
1849  
1850      $x = array(
1851          'i.date'              => array('desc' => SORT_ORDER_DATE,
1852                                       'type' => 'date'
1853                                 ),
1854  
1855          'i.name'              => array('desc' => SORT_ORDER_NAME
1856                                 ),
1857  
1858          'i.authorid'          => array('desc' => AUTHOR,
1859                                       'type' => 'authors'
1860                                 ),
1861  
1862          'i.extension'         => array('desc' => SORT_ORDER_EXTENSION
1863                                 ),
1864  
1865          'i.size'              => array('desc' => SORT_ORDER_SIZE,
1866                                       'type' => 'intrange'
1867                                 ),
1868  
1869          'i.dimensions_width'  => array('desc' => SORT_ORDER_WIDTH,
1870                                       'type' => 'intrange'
1871                                 ),
1872  
1873          'i.dimensions_height' => array('desc' => SORT_ORDER_HEIGHT,
1874                                       'type' => 'intrange'
1875                                 )
1876      );
1877  
1878      $addProp = explode(';', $serendipity['mediaProperties']);
1879      foreach($addProp AS $prop) {
1880          $parts = explode(':', $prop);
1881          $name  = $parts[0];
1882          $x['bp.' . $name] = array('desc' => (defined('MEDIA_PROPERTY_' . $name) ? constant('MEDIA_PROPERTY_' . $name) : htmlspecialchars($name)));
1883          if (preg_match('@date@i', $name)) {
1884              $x['bp.' . $name]['type'] = 'date';
1885          }
1886          if (preg_match('@length@i', $name)) {
1887              $x['bp.' . $name]['type'] = 'intrange';
1888          }
1889          if (preg_match('@dpi@i', $name)) {
1890              $x['bp.' . $name]['type'] = 'int';
1891          }
1892      }
1893  
1894      return $x;
1895  }
1896  
1897  /**
1898   * Escape a shell argument for imagemagick use
1899   *
1900   * @access public
1901   * @param   string  Input argument
1902   * @return  string  Output argument
1903   */
1904  function serendipity_escapeshellarg($string) {
1905      return escapeshellarg(str_replace('%', '', $string));
1906  }
1907  
1908  /**
1909   * Rename a media directory
1910   *
1911   * @access public
1912   * @param   string  Old directory name
1913   * @param   string  New directory name
1914   */
1915  function serendipity_renameDir($old, $new) {
1916  }
1917  
1918  /**
1919   * Makes sure a directory begins with or ends with a "/"
1920   *
1921   * @access public
1922   * @param   string  Type of where to append/prepend slash ('end', 'start', 'both')
1923   * @param   string  Directory name
1924   * @return  string  Output argument
1925   */
1926  function serendipity_dirSlash($type, $dir) {
1927  
1928      if ($dir == '') {
1929          return $dir;
1930      }
1931  
1932      if ($type == 'start' || $type == 'both') {
1933          if (substr($dir, 0, 1) != '/') {
1934              $dir = '/' . $dir;
1935          }
1936      }
1937  
1938      if ($type == 'end' || $type == 'both') {
1939          if (substr($dir, -1) != '/') {
1940              $dir .= '/';
1941          }
1942      }
1943  
1944      return $dir;
1945  }
1946  
1947  /**
1948   * Cycle a serendipity_traversePath resultset and apply read/write ACLs.
1949   *
1950   * @access public
1951   * @param   array   serendipity_traversePath result array
1952   * @param   string  ACL type ('read', 'write')
1953   */
1954  function serendipity_directoryACL(&$paths, $type = 'read') {
1955      global $serendipity;
1956      static $debug = false;
1957  
1958      if ($debug) {
1959          echo "Applying ACL for mode '$type'.<br />\n";
1960      }
1961  
1962      if (!is_array($paths)) {
1963          return true;
1964      }
1965  
1966      $startCount = count($paths);
1967      if (!isset($serendipity['enableACL']) || $serendipity['enableACL'] == true) {
1968          // Check if we are a cool superuser. Bail out if we are.
1969          $logged_in = serendipity_userLoggedIn();
1970          if ($logged_in && serendipity_checkPermission('adminImagesMaintainOthers') && serendipity_checkPermission('adminImagesDirectories')) {
1971              if (!$debug) {
1972                  return true;
1973              }
1974          }
1975  
1976          // Get list of all ACLs for directories.
1977          $q = "SELECT a.artifact_index AS directory,
1978                       a.groupid
1979                  FROM {$serendipity['dbPrefix']}access AS a
1980                 WHERE a.artifact_type = 'directory'
1981                   AND a.artifact_mode = '" . serendipity_db_escape_string($type) . "'";
1982          $allowed = serendipity_db_query($q);
1983          if (!is_array($allowed)) {
1984              return true;
1985          }
1986  
1987          // Get a list of all the groups for this user. Pipe it into a usable array.
1988          if ($logged_in) {
1989              $my_groups =& serendipity_getGroups($serendipity['authorid']);
1990              $acl_allowed_groups = array();
1991              foreach($my_groups AS $my_group) {
1992                  $acl_allowed_groups[$my_group['id']] = true;
1993              }
1994          } else {
1995              // Only the 'ALL AUTHORS' group is valid for non-logged in authors.
1996              $acl_allowed_groups = array(0 => true);
1997          }
1998  
1999          // Iterate every ACL and check if we are allowed to use it. Parse that data into a workable array.
2000          $acl_allowed = array();
2001          foreach($allowed AS $row) {
2002              $acl_allowed[$row['directory']][$row['groupid']] = true;
2003          }
2004  
2005          // Iterate the input path array and check it against ACL.
2006          foreach($paths AS $idx => $info) {
2007              if (!isset($acl_allowed[$info['relpath']])) {
2008                  // ACL for directory not set. Assume we are allowed to access.
2009                  continue;
2010              }
2011  
2012              $granted = false;
2013              foreach($acl_allowed[$info['relpath']] AS $groupid => $set) {
2014                  if ($groupid === 0 || isset($acl_allowed_groups[$groupid])) {
2015                      // We are allowed to access this element
2016                      $granted = true;
2017                      break;
2018                  }
2019              }
2020  
2021              if ($granted === false) {
2022                  // We are not allowed to access this element
2023                  if ($debug) {
2024                      echo "ACL for " . $info['relpath'] . " DENIED.<br />\n";
2025                  }
2026                  unset($paths[$idx]);
2027              } else {
2028                  if ($debug) {
2029                      echo "ACL for " . $info['relpath'] . " granted.<br />\n";
2030                  }
2031              }
2032          }
2033  
2034          if (count($paths) < $startCount) {
2035              if ($debug) {
2036                  echo "ACL denied all.<br />\n";
2037              }
2038              return false;
2039          }
2040      }
2041  
2042      return true;
2043  }
2044  
2045   /**
2046   * Build the name of a thumbnail image file.
2047   *
2048   * @author MTG
2049   * @param  string   Relative Path
2050   * @param  string   File name
2051   * @param  string   File extension
2052   * @param  string   Thumbnail suffix
2053   * @return array    Thumbnail path
2054   *
2055   */
2056  function serendipity_getThumbNailPath($sRelativePath, $sName, $sExtension, $sThumbName) {
2057      $aTempArray = array('path'      => $sRelativePath,
2058                          'name'      => $sName,
2059                          'extension' => $sExtension);
2060      serendipity_plugin_api::hook_event('backend_thumbnail_filename_select', $aTempArray);
2061  
2062      if (isset($aTempArray['thumbnail_filename'])) {
2063          $sThumbNailPath = $aTempArray['thumbnail_filename'];
2064      } else {
2065          $sThumbNailPath = $sRelativePath . $sName . (!empty($sThumbName) ? '.' . $sThumbName : '') . '.' . $sExtension;
2066      }
2067  
2068      return $sThumbNailPath;
2069  }
2070  
2071   /**
2072   * Given a relative path to an image, construct an array containing all
2073   * relevant information about that image in the file structure.
2074   *
2075   * @author MTG
2076   * @param  string   Relative Path
2077   * @return array    Data about image
2078   *
2079   */
2080  function &serendipity_getImageData($sRelativePath) {
2081      global $serendipity;
2082  
2083      // First, peel off the file name from the path
2084      $nPos = strrpos($sRelativePath, '/');
2085      if (is_bool($nPos) && !$nPos) {
2086          $sFileName  = $sRelativePath;
2087          $sDirectory = '';
2088      } else {
2089          $nLastSlashPos = 1 + $nPos;
2090          $sFileName     = substr($sRelativePath, $nLastSlashPos);
2091          $sDirectory    = substr($sRelativePath, 0, $nLastSlashPos);
2092      }
2093  
2094      list($sName, $sExtension) = serendipity_parseFileName($sFileName);
2095  
2096      $sImagePath = $serendipity['serendipityPath'] . $serendipity['uploadPath'] . $sRelativePath;
2097  
2098      $aSizeData = @serendipity_getimagesize($sImagePath , '', $sExtension);
2099      $nWidth    = $aSizeData[0];
2100      $nHeight   = $aSizeData[1];
2101      $sMime     = $aSizeData['mime'];
2102      $nFileSize = @filesize($sImagePath);
2103  
2104      $array = array(
2105          'name'              => $sName,
2106          'extension'         => $sExtension,
2107          'mime'              => $sMime,
2108          'size'              => $nFileSize,
2109          'dimensions_width'  => $nWidth,
2110          'dimensions_height' => $nHeight,
2111          'path'              => $sDirectory,
2112          'authorid'          => 0,
2113          'hotlink'           => 0,
2114          'id'                => $sRelativePath,
2115          'realname'          => $sFilename
2116      );
2117  
2118      return $array;
2119  }
2120  
2121  /**
2122   * Shows the HTML form to add/edit properties of uploaded media items
2123   *
2124   * @param  array    Associative array holding an array('image_id', 'target', 'created_thumbnail') that points to the uploaded media
2125   * @param  int      How many keyword checkboxes to display next to each other?
2126   * @param  boolean  Can existing data be modified?
2127   * @return boolean
2128   *
2129   */
2130  function serendipity_showPropertyForm(&$new_media, $keywordsPerBlock = 3, $is_edit = true) {
2131      global $serendipity;
2132  
2133      if (!is_array($new_media) || count($new_media) < 1) {
2134          return true;
2135      }
2136  
2137      $mirror = array();
2138      serendipity_checkPropertyAccess($new_media, $mirror, 'read');
2139  
2140      $editform_hidden = '';
2141      if (isset($GLOBALS['image_selector_addvars']) && is_array($GLOBALS['image_selector_addvars'])) {
2142          // These variables may come from serendipity_admin_image_selector.php to show embedded upload form
2143          foreach($GLOBALS['image_selector_addvars'] AS $imgsel_key => $imgsel_val) {
2144              $editform_hidden .= '          <input type="hidden" name="serendipity[' . htmlspecialchars($imgsel_key) . ']" value="' . htmlspecialchars($imgsel_val) . '" />' . "\n";
2145          }
2146      }
2147  
2148      $dprops   = explode(';', $serendipity['mediaProperties']);
2149      $keywords = explode(';', $serendipity['mediaKeywords']);
2150  
2151      $now  = serendipity_serverOffsetHour();
2152      $show = array();
2153      foreach($new_media AS $idx => $media) {
2154          $props =& serendipity_fetchMediaProperties($media['image_id']);
2155  
2156          $show[$idx] =& $media['internal'];
2157          $show[$idx]['image_id'] = $media['image_id'];
2158  
2159          serendipity_prepareMedia($show[$idx]);
2160          if (!is_array($props['base_metadata'])) {
2161              $show[$idx]['metadata'] =& serendipity_getMetaData($show[$idx]['realfile'], $show[$idx]['header']);
2162          } else {
2163              $show[$idx]['metadata'] = $props['base_metadata'];
2164              serendipity_plugin_api::hook_event('media_getproperties_cached', $show[$idx]['metadata'], $show[$idx]['realfile']);
2165          }
2166  
2167          serendipity_parseMediaProperties($dprops, $keywords, $show[$idx], $props, $keywordsPerBlock, $is_edit);
2168      }
2169  
2170      $smarty_vars = array(
2171          'is_edit'           => $is_edit,
2172          'editform_hidden'   => $editform_hidden,
2173          'keywordsPerBlock'  => $keywordsPerBlock,
2174          'keywords'          => $keywords,
2175          'dprops'            => $dprops
2176      );
2177  
2178      return serendipity_showMedia(
2179          $show,
2180          $mirror,
2181          $url,
2182          false,
2183          1,
2184          false,
2185          $smarty_vars);
2186  }
2187  
2188  /**
2189   * Parse/Convert properties
2190   *
2191   * @param  array    Holds the property key array
2192   * @param  array    Holds the keyword key array
2193   * @param  int      Holds the media metadata
2194   * @param  int      Holds the media properties
2195   * @param  int      How many keyword checkboxes to display next to each other?
2196   * @param  boolean  Can existing data be modified?
2197   * @return boolean
2198   *
2199   */
2200  function serendipity_parseMediaProperties(&$dprops, &$keywords, &$media, &$props, $keywordsPerBlock, $is_edit) {
2201      global $serendipity;
2202  
2203      if (!is_array($dprops)) {
2204          $dprops   = explode(';', $serendipity['mediaProperties']);
2205      }
2206      if (!is_array($keywords)) {
2207          $keywords = explode(';', $serendipity['mediaKeywords']);
2208      }
2209  
2210      $media['references'] = serendipity_db_query("SELECT link, name
2211                              FROM {$serendipity['dbPrefix']}references
2212                             WHERE entry_id = " . $media['id'] . "
2213                               AND type = 'media'
2214                          ORDER BY name DESC
2215                             LIMIT 15", false, 'assoc');
2216      if (!is_array($media['references'])) {
2217          $media['references'] = false;
2218      }
2219  
2220      foreach($dprops AS $prop) {
2221          $type = 'input';
2222          $parts = explode(':', trim($prop));
2223  
2224          if (in_array('MULTI', $parts)) {
2225              $type = 'textarea';
2226          }
2227  
2228          if (preg_match('@(AUDIO|VIDEO|DOCUMENT|IMAGE|ARCHIVE|BINARY)@i', $prop)) {
2229              $show_item = false;
2230              if ($media['mediatype'] == 'video' && in_array('VIDEO', $parts)) {
2231                  $show_item = true;
2232              }
2233  
2234              if ($media['mediatype'] == 'audio'  && in_array('AUDIO', $parts)) {
2235                  $show_item = true;
2236              }
2237  
2238              if ($media['mediatype'] == 'image'  && in_array('IMAGE', $parts)) {
2239                  $show_item = true;
2240              }
2241  
2242              if ($media['mediatype'] == 'document' && in_array('DOCUMENT', $parts)) {
2243                  $show_item = true;
2244              }
2245  
2246              if ($media['mediatype'] == 'archive' && in_array('ARCHIVE', $parts)) {
2247                  $show_item = true;
2248              }
2249  
2250              if ($media['mediatype'] == 'binary' && in_array('BINARY', $parts)) {
2251                  $show_item = true;
2252              }
2253  
2254              if (!$show_item) {
2255                  continue;
2256              }
2257          }
2258  
2259          if (!$is_edit) {
2260              $type = 'readonly';
2261          }
2262          $val =& serendipity_mediaTypeCast($parts[0], $props['base_property'][$parts[0]], true);
2263  
2264          $propkey = htmlspecialchars($parts[0]) . $idx;
2265  
2266          $media['base_property'][$propkey] = array(
2267              'label' => htmlspecialchars(defined('MEDIA_PROPERTY_' . strtoupper($parts[0])) ? constant('MEDIA_PROPERTY_' . strtoupper($parts[0])) : $parts[0]),
2268              'type'  => $type,
2269              'val'   => $val,
2270              'title' => htmlspecialchars($parts[0])
2271          );
2272  
2273          if (empty($val)) {
2274              switch($parts[0]) {
2275                  case 'DATE':
2276                      $media['base_property'][$propkey]['val'] = serendipity_strftime(DATE_FORMAT_SHORT, serendipity_pickKey($media['metadata'], 'DateCreated', $now));
2277                      break;
2278  
2279                  case 'RUN_LENGTH':
2280                      $media['base_property'][$propkey]['val'] = serendipity_pickKey($media['metadata'], 'RunLength', '00:00:00.00');
2281                      break;
2282  
2283                  case 'DPI':
2284                      $media['base_property'][$propkey]['val'] = serendipity_pickKey($media['metadata'], 'XResolution', 72);
2285                      break;
2286  
2287                  case 'COPYRIGHT':
2288                      $media['base_property'][$propkey]['val'] = serendipity_pickKey($media['metadata'], 'Creator', $serendipity['serendipityUser']);
2289                      break;
2290  
2291                  case 'TITLE':
2292                      $media['base_property'][$propkey]['val'] = serendipity_pickKey($media['metadata'], 'Title', $media['internal']['realname']);
2293                      break;
2294  
2295                  case 'COMMENT1':
2296                      $media['base_property'][$propkey]['val'] = serendipity_pickKey($media['metadata'], 'Keywords', '');
2297                      break;
2298  
2299                  case 'COMMENT2':
2300                      $media['base_property'][$propkey]['val'] = serendipity_pickKey($media['metadata'], 'PhotoLocation', '');
2301                      break;
2302  
2303                  default:
2304                      serendipity_plugin_api::hook_event('media_showproperties', $media, $propkey);
2305                      break;
2306              }
2307          }
2308      }
2309  
2310      if ($keywordsPerBlock > 0) {
2311          $rows = ceil(count($keywords) / $keywordsPerBlock);
2312          for($i = 0; $i < $rows; $i++) {
2313              for ($j = 0; $j < $keywordsPerBlock; $j++) {
2314                  $kidx = ($i*$keywordsPerBlock) + $j;
2315                  if (isset($keywords[$kidx])) {
2316                      $media['base_keywords'][$i][$j] = array(
2317                          'name'      => htmlspecialchars($keywords[$kidx]),
2318                          'selected'  => isset($props['base_keyword'][$keywords[$kidx]]) ? true : false
2319                      );
2320                  } else {
2321                      $media['base_keywords'][$i][$j] = array();
2322                  }
2323              }
2324          }
2325      }
2326  }
2327  
2328  /**
2329   * Tries to auto-convert specific fields into DB-storable values
2330   *
2331   * @param  string   The keyname
2332   * @param  string   The value
2333   * @param  string   Invert?
2334   * @return array    array('image_id') holding the last created thumbnail for immediate processing
2335   *
2336   */
2337  function serendipity_mediaTypeCast($key, $val, $invert = false) {
2338      if (stristr($key, 'date') !== FALSE) {
2339          if ($invert && is_numeric($val)) {
2340              return serendipity_strftime(DATE_FORMAT_SHORT, $val, false);
2341          } elseif ($invert === false) {
2342              $tmp = strtotime($val);
2343              if ($tmp !== FALSE && $tmp > 1) {
2344                  return $tmp;
2345              }
2346          }
2347      } elseif ($invert && stristr($key, 'length') !== FALSE) {
2348          $tmp = '';
2349  
2350          $hours    = intval(intval($val) / 3600);
2351          $minutes  = intval(($val / 60) % 60);
2352          $seconds  = intval($val % 60);
2353          $mseconds = intval((($val - $seconds) * 100) % 100);
2354  
2355          $tmp .= str_pad($hours, 2, '0', STR_PAD_LEFT) . ':';
2356          $tmp .= str_pad($minutes, 2, '0', STR_PAD_LEFT). ':';
2357          $tmp .= str_pad($seconds, 2, '0', STR_PAD_LEFT) . '.';
2358          $tmp .= str_pad($mseconds, 2, '0', STR_PAD_LEFT);
2359  
2360          return $tmp;
2361      } elseif ($invert === false && preg_match('@^([0-9]+):([0-9]+):([0-9]+).([0-9]+)$@i', $val, $m)) {
2362          $tmp = ($m[1] * 3600)
2363               + ($m[2] * 60)
2364               + ($m[3])
2365               + ($m[4] / 100);
2366          return $tmp;
2367      }
2368  
2369      return $val;
2370  }
2371  
2372  /**
2373   * Inserts media properties
2374   *
2375   * @param   string  Property_group
2376   * @return array    array('image_id') holding the last created thumbnail for immediate processing
2377   *
2378   */
2379  function serendipity_insertMediaProperty($property_group, $property_subgroup = '', $image_id, &$media, $use_cast = true) {
2380      global $serendipity;
2381  
2382      serendipity_db_query("DELETE FROM {$serendipity['dbPrefix']}mediaproperties
2383                                  WHERE mediaid = " . (int)$image_id . "
2384                                    " . ($property_subgroup != 'ALL' ? "AND property_subgroup = '" . serendipity_db_escape_string($property_subgroup) . "'" : '') . "
2385                                    AND property_group = '" . serendipity_db_escape_string($property_group) . "'");
2386  
2387      if (is_array($media)) {
2388          foreach($media AS $key => $val) {
2389              if ($key == 'image_id') continue;
2390  
2391              if (is_array($val)) {
2392                  $use_property_subgroup = $key;
2393                  $use_val = $val;
2394              } else {
2395                  $use_property_subgroup = $property_subgroup;
2396                  $use_val = array($key => $val);
2397              }
2398  
2399              foreach($use_val AS $insert_key => $insert_val) {
2400                  if ($use_cast) {
2401                      $insert_val = serendipity_mediaTypeCast($insert_key, $insert_val);
2402                  }
2403                  $q = sprintf("INSERT INTO {$serendipity['dbPrefix']}mediaproperties
2404                                            (mediaid, property_group, property_subgroup, property, value)
2405                                     VALUES (%d, '%s', '%s', '%s', '%s')",
2406                               $image_id,
2407                               serendipity_db_escape_string($property_group),
2408                               serendipity_db_escape_string($useproperty_subgroup),
2409                               serendipity_db_escape_string($insert_key),
2410                               serendipity_db_escape_string($insert_val));
2411                  serendipity_db_query($q);
2412              }
2413          }
2414      }
2415  }
2416  
2417  /**
2418   * Inserts the submitted properties of uploaded media items
2419   *
2420   * @return array    array('image_id') holding the last created thumbnail for immediate processing
2421   *
2422   */
2423  function serendipity_parsePropertyForm() {
2424      global $serendipity;
2425  
2426      if (!is_array($serendipity['POST']['mediaProperties'])) {
2427          return false;
2428      }
2429  
2430      serendipity_checkPropertyAccess($serendipity['POST']['mediaProperties'], $serendipity['POST']['mediaKeywords'], 'write');
2431  
2432      foreach($serendipity['POST']['mediaProperties'] AS $id => $media) {
2433          serendipity_insertMediaProperty('base_property', '', $media['image_id'], $media);
2434  
2435          $s9y_img = $media['internal'];
2436          $s9y_img['image_id'] = $media['image_id'];
2437          serendipity_prepareMedia($s9y_img);
2438          $s9y_img['metadata'] =& serendipity_getMetaData($s9y_img['realfile'], $s9y_img['header']);
2439          serendipity_insertMediaProperty('base_metadata', 'ALL', $media['image_id'], $s9y_img['metadata']);
2440          $s9y_img['hidden'] = array(
2441              'author'   => $serendipity['serendipityUser'],
2442              'authorid' => $serendipity['authorid']
2443          );
2444          serendipity_insertMediaProperty('base_hidden', '', $media['image_id'], $s9y_img['hidden']);
2445  
2446          if ($serendipity['POST']['oldDir'][$id] != $serendipity['POST']['newDir'][$id]) {
2447              serendipity_moveMediaDirectory(
2448                  serendipity_uploadSecure($serendipity['POST']['oldDir'][$id]),
2449                  serendipity_uploadSecure($serendipity['POST']['newDir'][$id]),
2450                  'filedir',
2451                  $media['image_id']);
2452          }
2453      }
2454  
2455      if (is_array($serendipity['POST']['mediaKeywords'])) {
2456          foreach($serendipity['POST']['mediaKeywords'] AS $id => $keywords) {
2457              serendipity_insertMediaProperty('base_keyword', '', $serendipity['POST']['mediaProperties'][$id]['image_id'], $keywords);
2458          }
2459      }
2460  
2461      $array = array(
2462          'image_id'          => $serendipity['POST']['mediaProperties'][0]['image_id'],
2463      );
2464  
2465      return $array;
2466  }
2467  
2468  /**
2469   * Fetches existing Media Properties for images
2470   *
2471   * @param  int      The media item id
2472   * @return array    Array of image metadata
2473   *
2474   */
2475  function &serendipity_fetchMediaProperties($id) {
2476      global $serendipity;
2477  
2478      $sql = "SELECT mediaid, property, property_group, property_subgroup, value
2479                FROM {$serendipity['dbPrefix']}mediaproperties
2480               WHERE mediaid IN (" . (is_array($id) ? serendipity_db_implode(',', $id) : (int)$id) . ")";
2481      $rows  = serendipity_db_query($sql, false, 'assoc');
2482      $props = array();
2483      if (is_array($rows)) {
2484          foreach($rows AS $row) {
2485              if (empty($row['property_subgroup'])) {
2486                  if (is_array($id)) {
2487                      $props[$row['mediaid']][$row['property_group']][$row['property']] = $row['value'];
2488                  } else {
2489                      $props[$row['property_group']][$row['property']] = $row['value'];
2490                  }
2491              } else {
2492                  if (is_array($id)) {
2493                      $props[$row['mediaid']][$row['property_group']][$row['property_subgroup']][$row['property']] = $row['value'];
2494                  } else {
2495                      $props[$row['property_group']][$row['property_subgroup']][$row['property']] = $row['value'];
2496                  }
2497              }
2498          }
2499      }
2500      return $props;
2501  }
2502  
2503  /**
2504   * Checks if properties to a specific image are allowed to be fetched
2505   *
2506   * @param  array    Array of image metadata
2507   * @param  array    Array of additional image metadata
2508   * @param  string   ACL toggle type ('read', 'write')
2509   * @return array    Stripped Array of image metadata
2510   *
2511   */
2512  function serendipity_checkPropertyAccess(&$new_media, &$additional, $mode = 'read') {
2513      global $serendipity;
2514  
2515      // Strip out images we don't have access to
2516      $ids = array();
2517      foreach($new_media AS $id => $item) {
2518          $ids[] = $item['image_id'];
2519      }
2520  
2521      $valid_images = serendipity_fetchImageFromDatabase($ids, $mode);
2522      foreach ($new_media AS $id => $media) {
2523          if (!isset($valid_images[$media['image_id']])) {
2524              unset($new_media[$id]);
2525              unset($additional[$id]);
2526          } else {
2527              $new_media[$id]['internal'] = $valid_images[$media['image_id']];
2528          }
2529      }
2530  
2531      return true;
2532  }
2533  
2534  /**
2535   * Prepare a media item for showing
2536   *
2537   * @param  array    Array of image metadata
2538   * @param  string   URL for maintenance tasks
2539   * @return bool
2540   *
2541   */
2542  function serendipity_prepareMedia(&$file, $url = '') {
2543      global $serendipity;
2544      static $full_perm = null;
2545  
2546      if ($full_perm === null) {
2547          $full_perm = serendipity_checkPermission('adminImagesMaintainOthers');
2548      }
2549  
2550      $sThumbSource           = serendipity_getThumbNailPath($file['path'], $file['name'], $file['extension'], $file['thumbnail_name']);
2551      $file['full_thumb']     = $serendipity['serendipityPath'] . $serendipity['uploadPath'] . $sThumbSource;
2552      $file['full_thumbHTTP'] = $serendipity['serendipityHTTPPath'] . $serendipity['uploadHTTPPath'] . $sThumbSource;
2553  
2554      if ($file['hotlink']) {
2555          $file['full_file']  = $file['path'];
2556          $file['show_thumb'] = $file['path'];
2557          if (!isset($file['imgsrc'])) {
2558              $file['imgsrc'] = $file['show_thumb'];
2559          }
2560      } else {
2561          $file['full_file']  = $serendipity['serendipityHTTPPath'] . $serendipity['uploadHTTPPath'] . $file['path'] . $file['name'] . '.'. $file['extension'];
2562          $file['show_thumb'] = $file['full_thumbHTTP'];
2563          if (!isset($file['imgsrc'])) {
2564              $file['imgsrc'] = $serendipity['uploadHTTPPath'] . $file['path'] . $file['name'] . (!empty($file['thumbnail_name']) ? '.' . $file['thumbnail_name'] : '') . '.' . $file['extension'];
2565          }
2566      }
2567  
2568      if (empty($file['realname'])) {
2569          $file['realname'] = $file['name'] . '.' . $file['extension'];
2570      }
2571      $file['diskname'] = $file['name'] . '.' . $file['extension'];
2572  
2573      $file['links'] = array('imagelinkurl' => $file['full_file']);
2574  
2575      $file['dim']       = @getimagesize($file['full_thumb'], $file['header']);
2576      $file['is_image']  = serendipity_isImage($file);
2577  
2578      if ($file['is_image']) {
2579          $file['mediatype'] = 'image';
2580      } elseif (0 === strpos(strtolower($file['displaymime']), 'video/') || 0 === strpos(strtolower($file['displaymime']), 'application/x-shockwave')) {
2581          $file['mediatype'] = 'video';
2582      } elseif (0 === strpos(strtolower($file['displaymime']), 'audio/') || 0 === strpos(strtolower($file['displaymime']), 'application/vnd.rn-') || 0 === strpos(strtolower($file['displaymime']), 'application/ogg')) {
2583          $file['mediatype'] = 'audio';
2584      } elseif (0 === strpos(strtolower($file['displaymime']), 'text/')) {
2585          $file['mediatype'] = 'document';
2586      } elseif (preg_match('@application/(pdf|rtf|msword|msexcel|excel|x-excel|mspowerpoint|postscript|vnd\.ms*|powerpoint)@i', $file['displaymime'])) {
2587          $file['mediatype'] = 'document';
2588      } elseif (preg_match('@application/(java-archive|zip|gzip|arj|x-bzip|x-bzip2|x-compressed|x-gzip|x-stuffit)@i', $file['displaymime'])) {
2589          $file['mediatype'] = 'archive';
2590      } else {
2591          $file['mediatype'] = 'binary';
2592      }
2593  
2594      $file['realfile']  = $serendipity['serendipityPath'] . $serendipity['uploadPath'] . $file['path'] . $file['name'] . '.'. $file['extension'];
2595  
2596      if ($full_perm || $serendipity['authorid'] == $file['authorid'] || $file['authorid'] == '0') {
2597          $file['is_editable'] = true;
2598      } else {
2599          $file['is_editable'] = false;
2600      }
2601  
2602      /* If it is an image, and the thumbnail exists */
2603      if ($file['is_image'] && file_exists($file['full_thumb'])) {
2604          $file['thumbWidth']  = $file['dim'][0];
2605          $file['thumbHeight'] = $file['dim'][1];
2606          $file['preview'] .= '<img src="' . $serendipity['serendipityHTTPPath'] . $serendipity['uploadHTTPPath'] . $sThumbSource . '" border="0" title="' . $file['path'] . $file['name'] . '" alt="'. $file['realname'] . '" />';
2607          if ($url) {
2608              $file['preview_url'] = $url .'&amp;serendipity[image]='. $file['id'];
2609              $file['preview'] = '<a href="'. $file['preview_url'] .'">'. $file['preview'] .'</a>';
2610          }
2611      } elseif ($file['is_image'] && $file['hotlink']) {
2612          $sizes = serendipity_calculate_aspect_size($file['dimensions_width'], $file['dimensions_height'], $serendipity['thumbSize']);
2613          $file['thumbWidth']  = $sizes[0];
2614          $file['thumbHeight'] = $sizes[1];
2615          $file['preview'] .= '<img src="' . $file['path'] . '" width="' . $sizes[0] . '" height="' . $sizes[1] . '" border="0" title="' . $file['path'] . '" alt="'. $file['realname'] . '" />';
2616          if ($url) {
2617              $file['preview_url'] = $url .'&amp;serendipity[image]='. $file['id'];
2618              $file['preview'] = '<a href="'. $file['preview_url'] .'">'. $file['preview'] .'</a>';
2619          }
2620      /* If it's not an image, or the thumbnail does not exist */
2621      } else {
2622          $mimeicon = serendipity_getTemplateFile('admin/img/mime_' . preg_replace('@[^a-z0-9\-\_]@i', '-', $file['mime']) . '.png');
2623          if (!$mimeicon) {
2624              $mimeicon = serendipity_getTemplateFile('admin/img/mime_unknown.png');
2625          }
2626          $file['preview'] .= '<img src="'. $mimeicon .'" title="' . $file['path'] . $file['name'] . ' (' . $file['mime'] . ')" alt="'. $file['mime'] .'" /><br /><span style="font-weight: bold; font-size: 8pt">- ' . (($file['hotlink']) ? MEDIA_HOTLINKED : $file['mime']) .' -</span>';
2627          if ($url) {
2628              $file['preview_url'] = $url .'&amp;serendipity[image]='. $file['id'];
2629              $file['preview'] .= '<br /><a href="' . $file['preview_url'] . '">' . $file['name'] . '.' . $file['extension'] . '</a>';
2630          }
2631      }
2632  
2633      $file['popupWidth']   = ($file['is_image'] ? ($file['dimensions_width']  + 20) : 600);
2634      $file['popupHeight']  = ($file['is_image'] ? ($file['dimensions_height'] + 20) : 500);
2635      if ($file['hotlink']) {
2636          $file['nice_hotlink'] = wordwrap($file['path'], 45, '<br />', 1);
2637      }
2638      $file['nice_size']    = number_format(round($file['size']/1024, 2), NUMBER_FORMAT_DECIMALS, NUMBER_FORMAT_DECPOINT, NUMBER_FORMAT_THOUSANDS);
2639  
2640      return true;
2641  }
2642  
2643  /**
2644   * Prints a media item
2645   *
2646   * @param  array    Array of image metadata
2647   * @param  string   URL for maintenance tasks
2648   * @param  boolean  Whether to show maintenance task items
2649   * @param  int      how many media items to display per row
2650   * @param  boolean  Enclose within a table cell?
2651   * @param  array    Additional Smarty variables
2652   * @param  boolean  If TRUE, will echo Smarty output.
2653   * @return string   Smarty block name
2654   *
2655   */
2656  function serendipity_showMedia(&$file, &$paths, $url = '', $manage = false, $lineBreak = 3, $enclose = true, $smarty_vars = array(), $smarty_display = true) {
2657      global $serendipity;
2658  
2659      $form_hidden = '';
2660      foreach($serendipity['GET'] AS $g_key => $g_val) {
2661          if (!is_array($g_val) && $g_key != 'page') {
2662              $form_hidden .= '<input type="hidden" name="serendipity[' . $g_key . ']" value="' . htmlspecialchars($g_val) . '" />';
2663          }
2664      }
2665  
2666      serendipity_smarty_init();
2667      $media = array(
2668          'manage'            => $manage,
2669          'lineBreak'         => $lineBreak,
2670          'lineBreakP'        => round(1/$lineBreak*100),
2671          'url'               => $url,
2672          'enclose'           => $enclose,
2673          'zoomIMG'           => serendipity_getTemplateFile('admin/img/big_zoom.png'),
2674          'renameIMG'         => serendipity_getTemplateFile('admin/img/big_rename.png'),
2675          'resizeIMG'         => serendipity_getTemplateFile('admin/img/big_resize.png'),
2676          'rotatecwIMG'       => serendipity_getTemplateFile('admin/img/big_rotate_cw.png'),
2677          'rotateccwIMG'      => serendipity_getTemplateFile('admin/img/big_rotate_ccw.png'),
2678          'configureIMG'      => serendipity_getTemplateFile('admin/img/configure.png'),
2679          'deleteIMG'         => serendipity_getTemplateFile('admin/img/big_delete.png'),
2680          'prevIMG'           => serendipity_getTemplateFile('admin/img/previous.png'),
2681          'nextIMG'           => serendipity_getTemplateFile('admin/img/next.png'),
2682          'token'             => serendipity_setFormToken(),
2683          'form_hidden'       => $form_hidden,
2684          'blimit_path'       => basename($limit_path),
2685          'only_path'         => $serendipity['GET']['only_path'],
2686          'only_filename'     => $serendipity['GET']['only_filename'],
2687          'sortorder'         => $serendipity['GET']['sortorder'],
2688          'keywords_selected' => $serendipity['GET']['keywords'],
2689          'filter'            => $serendipity['GET']['filter'],
2690          'sort_order'        => serendipity_getImageFields(),
2691          'authors'           => serendipity_fetchUsers(),
2692          'sort_row_interval' => array(8, 16, 50, 100),
2693          'nr_files'          => count($file),
2694          'keywords'          => explode(';', $serendipity['mediaKeywords']),
2695      );
2696  
2697      $media = array_merge($media, $smarty_vars);
2698      $media['files'] =& $file;
2699      if (count($paths) > 0) {
2700          $media['paths'] =& $paths;
2701      } else {
2702          $media['paths'] =& serendipity_getMediaPaths();
2703      }
2704  
2705      $serendipity['smarty']->assign_by_ref('media', $media);
2706  
2707      if ($enclose) {
2708          serendipity_smarty_fetch('MEDIA_ITEMS', 'admin/media_items.tpl');
2709          $block = 'admin/media_pane.tpl';
2710          if ($smarty_display) {
2711              $serendipity['smarty']->display(serendipity_getTemplateFile('admin/media_pane.tpl', 'serendipityPath'));
2712          }
2713      } else {
2714          serendipity_smarty_fetch('MEDIA_ITEMS', 'admin/media_items.tpl');
2715          $block = 'admin/media_properties.tpl';
2716          if ($smarty_display) {
2717              $serendipity['smarty']->display(serendipity_getTemplateFile('admin/media_properties.tpl', 'serendipityPath'));
2718          }
2719      }
2720  
2721      return $block;
2722  }
2723  
2724  /**
2725   * Convert a IPTC/EXIF/XMP item
2726   *
2727   * @param  string   The content
2728   * @param  string   The type of the content
2729   * @return string   The converted content
2730   *
2731   */
2732  function serendipity_metaFieldConvert(&$item, $type) {
2733      switch($type) {
2734          case 'math':
2735              $parts = explode('/', $item);
2736              return ($parts[0] / $parts[1]);
2737              break;
2738  
2739          case 'or':
2740              if ($item == '1') {
2741                  return 'Landscape';
2742              } else {
2743                  return 'Portrait';
2744              }
2745  
2746          case 'date':
2747              return strtotime($item);
2748              break;
2749  
2750          case 'date2':
2751              $parts = explode(':', $item);
2752              return mktime($parts[3], $parts[4], $parts[5], $parts[1], $parts[2], $parts[0]);
2753              break;
2754  
2755          case 'rdf':
2756              if (preg_match('@<rdf:li[^>]*>(.*)</rdf:li>@i', $item, $ret)) {
2757                  return $ret[1];
2758              }
2759              break;
2760  
2761          case 'text':
2762          default:
2763              return trim($item);
2764              break;
2765      }
2766  
2767      return '';
2768  }
2769  
2770  /**
2771   * Get the RAW media header data (XMP)
2772   *
2773   * @param  string   Filename
2774   * @return array    The raw media header data
2775   *
2776   * Inspired, but rewritten,  by "PHP JPEG Metadata Toolkit" from http://electronics.ozhiker.com.
2777   * Code is GPL so sadly we couldn't bundle that GREAT library.
2778   */
2779  function serendipity_getMediaRaw($filename) {
2780      $abort = false;
2781  
2782      $f = @fopen($filename, 'rb');
2783      $ret = array();
2784      if (!$f) {
2785          return $ret;
2786      }
2787  
2788      $filedata = fread($f, 2);
2789  
2790      if ($filedata != "\xFF\xD8") {
2791          fclose($f);
2792          return $ret;
2793      }
2794  
2795      $filedata = fread($f, 2);
2796  
2797      if ($filedata{0} != "\xFF") {
2798          fclose($f);
2799          return $ret;
2800      }
2801  
2802      while (!$abort && !feof($f) && $filedata{1} != "\xD9") {
2803          if ((ord($filedata{1}) < 0xD0) || (ord($filedata{1}) > 0xD7)) {
2804              $ordret   = fread($f, 2);
2805              $ordstart = ftell($f);
2806              $int      = unpack('nsize', $ordret);
2807  
2808              if (ord($filedata{1}) == 225) {
2809                  $content  = fread($f, $int['size'] - 2);
2810  
2811                  if (substr($content, 0, 24) == 'http://ns.adobe.com/xap/') {
2812                      $ret[] = array(
2813                          'ord'      => ord($filedata{1}),
2814                          'ordstart' => $ordstart,
2815                          'int'      => $int,
2816                          'content'  => $content
2817                      );
2818                  }
2819              } else {
2820                  fseek($f, $int['size'] - 2, SEEK_CUR);
2821              }
2822          }
2823  
2824          if ($filedata{1} == "\xDA") {
2825              $abort = true;
2826          } else {
2827              $filedata = fread($f, 2);
2828              if ($filedata{0} != "\xFF") {
2829                  fclose($f);
2830                  return $ret;
2831              }
2832          }
2833      }
2834  
2835      fclose($f);
2836  
2837      return $ret;
2838  }
2839  
2840  /**
2841   * Get the IPTC/EXIF/XMP media metadata
2842   *
2843   * @param  string   Filename
2844   * @return array    The raw media header data
2845   *
2846   */
2847  function &serendipity_getMetaData($file, &$info) {
2848      global $serendipity;
2849  
2850      # Fields taken from: http://demo.imagefolio.com/demo/ImageFolio31_files/skins/cool_blue/images/iptc.html
2851      static $IPTC_Fields = array(
2852      '2#005' => 'ObjectName',
2853      '2#025' => 'Keywords',
2854      '2#026' => 'LocationCode',
2855      '2#027' => 'LocationName',
2856      '2#030' => 'ReleaseDate',
2857      '2#035' => 'ReleaseTime',
2858      '2#037' => 'ExpirationDate',
2859      '2#038' => 'ExpirationTime',
2860      '2#055' => 'DateCreated',
2861      '2#060' => 'TimeCreated',
2862      '2#062' => 'DigitalDateCreated',
2863      '2#063' => 'DigitalTimeCreated',
2864      '2#065' => 'Software',
2865      '2#070' => 'SoftwareVersion',
2866      '2#080' => 'Photographer',
2867      '2#085' => 'Photographer Name',
2868      '2#090' => 'PhotoLocation',
2869      '2#092' => 'PhotoLocation2',
2870      '2#095' => 'PhotoState',
2871      '2#100' => 'PhotoCountryCode',
2872      '2#101' => 'PhotoCountry',
2873      '2#105' => 'Title',
2874      '2#110' => 'Credits',
2875      '2#115' => 'Source',
2876      '2#116' => 'Creator',
2877      '2#118' => 'Contact',
2878      '2#120' => 'Description',
2879      '2#131' => 'Orientation',
2880      '2#150' => 'AudioType',
2881      '2#151' => 'AudioSamplingRate',
2882      '2#152' => 'AudioSamplingResolution',
2883      '2#153' => 'AudioDuration'
2884      );
2885  
2886      static $ExifFields = array(
2887          'IFD0' => array(
2888              'Make'          => array('type' => 'text',  'name' => 'CameraMaker'),
2889              'Model'         => array('type' => 'text',  'name' => 'CameraModel'),
2890              'Orientation'   => array('type' => 'or',    'name' => 'Orientation'),
2891              'XResolution'   => array('type' => 'math',  'name' => 'XResolution'),
2892              'YResolution'   => array('type' => 'math',  'name' => 'YResolution'),
2893              'Software'      => array('type' => 'text',  'name' => 'Software'),
2894              'DateTime'      => array('type' => 'date2', 'name' => 'DateCreated'),
2895              'Artist'        => array('type' => 'text',  'name' => 'Creator'),
2896          ),
2897  
2898          'EXIF' => array(
2899              'ExposureTime'          => array('type' => 'math',  'name' => 'ExposureTime'),
2900              'ApertureValue'         => array('type' => 'math',  'name' => 'ApertureValue'),
2901              'MaxApertureValue'      => array('type' => 'math',  'name' => 'MaxApertureValue'),
2902              'ISOSpeedRatings'       => array('type' => 'text',  'name' => 'ISOSpeedRatings'),
2903              'DateTimeOriginal'      => array('type' => 'date2', 'name' => 'DateCreated'),
2904              'MeteringMode'          => array('type' => 'text',  'name' => 'MeteringMode'),
2905              'FNumber'               => array('type' => 'math',  'name' => 'FNumber'),
2906              'ExposureProgram'       => array('type' => 'text',  'name' => 'ExposureProgram'),
2907              'FocalLength'           => array('type' => 'math',  'name' => 'FocalLength'),
2908              'WhiteBalance'          => array('type' => 'text',  'name' => 'WhiteBalance'),
2909              'DigitalZoomRatio'      => array('type' => 'math',  'name' => 'DigitalZoomRatio'),
2910              'FocalLengthIn35mmFilm' => array('type' => 'text',  'name' => 'FocalLengthIn35mmFilm'),
2911              'Flash'                 => array('type' => 'text',  'name' => 'Flash'),
2912              'Fired'                 => array('type' => 'text',  'name' => 'FlashFired'),
2913              'RedEyeMode'            => array('type' => 'text',  'name' => 'RedEyeMode'),
2914          )
2915      );
2916  
2917      static $xmpPatterns = array(
2918      'tiff:Orientation'              => array('type' => 'or',   'name' => 'Orientation'),
2919      'tiff:XResolution'              => array('type' => 'math', 'name' => 'XResolution'),
2920      'tiff:YResolution'              => array('type' => 'math', 'name' => 'YResolution'),
2921      'tiff:Make'                     => array('type' => 'text', 'name' => 'CameraMaker'),
2922      'tiff:Model'                    => array('type' => 'text', 'name' => 'CameraModel'),
2923      'xap:ModifyDate'                => array('type' => 'date', 'name' => 'DateModified'),
2924      'xap:CreatorTool'               => array('type' => 'text', 'name' => 'Software'),
2925      'xap:CreateDate'                => array('type' => 'date', 'name' => 'DateCreated'),
2926      'xap:MetadataDate'              => array('type' => 'date', 'name' => 'DateMetadata'),
2927  
2928      'exif:ExposureTime'             => array('type' => 'math',  'name' => 'ExposureTime'),
2929      'exif:ApertureValue'            => array('type' => 'math',  'name' => 'ApertureValue'),
2930      'exif:MaxApertureValue'         => array('type' => 'math',  'name' => 'MaxApertureValue'),
2931      'exif:ISOSpeedRatings'          => array('type' => 'text',  'name' => 'ISOSpeedRatings'),
2932      'exif:DateTimeOriginal'         => array('type' => 'date',  'name' => 'DateCreated'),
2933      'exif:MeteringMode'             => array('type' => 'text',  'name' => 'MeteringMode'),
2934      'exif:FNumber'                  => array('type' => 'math',  'name' => 'FNumber'),
2935      'exif:ExposureProgram'          => array('type' => 'text',  'name' => 'ExposureProgram'),
2936      'exif:FocalLength'              => array('type' => 'math',  'name' => 'FocalLength'),
2937      'exif:WhiteBalance'             => array('type' => 'text',  'name' => 'WhiteBalance'),
2938      'exif:DigitalZoomRatio'         => array('type' => 'math',  'name' => 'DigitalZoomRatio'),
2939      'exif:FocalLengthIn35mmFilm'    => array('type' => 'text',  'name' => 'FocalLengthIn35mmFilm'),
2940      'exif:Fired'                    => array('type' => 'text',  'name' => 'FlashFired'),
2941      'exif:RedEyeMode'               => array('type' => 'text',  'name' => 'RedEyeMode'),
2942  
2943      'dc:title'                      => array('type' => 'rdf',   'name' => 'Title'),
2944      'dc:creator'                    => array('type' => 'rdf',   'name' => 'Creator'),
2945      );
2946  
2947      $ret = array();
2948  
2949      if (!$serendipity['mediaExif']) {
2950          return $ret;
2951      }
2952  
2953      if (!file_exists($file)) {
2954          return $ret;
2955      }
2956  
2957      if (function_exists('iptcparse') && is_array($info) && isset($info['APP13'])) {
2958          $iptc = iptcparse($info['APP13']);
2959          foreach($IPTC_Fields AS $field => $desc) {
2960              if ($iptc[$field]) {
2961                  if (is_array($iptc[$field])) {
2962                      $ret['IPTC'][$desc] = trim(implode(';', $iptc[$field]));
2963                  } else {
2964                      $ret['IPTC'][$desc] = trim($iptc[$field]);
2965                  }
2966              }
2967          }
2968      }
2969  
2970      if (function_exists('exif_read_data') && is_array($info)) {
2971          $exif = @exif_read_data($file, 'FILE,COMPUTED,ANY_TAG,IFD0,COMMENT,EXIF', true, false);
2972          if (is_array($exif)) {
2973              foreach($ExifFields AS $Exifgroup => $ExifField) {
2974                  foreach($ExifField AS $ExifName => $ExifItem) {
2975                      if (!isset($exif[$Exifgroup][$ExifName])) {
2976                          continue;
2977                      }
2978                      $ret['EXIF'][$ExifItem['name']] = serendipity_metaFieldConvert($exif[$Exifgroup][$ExifName], $ExifItem['type']);
2979                      if ($ret['EXIF'][$item['name']] == $ret['IPTC'][$item['name']]) {
2980                          unset($ret['IPTC'][$item['name']]);
2981                      }
2982                  }
2983              }
2984          }
2985      }
2986  
2987      $xmp = serendipity_getMediaRaw($file);
2988      foreach($xmp AS $xmp_data) {
2989          if (empty($xmp_data['content'])) {
2990              continue;
2991          }
2992          foreach($xmpPatterns AS $lookup => $item) {
2993              if (preg_match('@<' . $lookup . '>(.*)</' . $lookup . '>@', $xmp_data['content'], $match)) {
2994                  $ret['XMP'][$item['name']] = serendipity_metaFieldConvert($match[1], $item['type']);
2995                  if ($ret['EXIF'][$item['name']] == $ret['XMP'][$item['name']]) {
2996                      unset($ret['EXIF'][$item['name']]);
2997                  }
2998              }
2999          }
3000      }
3001  
3002      serendipity_plugin_api::hook_event('media_getproperties', $ret, $file);
3003  
3004      return $ret;
3005  }
3006  
3007  /**
3008   * Parses an existing filename and increases the filecount.
3009   *
3010   * @param  string   The (duplicate) filename
3011   * @param  string   The full path to the (duplicate) filename
3012   * @param  string   The directory of the (duplicate) filename
3013   * @param  boolean  Show new filename?
3014   * @return string   The new filename
3015   *
3016   */
3017  function serendipity_imageAppend(&$tfile, &$target, $dir, $echo = true) {
3018      static $safe_bail = 20;
3019  
3020      $realname = $tfile;
3021      list($filebase, $extension) = serendipity_parseFileName($tfile);
3022  
3023      $cnum = 1;
3024      if (preg_match('@^(.*)([0-9]+)$@', $filebase, $match)) {
3025          $cnum     = $match[2];
3026          $filebase = $match[1];
3027      }
3028  
3029      $i = 0;
3030      while ($i <= $safe_bail && file_exists($dir . $filebase . $cnum . '.' . $extension)) {
3031          $cnum++;
3032      }
3033  
3034      // Check if the file STILL exists and append a MD5 if that's the case. That should be unique enough.
3035      if (file_exists($dir . $filebase . $cnum . '.' . $extension)) {
3036          $cnum = md5(time() . $filebase);
3037      }
3038  
3039      // Those variables are passed by reference!
3040      $tfile  = $filebase . $cnum . '.' . $extension;
3041      $target = $dir . $tfile;
3042  
3043      if ($echo) {
3044          printf(FILENAME_REASSIGNED . '<br />', htmlspecialchars($tfile));
3045      }
3046      return $realname;
3047  }
3048  
3049  /**
3050   * Checks if an uploaded media item hits any configured limits.
3051   *
3052   * @param  string   The filename
3053   * @return boolean  TRUE when file is okay, FALSE when it is beyond limits
3054   *
3055   */
3056  function serendipity_checkMediaSize($file) {
3057      global $serendipity;
3058  
3059      if (!empty($serendipity['maxFileSize'])) {
3060          if (filesize($file) > $serendipity['maxFileSize']) {
3061              printf(MEDIA_UPLOAD_SIZEERROR . '<br />', (int)$serendipity['maxFileSize']);
3062              return false;
3063          }
3064      }
3065  
3066      if (!empty($serendipity['maxImgWidth']) || !empty($serendipity['maxImgHeight'])) {
3067          $dim = serendipity_getimagesize($file);
3068          if (!is_array($dim) || !isset($dim[0])) {
3069              return true;
3070          }
3071  
3072          if (!empty($serendipity['maxImgWidth'])) {
3073              if ($dim[0] > $serendipity['maxImgWidth']) {
3074                  printf(MEDIA_UPLOAD_DIMERROR . '<br />', (int)$serendipity['maxImgWidth'], (int)$serendipity['maxImgHeight']);
3075                  return false;
3076              }
3077          }
3078  
3079          if (!empty($serendipity['maxImgHeight'])) {
3080              if ($dim[1] > $serendipity['maxImgHeight']) {
3081                  printf(MEDIA_UPLOAD_DIMERROR . '<br />', (int)$serendipity['maxImgWidth'], (int)$serendipity['maxImgHeight']);
3082                  return false;
3083              }
3084          }
3085      }
3086  
3087      return true;
3088  }
3089  
3090  /**
3091   * Moves a media directory
3092   *
3093   * @param  string   The old directory
3094   * @param  string   The new directory
3095   * @param  string   The type of what to remove (dir|file|filedir)
3096   * @param  string   An item id of a file
3097   * @return boolean
3098   *
3099   */
3100  function serendipity_moveMediaDirectory($oldDir, $newDir, $type = 'dir', $item_id = null, $file = null) {
3101      global $serendipity;
3102  
3103      $real_oldDir = $serendipity['serendipityPath'] . $serendipity['uploadPath'] . $oldDir;
3104      $real_newDir = $serendipity['serendipityPath'] . $serendipity['uploadPath'] . $newDir;
3105  
3106      if ($type == 'dir') {
3107          if (!is_dir($real_oldDir)) {
3108              printf(ERROR_FILE_NOT_EXISTS . '<br />', $oldDir);
3109              return false;
3110          }
3111  
3112          if (is_dir($real_newDir)) {
3113              printf(ERROR_FILE_EXISTS . '<br />', $newDir);
3114              return false;
3115          }
3116  
3117          if (!rename($real_oldDir, $real_newDir)) {
3118              printf(MEDIA_DIRECTORY_MOVE_ERROR . '<br />', $newDir);
3119              return false;
3120          }
3121  
3122          printf(MEDIA_DIRECTORY_MOVED . '<br />', $newDir);
3123  
3124          $dirs = serendipity_db_query("SELECT id, path
3125                                          FROM {$serendipity['dbPrefix']}images
3126                                         WHERE path LIKE '" . serendipity_db_escape_string($oldDir) . "%'", false, 'assoc');
3127          if (is_array($dirs)) {
3128              foreach($dirs AS $dir) {
3129                  $old = $dir['path'];
3130                  $new = preg_replace('@^(' . preg_quote($oldDir) . ')@i', $newDir, $old);
3131                  serendipity_db_query("UPDATE {$serendipity['dbPrefix']}images
3132                                           SET path = '" . serendipity_db_escape_string($new) . "'
3133                                         WHERE id = {$dir['id']}");
3134              }
3135          }
3136  
3137          $dirs = serendipity_db_query("SELECT groupid, artifact_id, artifact_type, artifact_mode, artifact_index
3138                                          FROM {$serendipity['dbPrefix']}access
3139                                         WHERE artifact_type = 'directory'
3140                                           AND artifact_index LIKE '" . serendipity_db_escape_string($oldDir) . "%'", false, 'assoc');
3141          if (is_array($dirs)) {
3142              foreach($dirs AS $dir) {
3143                  $old = $dir['artifact_index'];
3144                  $new = preg_replace('@^(' . preg_quote($oldDir) . ')@i', $newDir, $old);
3145                  serendipity_db_query("UPDATE {$serendipity['dbPrefix']}access
3146                                           SET artifact_index = '" . serendipity_db_escape_string($new) . "'
3147                                         WHERE groupid        = '" . serendipity_db_escape_string($dir['groupid']) . "'
3148                                           AND artifact_id    = '" . serendipity_db_escape_string($dir['artifact_id']) . "'
3149                                           AND artifact_type  = '" . serendipity_db_escape_string($dir['artifact_type']) . "'
3150                                           AND artifact_mode  = '" . serendipity_db_escape_string($dir['artifact_mode']) . "'
3151                                           AND artifact_index = '" . serendipity_db_escape_string($dir['artifact_index']) . "'");
3152              }
3153          }
3154      }
3155  
3156      if ($type == 'file') {
3157          if (serendipity_isActiveFile(basename($newDir))) {
3158              printf(ERROR_FILE_FORBIDDEN, htmlspecialchars($newDir));
3159              return false;
3160          }
3161  
3162          if ($file['hotlink']) {
3163              serendipity_updateImageInDatabase(array('realname' => $newDir, 'name' => $newDir), $item_id);
3164          } else {
3165              $file_new = $file['path'] . $newDir . '.';
3166              $file_old = $file['path'] . $file['name'] . '.';
3167  
3168              $newfile = $serendipity['serendipityPath'] . $serendipity['uploadPath'] . $file_new . $file['extension'];
3169              $oldfile = $serendipity['serendipityPath'] . $serendipity['uploadPath'] . $file_old . $file['extension'];
3170              if ($newDir != '' && file_exists($oldfile) && !file_exists($newfile)) {
3171                  $renameValues = array(array(
3172                      'from'   => $oldfile,
3173                      'to'     => $newfile,
3174                      'thumb'  => $serendipity['thumbSuffix'],
3175                      'fthumb' => $file['thumbnail_name'],
3176                      'oldDir' => $oldDir,
3177                      'newDir' => $newDir,
3178                      'type'   => $type,
3179                      'item_id'=> $item_id,
3180                      'file'   => $file
3181                  ));
3182  
3183                  serendipity_plugin_api::hook_event('backend_media_rename', $renameValues);
3184  
3185                  // Rename file
3186                  rename($renameValues[0]['from'], $renameValues[0]['to']);
3187  
3188                  foreach($renameValues as $renameData) {
3189                      // Rename thumbnail
3190                      rename($serendipity['serendipityPath'] . $serendipity['uploadPath'] . $file['path'] . $file['name'] . (!empty($renameData['fthumb']) ? '.' . $renameData['fthumb'] : '') . '.' .  $file['extension'],
3191                             $serendipity['serendipityPath'] . $serendipity['uploadPath'] . $file['path'] . $newDir . '.' . $renameData['thumb'] . '.' . $file['extension']);
3192                  }
3193  
3194                  serendipity_updateImageInDatabase(array('thumbnail_name' => $renameValues[0]['thumb'], 'realname' => $newDir, 'name' => $newDir), $item_id);
3195                  $oldDir = $file_old;
3196                  $newDir = $file_new;
3197                  $real_oldDir = $serendipity['serendipityPath'] . $serendipity['uploadPath'] . $oldDir;
3198                  $real_newDir = $serendipity['serendipityPath'] . $serendipity['uploadPath'] . $newDir;
3199                  // Forward user to overview (we don't want the user's back button to rename things again)
3200              } else {
3201                  if (!file_exists($oldfile)) {
3202                      echo ERROR_FILE_NOT_EXISTS;
3203                  } elseif (file_exists($newfile)) {
3204                      echo ERROR_FILE_EXISTS;
3205                  } else {
3206                      echo ERROR_SOMETHING;
3207                  }
3208  
3209                  return false;
3210              }
3211          }
3212      } elseif ($type == 'filedir') {
3213          serendipity_db_query("UPDATE {$serendipity['dbPrefix']}images
3214                                   SET path = '" . serendipity_db_escape_string($newDir) . "'
3215                                 WHERE id   = " . (int)$item_id);
3216          $pick = serendipity_db_query("SELECT * FROM  {$serendipity['dbPrefix']}images
3217                                 WHERE id   = " . (int)$item_id, true, 'assoc');
3218  
3219          // Move thumbs
3220          $oldfile = $serendipity['serendipityPath'] . $serendipity['uploadPath'] . $oldDir . $pick['name'] . '.' . $pick['extension'];
3221          $newfile = $serendipity['serendipityPath'] . $serendipity['uploadPath'] . $newDir . $pick['name'] . '.' . $pick['extension'];
3222  
3223          $renameValues = array(array(
3224              'from'   => $oldfile,
3225              'to'     => $newfile,
3226              'thumb'  => $serendipity['thumbSuffix'],
3227              'fthumb' => $pick['thumbnail_name'],
3228              'oldDir' => $oldDir,
3229              'newDir' => $newDir,
3230              'type'   => $type,
3231              'item_id'=> $item_id,
3232              'file'   => $file
3233          ));
3234  
3235          serendipity_plugin_api::hook_event('backend_media_rename', $renameValues);
3236  
3237          // Rename file
3238          rename($renameValues[0]['from'], $renameValues[0]['to']);
3239  
3240          foreach($renameValues as $renameData) {
3241              // Rename thumbnail
3242              rename($serendipity['serendipityPath'] . $serendipity['uploadPath'] . $oldDir . $pick['name'] . (!empty($renameData['fthumb']) ? '.' . $renameData['fthumb'] : '') . '.' .  $pick['extension'],
3243                     $serendipity['serendipityPath'] . $serendipity['uploadPath'] . $newDir . $pick['name'] . '.' . $renameData['thumb'] . '.' . $pick['extension']);
3244          }
3245  
3246          $oldDir .= $pick['name'];
3247          $newDir .= $pick['name'];
3248      } elseif ($type == 'dir') {
3249          $renameValues = array(array(
3250              'from'   => $oldfile,
3251              'to'     => $newfile,
3252              'thumb'  => $serendipity['thumbSuffix'],
3253              'fthumb' => $file['thumbnail_name'],
3254              'oldDir' => $oldDir,
3255              'newDir' => $newDir,
3256              'type'   => $type,
3257              'item_id'=> $item_id,
3258              'file'   => $file
3259          ));
3260  
3261          serendipity_plugin_api::hook_event('backend_media_rename', $renameValues);
3262      }
3263  
3264      // Only MySQL supported, since I don't know how to use REGEXPs differently.
3265      if ($serendipity['dbType'] != 'mysql' && $serendipity['dbType'] != 'mysqli') {
3266          echo MEDIA_DIRECTORY_MOVE_ENTRY . '<br />';
3267          return true;
3268      }
3269  
3270      $q = "SELECT id, body, extended
3271              FROM {$serendipity['dbPrefix']}entries
3272             WHERE body     REGEXP '(src=|href=|window.open.)(\'|\")(" . serendipity_db_escape_String($serendipity['baseURL'] . $serendipity['uploadHTTPPath'] . $oldDir) . "|" . serendipity_db_escape_string($serendipity['serendipityHTTPPath'] . $serendipity['uploadHTTPPath'] . $oldDir) . ")'
3273                OR extended REGEXP '(src=|href=|window.open.)(\'|\")(" . serendipity_db_escape_String($serendipity['baseURL'] . $serendipity['uploadHTTPPath'] . $oldDir) . "|" . serendipity_db_escape_string($serendipity['serendipityHTTPPath'] . $serendipity['uploadHTTPPath'] . $oldDir) . ")'
3274      ";
3275  
3276      $dirs = serendipity_db_query($q);
3277      if (is_array($dirs)) {
3278          foreach($dirs AS $dir) {
3279              $dir['body']     = preg_replace('@(src=|href=|window.open.)(\'|")(' . preg_quote($serendipity['baseURL'] . $serendipity['uploadHTTPPath'] . $oldDir) . '|' . preg_quote($serendipity['serendipityHTTPPath'] . $serendipity['uploadHTTPPath'] . $oldDir) . ')@', '\1\2' . $serendipity['serendipityHTTPPath'] . $serendipity['uploadHTTPPath'] . $newDir, $dir['body']);
3280              $dir['extended'] = preg_replace('@(src=|href=|window.open.)(\'|")(' . preg_quote($serendipity['baseURL'] . $serendipity['uploadHTTPPath'] . $oldDir) . '|' . preg_quote($serendipity['serendipityHTTPPath'] . $serendipity['uploadHTTPPath'] . $oldDir) . ')@', '\1\2' . $serendipity['serendipityHTTPPath'] . $serendipity['uploadHTTPPath'] . $newDir, $dir['extended']);
3281  
3282              $uq = "UPDATE {$serendipity['dbPrefix']}entries
3283                                       SET body     = '" . serendipity_db_escape_string($dir['body']) . "' ,
3284                                           extended = '" . serendipity_db_escape_string($dir['extended']) . "'
3285                                     WHERE id       = " . serendipity_db_escape_string($dir['id']);
3286              serendipity_db_query($uq);
3287          }
3288  
3289          printf(MEDIA_DIRECTORY_MOVE_ENTRIES . '<br />', count($dirs));
3290      }
3291  
3292      return true;
3293  }
3294  
3295  /**
3296   * Gets all available media directories
3297   *
3298   * @return array
3299   *
3300   */
3301  function &serendipity_getMediaPaths() {
3302      global $serendipity;
3303  
3304      $aExclude = array("CVS" => true, ".svn" => true);
3305      serendipity_plugin_api::hook_event('backend_media_path_exclude_directories', $aExclude);
3306      $paths        = array();
3307  
3308      $aResultSet   = serendipity_traversePath(
3309          $serendipity['serendipityPath'] . $serendipity['uploadPath'],
3310          '',
3311          false,
3312          NULL,
3313          1,
3314          NULL,
3315          FALSE,
3316          $aExclude
3317      );
3318  
3319      foreach ($aResultSet AS $sKey => $sFile) {
3320          if ($sFile['directory']) {
3321              array_push($paths, $sFile);
3322          }
3323          unset($aResultSet[$sKey]);
3324      }
3325      serendipity_directoryACL($paths, 'read');
3326  
3327      usort($paths, 'serendipity_sortPath');
3328  
3329      return $paths;
3330  }
3331  
3332  /**
3333   * Checks whether a user has access to write into a directory
3334   *
3335   * @access public
3336   * @param   string Directory to check
3337   * @return  boolean
3338   */
3339  function serendipity_checkDirUpload($dir) {
3340      global $serendipity;
3341  
3342      /*
3343      if (serendipity_checkPermission('adminImagesMaintainOthers')) {
3344          return true;
3345      }
3346      */
3347  
3348      $allowed  = serendipity_ACLGet(0, 'directory', 'write', $dir);
3349      $mygroups = serendipity_checkPermission(null, null, true);
3350  
3351      // Usergroup "0" always means that access is granted. If no array exists, no ACL restrictions have been set and all is fine.
3352      if (!is_array($allowed) || isset($allowed[0])) {
3353          return true;
3354      }
3355  
3356      if (!is_array($mygroups)) {
3357          return true;
3358      }
3359  
3360      foreach($mygroups AS $grpid => $grp) {
3361          if (isset($allowed[$grpid])) {
3362              return true;
3363              break;
3364          }
3365      }
3366  
3367      return false;
3368  }


Généré le : Sat Nov 24 09:00:37 2007 par Balluche grâce à PHPXref 0.7
  Clicky Web Analytics