[ Index ]

PHP Cross Reference of Drupal 6 (yi-drupal)

title

Body

[close]

/includes/ -> file.inc (source)

   1  <?php
   2  
   3  /**
   4   * @file
   5   * API for handling file uploads and server file management.
   6   */
   7  
   8  /**
   9   * @defgroup file File interface
  10   * @{
  11   * Common file handling functions.
  12   */
  13  
  14  define('FILE_DOWNLOADS_PUBLIC', 1);
  15  define('FILE_DOWNLOADS_PRIVATE', 2);
  16  define('FILE_CREATE_DIRECTORY', 1);
  17  define('FILE_MODIFY_PERMISSIONS', 2);
  18  define('FILE_EXISTS_RENAME', 0);
  19  define('FILE_EXISTS_REPLACE', 1);
  20  define('FILE_EXISTS_ERROR', 2);
  21  
  22  /**
  23   * A files status can be one of two values: temporary or permanent. The status
  24   * for each file Drupal manages is stored in the {files} tables. If the status
  25   * is temporary Drupal's file garbage collection will delete the file and
  26   * remove it from the files table after a set period of time.
  27   *
  28   * If you wish to add custom statuses for use by contrib modules please expand as
  29   * binary flags and consider the first 8 bits reserved. (0,1,2,4,8,16,32,64,128)
  30   */
  31  define('FILE_STATUS_TEMPORARY', 0);
  32  define('FILE_STATUS_PERMANENT', 1);
  33  
  34  /**
  35   * Create the download path to a file.
  36   *
  37   * @param $path A string containing the path of the file to generate URL for.
  38   * @return A string containing a URL that can be used to download the file.
  39   */
  40  function file_create_url($path) {
  41    // Strip file_directory_path from $path. We only include relative paths in urls.
  42    if (strpos($path, file_directory_path() .'/') === 0) {
  43      $path = trim(substr($path, strlen(file_directory_path())), '\\/');
  44    }
  45    switch (variable_get('file_downloads', FILE_DOWNLOADS_PUBLIC)) {
  46      case FILE_DOWNLOADS_PUBLIC:
  47        return $GLOBALS['base_url'] .'/'. file_directory_path() .'/'. str_replace('\\', '/', $path);
  48      case FILE_DOWNLOADS_PRIVATE:
  49        return url('system/files/'. $path, array('absolute' => TRUE));
  50    }
  51  }
  52  
  53  /**
  54   * Make sure the destination is a complete path and resides in the file system
  55   * directory, if it is not prepend the file system directory.
  56   *
  57   * @param $dest A string containing the path to verify. If this value is
  58   *   omitted, Drupal's 'files' directory will be used.
  59   * @return A string containing the path to file, with file system directory
  60   *   appended if necessary, or FALSE if the path is invalid (i.e. outside the
  61   *   configured 'files' or temp directories).
  62   */
  63  function file_create_path($dest = 0) {
  64    $file_path = file_directory_path();
  65    if (!$dest) {
  66      return $file_path;
  67    }
  68    // file_check_location() checks whether the destination is inside the Drupal files directory.
  69    if (file_check_location($dest, $file_path)) {
  70      return $dest;
  71    }
  72    // check if the destination is instead inside the Drupal temporary files directory.
  73    else if (file_check_location($dest, file_directory_temp())) {
  74      return $dest;
  75    }
  76    // Not found, try again with prefixed directory path.
  77    else if (file_check_location($file_path .'/'. $dest, $file_path)) {
  78      return $file_path .'/'. $dest;
  79    }
  80    // File not found.
  81    return FALSE;
  82  }
  83  
  84  /**
  85   * Checks whether a directory exists and is writable.
  86   *
  87   * Furthermore, the directory can optionally be created if it does not exist,
  88   * and/or be set to writable if it is currently not. Directories need to have
  89   * execute permission to be considered a directory by FTP servers.
  90   *
  91   * @param $directory
  92   *   A string representing the directory path.
  93   * @param $mode
  94   *   An optional bitmask containing the actions, if any, to be carried out on
  95   *   the directory. Any combination of the actions FILE_CREATE_DIRECTORY and
  96   *   FILE_MODIFY_PERMISSIONS is allowed.
  97   * @param $form_item
  98   *   An optional string containing the name of a form item that any errors
  99   *   will be attached to. Useful when the function validates a directory path
 100   *   entered as a form value. An error will consequently prevent form submit
 101   *   handlers from running, and instead display the form along with the
 102   *   error messages.
 103   *
 104   * @return
 105   *   FALSE if the directory does not exist or is not writable, even after
 106   *   any optional actions have been carried out. Otherwise, TRUE is returned.
 107   */
 108  function file_check_directory(&$directory, $mode = 0, $form_item = NULL) {
 109    $directory = rtrim($directory, '/\\');
 110  
 111    // Check if directory exists.
 112    if (!is_dir($directory)) {
 113      if (($mode & FILE_CREATE_DIRECTORY) && @mkdir($directory)) {
 114        drupal_set_message(t('The directory %directory has been created.', array('%directory' => $directory)));
 115        @chmod($directory, 0775); // Necessary for non-webserver users.
 116      }
 117      else {
 118        if ($form_item) {
 119          form_set_error($form_item, t('The directory %directory does not exist.', array('%directory' => $directory)));
 120        }
 121        return FALSE;
 122      }
 123    }
 124  
 125    // Check to see if the directory is writable.
 126    if (!is_writable($directory)) {
 127      if (($mode & FILE_MODIFY_PERMISSIONS) && @chmod($directory, 0775)) {
 128        drupal_set_message(t('The permissions of directory %directory have been changed to make it writable.', array('%directory' => $directory)));
 129      }
 130      else {
 131        form_set_error($form_item, t('The directory %directory is not writable', array('%directory' => $directory)));
 132        watchdog('file system', 'The directory %directory is not writable, because it does not have the correct permissions set.', array('%directory' => $directory), WATCHDOG_ERROR);
 133        return FALSE;
 134      }
 135    }
 136  
 137    if ((file_directory_path() == $directory || file_directory_temp() == $directory) && !is_file("$directory/.htaccess")) {
 138      $htaccess_lines = "SetHandler Drupal_Security_Do_Not_Remove_See_SA_2006_006\nOptions None\nOptions +FollowSymLinks";
 139      if (($fp = fopen("$directory/.htaccess", 'w')) && fputs($fp, $htaccess_lines)) {
 140        fclose($fp);
 141        chmod($directory .'/.htaccess', 0664);
 142      }
 143      else {
 144        $variables = array('%directory' => $directory, '!htaccess' => '<br />'. nl2br(check_plain($htaccess_lines)));
 145        form_set_error($form_item, t("Security warning: Couldn't write .htaccess file. Please create a .htaccess file in your %directory directory which contains the following lines: <code>!htaccess</code>", $variables));
 146        watchdog('security', "Security warning: Couldn't write .htaccess file. Please create a .htaccess file in your %directory directory which contains the following lines: <code>!htaccess</code>", $variables, WATCHDOG_ERROR);
 147      }
 148    }
 149  
 150    return TRUE;
 151  }
 152  
 153  /**
 154   * Checks path to see if it is a directory, or a dir/file.
 155   *
 156   * @param $path A string containing a file path. This will be set to the
 157   *   directory's path.
 158   * @return If the directory is not in a Drupal writable directory, FALSE is
 159   *   returned. Otherwise, the base name of the path is returned.
 160   */
 161  function file_check_path(&$path) {
 162    // Check if path is a directory.
 163    if (file_check_directory($path)) {
 164      return '';
 165    }
 166  
 167    // Check if path is a possible dir/file.
 168    $filename = basename($path);
 169    $path = dirname($path);
 170    if (file_check_directory($path)) {
 171      return $filename;
 172    }
 173  
 174    return FALSE;
 175  }
 176  
 177  /**
 178   * Check if a file is really located inside $directory. Should be used to make
 179   * sure a file specified is really located within the directory to prevent
 180   * exploits.
 181   *
 182   * @code
 183   *   // Returns FALSE:
 184   *   file_check_location('/www/example.com/files/../../../etc/passwd', '/www/example.com/files');
 185   * @endcode
 186   *
 187   * @param $source A string set to the file to check.
 188   * @param $directory A string where the file should be located.
 189   * @return 0 for invalid path or the real path of the source.
 190   */
 191  function file_check_location($source, $directory = '') {
 192    $check = realpath($source);
 193    if ($check) {
 194      $source = $check;
 195    }
 196    else {
 197      // This file does not yet exist
 198      $source = realpath(dirname($source)) .'/'. basename($source);
 199    }
 200    $directory = realpath($directory);
 201    if ($directory && strpos($source, $directory) !== 0) {
 202      return 0;
 203    }
 204    return $source;
 205  }
 206  
 207  /**
 208   * Copies a file to a new location.
 209   *
 210   * This is a powerful function that in many ways performs like an advanced
 211   * version of copy().
 212   * - Checks if $source and $dest are valid and readable/writable.
 213   * - Performs a file copy if $source is not equal to $dest.
 214   * - If file already exists in $dest either the call will error out, replace the
 215   *   file or rename the file based on the $replace parameter.
 216   *
 217   * @param $source
 218   *   Either a string specifying the file location of the original file or an
 219   *   object containing a 'filepath' property. This parameter is passed by
 220   *   reference and will contain the resulting destination filename in case of
 221   *   success.
 222   * @param $dest
 223   *   A string containing the directory $source should be copied to. If this
 224   *   value is omitted, Drupal's 'files' directory will be used.
 225   * @param $replace
 226   *   Replace behavior when the destination file already exists.
 227   *   - FILE_EXISTS_REPLACE: Replace the existing file.
 228   *   - FILE_EXISTS_RENAME: Append _{incrementing number} until the filename is
 229   *     unique.
 230   *   - FILE_EXISTS_ERROR: Do nothing and return FALSE.
 231   * @return
 232   *   TRUE for success, FALSE for failure.
 233   */
 234  function file_copy(&$source, $dest = 0, $replace = FILE_EXISTS_RENAME) {
 235    $dest = file_create_path($dest);
 236  
 237    $directory = $dest;
 238    $basename = file_check_path($directory);
 239  
 240    // Make sure we at least have a valid directory.
 241    if ($basename === FALSE) {
 242      $source = is_object($source) ? $source->filepath : $source;
 243      drupal_set_message(t('The selected file %file could not be uploaded, because the destination %directory is not properly configured.', array('%file' => $source, '%directory' => $dest)), 'error');
 244      watchdog('file system', 'The selected file %file could not be uploaded, because the destination %directory could not be found, or because its permissions do not allow the file to be written.', array('%file' => $source, '%directory' => $dest), WATCHDOG_ERROR);
 245      return 0;
 246    }
 247  
 248    // Process a file upload object.
 249    if (is_object($source)) {
 250      $file = $source;
 251      $source = $file->filepath;
 252      if (!$basename) {
 253        $basename = $file->filename;
 254      }
 255    }
 256  
 257    $source = realpath($source);
 258    if (!file_exists($source)) {
 259      drupal_set_message(t('The selected file %file could not be copied, because no file by that name exists. Please check that you supplied the correct filename.', array('%file' => $source)), 'error');
 260      return 0;
 261    }
 262  
 263    // If the destination file is not specified then use the filename of the source file.
 264    $basename = $basename ? $basename : basename($source);
 265    $dest = $directory .'/'. $basename;
 266  
 267    // Make sure source and destination filenames are not the same, makes no sense
 268    // to copy it if they are. In fact copying the file will most likely result in
 269    // a 0 byte file. Which is bad. Real bad.
 270    if ($source != realpath($dest)) {
 271      if (!$dest = file_destination($dest, $replace)) {
 272        drupal_set_message(t('The selected file %file could not be copied, because a file by that name already exists in the destination.', array('%file' => $source)), 'error');
 273        return FALSE;
 274      }
 275  
 276      if (!@copy($source, $dest)) {
 277        drupal_set_message(t('The selected file %file could not be copied.', array('%file' => $source)), 'error');
 278        return 0;
 279      }
 280  
 281      // Give everyone read access so that FTP'd users or
 282      // non-webserver users can see/read these files,
 283      // and give group write permissions so group members
 284      // can alter files uploaded by the webserver.
 285      @chmod($dest, 0664);
 286    }
 287  
 288    if (isset($file) && is_object($file)) {
 289      $file->filename = $basename;
 290      $file->filepath = $dest;
 291      $source = $file;
 292    }
 293    else {
 294      $source = $dest;
 295    }
 296  
 297    return 1; // Everything went ok.
 298  }
 299  
 300  /**
 301   * Determines the destination path for a file depending on how replacement of
 302   * existing files should be handled.
 303   *
 304   * @param $destination A string specifying the desired path.
 305   * @param $replace Replace behavior when the destination file already exists.
 306   *   - FILE_EXISTS_REPLACE - Replace the existing file
 307   *   - FILE_EXISTS_RENAME - Append _{incrementing number} until the filename is
 308   *     unique
 309   *   - FILE_EXISTS_ERROR - Do nothing and return FALSE.
 310   * @return The destination file path or FALSE if the file already exists and
 311   *   FILE_EXISTS_ERROR was specified.
 312   */
 313  function file_destination($destination, $replace) {
 314    if (file_exists($destination)) {
 315      switch ($replace) {
 316        case FILE_EXISTS_RENAME:
 317          $basename = basename($destination);
 318          $directory = dirname($destination);
 319          $destination = file_create_filename($basename, $directory);
 320          break;
 321  
 322        case FILE_EXISTS_ERROR:
 323          drupal_set_message(t('The selected file %file could not be copied, because a file by that name already exists in the destination.', array('%file' => $destination)), 'error');
 324          return FALSE;
 325      }
 326    }
 327    return $destination;
 328  }
 329  
 330  /**
 331   * Moves a file to a new location.
 332   *
 333   * - Checks if $source and $dest are valid and readable/writable.
 334   * - Performs a file move if $source is not equal to $dest.
 335   * - If file already exists in $dest either the call will error out, replace the
 336   *   file or rename the file based on the $replace parameter.
 337   *
 338   * @param $source
 339   *   Either a string specifying the file location of the original file or an
 340   *   object containing a 'filepath' property. This parameter is passed by
 341   *   reference and will contain the resulting destination filename in case of
 342   *   success.
 343   * @param $dest
 344   *   A string containing the directory $source should be copied to. If this
 345   *   value is omitted, Drupal's 'files' directory will be used.
 346   * @param $replace
 347   *   Replace behavior when the destination file already exists.
 348   *   - FILE_EXISTS_REPLACE: Replace the existing file.
 349   *   - FILE_EXISTS_RENAME: Append _{incrementing number} until the filename is
 350   *     unique.
 351   *   - FILE_EXISTS_ERROR: Do nothing and return FALSE.
 352   * @return
 353   *   TRUE for success, FALSE for failure.
 354   */
 355  function file_move(&$source, $dest = 0, $replace = FILE_EXISTS_RENAME) {
 356    $path_original = is_object($source) ? $source->filepath : $source;
 357  
 358    if (file_copy($source, $dest, $replace)) {
 359      $path_current = is_object($source) ? $source->filepath : $source;
 360  
 361      if ($path_original == $path_current || file_delete($path_original)) {
 362        return 1;
 363      }
 364      drupal_set_message(t('The removal of the original file %file has failed.', array('%file' => $path_original)), 'error');
 365    }
 366    return 0;
 367  }
 368  
 369  /**
 370   * Modify a filename as needed for security purposes.
 371   *
 372   * Munging a file name prevents unknown file extensions from masking exploit
 373   * files. When web servers such as Apache decide how to process a URL request,
 374   * they use the file extension. If the extension is not recognized, Apache
 375   * skips that extension and uses the previous file extension. For example, if
 376   * the file being requested is exploit.php.pps, and Apache does not recognize
 377   * the '.pps' extension, it treats the file as PHP and executes it. To make
 378   * this file name safe for Apache and prevent it from executing as PHP, the
 379   * .php extension is "munged" into .php_, making the safe file name
 380   * exploit.php_.pps.
 381   *
 382   * Specifically, this function adds an underscore to all extensions that are
 383   * between 2 and 5 characters in length, internal to the file name, and not
 384   * included in $extensions.
 385   *
 386   * Function behavior is also controlled by the Drupal variable
 387   * 'allow_insecure_uploads'. If 'allow_insecure_uploads' evaluates to TRUE, no
 388   * alterations will be made, if it evaluates to FALSE, the filename is 'munged'.
 389   *
 390   * @param $filename
 391   *   File name to modify.
 392   * @param $extensions
 393   *   A space-separated list of extensions that should not be altered.
 394   * @param $alerts
 395   *   If TRUE, drupal_set_message() will be called to display a message if the
 396   *   file name was changed.
 397   *
 398   * @return
 399   *   The potentially modified $filename.
 400   */
 401  function file_munge_filename($filename, $extensions, $alerts = TRUE) {
 402    $original = $filename;
 403  
 404    // Allow potentially insecure uploads for very savvy users and admin
 405    if (!variable_get('allow_insecure_uploads', 0)) {
 406      $whitelist = array_unique(explode(' ', trim($extensions)));
 407  
 408      // Split the filename up by periods. The first part becomes the basename
 409      // the last part the final extension.
 410      $filename_parts = explode('.', $filename);
 411      $new_filename = array_shift($filename_parts); // Remove file basename.
 412      $final_extension = array_pop($filename_parts); // Remove final extension.
 413  
 414      // Loop through the middle parts of the name and add an underscore to the
 415      // end of each section that could be a file extension but isn't in the list
 416      // of allowed extensions.
 417      foreach ($filename_parts as $filename_part) {
 418        $new_filename .= '.'. $filename_part;
 419        if (!in_array($filename_part, $whitelist) && preg_match("/^[a-zA-Z]{2,5}\d?$/", $filename_part)) {
 420          $new_filename .= '_';
 421        }
 422      }
 423      $filename = $new_filename .'.'. $final_extension;
 424  
 425      if ($alerts && $original != $filename) {
 426        drupal_set_message(t('For security reasons, your upload has been renamed to %filename.', array('%filename' => $filename)));
 427      }
 428    }
 429  
 430    return $filename;
 431  }
 432  
 433  /**
 434   * Undo the effect of upload_munge_filename().
 435   *
 436   * @param $filename string filename
 437   * @return string
 438   */
 439  function file_unmunge_filename($filename) {
 440    return str_replace('_.', '.', $filename);
 441  }
 442  
 443  /**
 444   * Create a full file path from a directory and filename. If a file with the
 445   * specified name already exists, an alternative will be used.
 446   *
 447   * @param $basename string filename
 448   * @param $directory string directory
 449   * @return
 450   */
 451  function file_create_filename($basename, $directory) {
 452    $dest = $directory .'/'. $basename;
 453  
 454    if (file_exists($dest)) {
 455      // Destination file already exists, generate an alternative.
 456      if ($pos = strrpos($basename, '.')) {
 457        $name = substr($basename, 0, $pos);
 458        $ext = substr($basename, $pos);
 459      }
 460      else {
 461        $name = $basename;
 462        $ext = '';
 463      }
 464  
 465      $counter = 0;
 466      do {
 467        $dest = $directory .'/'. $name .'_'. $counter++ . $ext;
 468      } while (file_exists($dest));
 469    }
 470  
 471    return $dest;
 472  }
 473  
 474  /**
 475   * Delete a file.
 476   *
 477   * @param $path A string containing a file path.
 478   * @return TRUE for success, FALSE for failure.
 479   */
 480  function file_delete($path) {
 481    if (is_file($path)) {
 482      return unlink($path);
 483    }
 484  }
 485  
 486  /**
 487   * Determine total disk space used by a single user or the whole filesystem.
 488   *
 489   * @param $uid
 490   *   An optional user id. A NULL value returns the total space used
 491   *   by all files.
 492   */
 493  function file_space_used($uid = NULL) {
 494    if (isset($uid)) {
 495      return (int) db_result(db_query('SELECT SUM(filesize) FROM {files} WHERE uid = %d', $uid));
 496    }
 497    return (int) db_result(db_query('SELECT SUM(filesize) FROM {files}'));
 498  }
 499  
 500  /**
 501   * Saves a file upload to a new location.
 502   *
 503   * The source file is validated as a proper upload and handled as such.
 504   * The file will be added to the files table as a temporary file. Temporary
 505   * files are periodically cleaned. To make the file permanent file call
 506   * file_set_status() to change its status.
 507   *
 508   * @param $source
 509   *   A string specifying the name of the upload field to save.
 510   * @param $validators
 511   *   (optional) An associative array of callback functions used to validate the
 512   *   file. The keys are function names and the values arrays of callback
 513   *   parameters which will be passed in after the file object. The
 514   *   functions should return an array of error messages; an empty array
 515   *   indicates that the file passed validation. The functions will be called in
 516   *   the order specified.
 517   * @param $dest
 518   *   A string containing the directory $source should be copied to. If this is
 519   *   not provided or is not writable, the temporary directory will be used.
 520   * @param $replace
 521   *   Replace behavior when the destination file already exists:
 522   *   - FILE_EXISTS_REPLACE: Replace the existing file.
 523   *   - FILE_EXISTS_RENAME: Append _{incrementing number} until the filename
 524   *     is unique.
 525   *   - FILE_EXISTS_ERROR: Do nothing and return FALSE.
 526   *
 527   * @return
 528   *   An object containing the file information, or 0 in the event of an error.
 529   */
 530  function file_save_upload($source, $validators = array(), $dest = FALSE, $replace = FILE_EXISTS_RENAME) {
 531    global $user;
 532    static $upload_cache;
 533  
 534    // Add in our check of the the file name length.
 535    $validators['file_validate_name_length'] = array();
 536  
 537    // Return cached objects without processing since the file will have
 538    // already been processed and the paths in _FILES will be invalid.
 539    if (isset($upload_cache[$source])) {
 540      return $upload_cache[$source];
 541    }
 542  
 543    // If a file was uploaded, process it.
 544    if (isset($_FILES['files']) && $_FILES['files']['name'][$source] && is_uploaded_file($_FILES['files']['tmp_name'][$source])) {
 545      // Check for file upload errors and return FALSE if a
 546      // lower level system error occurred.
 547      switch ($_FILES['files']['error'][$source]) {
 548        // @see http://php.net/manual/en/features.file-upload.errors.php
 549        case UPLOAD_ERR_OK:
 550          break;
 551  
 552        case UPLOAD_ERR_INI_SIZE:
 553        case UPLOAD_ERR_FORM_SIZE:
 554          drupal_set_message(t('The file %file could not be saved, because it exceeds %maxsize, the maximum allowed size for uploads.', array('%file' => $source, '%maxsize' => format_size(file_upload_max_size()))), 'error');
 555          return 0;
 556  
 557        case UPLOAD_ERR_PARTIAL:
 558        case UPLOAD_ERR_NO_FILE:
 559          drupal_set_message(t('The file %file could not be saved, because the upload did not complete.', array('%file' => $source)), 'error');
 560          return 0;
 561  
 562          // Unknown error
 563        default:
 564          drupal_set_message(t('The file %file could not be saved. An unknown error has occurred.', array('%file' => $source)), 'error');
 565          return 0;
 566      }
 567  
 568      // Build the list of non-munged extensions.
 569      // @todo: this should not be here. we need to figure out the right place.
 570      $extensions = '';
 571      foreach ($user->roles as $rid => $name) {
 572        $extensions .= ' '. variable_get("upload_extensions_$rid",
 573        variable_get('upload_extensions_default', 'jpg jpeg gif png txt html doc xls pdf ppt pps odt ods odp'));
 574      }
 575  
 576      // Begin building file object.
 577      $file = new stdClass();
 578      $file->filename = file_munge_filename(trim(basename($_FILES['files']['name'][$source]), '.'), $extensions);
 579      $file->filepath = $_FILES['files']['tmp_name'][$source];
 580      $file->filemime = file_get_mimetype($file->filename);
 581  
 582      // If the destination is not provided, or is not writable, then use the
 583      // temporary directory.
 584      if (empty($dest) || file_check_path($dest) === FALSE) {
 585        $dest = file_directory_temp();
 586      }
 587  
 588      $file->source = $source;
 589      $file->destination = file_destination(file_create_path($dest .'/'. $file->filename), $replace);
 590      $file->filesize = $_FILES['files']['size'][$source];
 591  
 592      // Call the validation functions.
 593      $errors = array();
 594      foreach ($validators as $function => $args) {
 595        array_unshift($args, $file);
 596        // Make sure $file is passed around by reference.
 597        $args[0] = &$file;
 598        $errors = array_merge($errors, call_user_func_array($function, $args));
 599      }
 600  
 601      // Rename potentially executable files, to help prevent exploits.
 602      if (preg_match('/\.(php|pl|py|cgi|asp|js)$/i', $file->filename) && (substr($file->filename, -4) != '.txt')) {
 603        $file->filemime = 'text/plain';
 604        $file->filepath .= '.txt';
 605        $file->filename .= '.txt';
 606        // As the file may be named example.php.txt, we need to munge again to
 607        // convert to example.php_.txt, then create the correct destination.
 608        $file->filename = file_munge_filename($file->filename, $extensions);
 609        $file->destination = file_destination(file_create_path($dest .'/'. $file->filename), $replace);
 610      }
 611  
 612  
 613      // Check for validation errors.
 614      if (!empty($errors)) {
 615        $message = t('The selected file %name could not be uploaded.', array('%name' => $file->filename));
 616        if (count($errors) > 1) {
 617          $message .= '<ul><li>'. implode('</li><li>', $errors) .'</li></ul>';
 618        }
 619        else {
 620          $message .= ' '. array_pop($errors);
 621        }
 622        form_set_error($source, $message);
 623        return 0;
 624      }
 625  
 626      // Move uploaded files from PHP's upload_tmp_dir to Drupal's temporary directory.
 627      // This overcomes open_basedir restrictions for future file operations.
 628      $file->filepath = $file->destination;
 629      if (!move_uploaded_file($_FILES['files']['tmp_name'][$source], $file->filepath)) {
 630        form_set_error($source, t('File upload error. Could not move uploaded file.'));
 631        watchdog('file', 'Upload error. Could not move uploaded file %file to destination %destination.', array('%file' => $file->filename, '%destination' => $file->filepath));
 632        return 0;
 633      }
 634  
 635      // If we made it this far it's safe to record this file in the database.
 636      $file->uid = $user->uid;
 637      $file->status = FILE_STATUS_TEMPORARY;
 638      $file->timestamp = time();
 639      drupal_write_record('files', $file);
 640  
 641      // Add file to the cache.
 642      $upload_cache[$source] = $file;
 643      return $file;
 644    }
 645    return 0;
 646  }
 647  
 648  /**
 649   * Check for files with names longer than we can store in the database.
 650   *
 651   * @param $file
 652   *   A Drupal file object.
 653   * @return
 654   *   An array. If the file name is too long, it will contain an error message.
 655   */
 656  function file_validate_name_length($file) {
 657    $errors = array();
 658  
 659    if (strlen($file->filename) > 255) {
 660      $errors[] = t('Its name exceeds the 255 characters limit. Please rename the file and try again.');
 661    }
 662    return $errors;
 663  }
 664  
 665  /**
 666   * Check that the filename ends with an allowed extension. This check is not
 667   * enforced for the user #1.
 668   *
 669   * @param $file
 670   *   A Drupal file object.
 671   * @param $extensions
 672   *   A string with a space separated list of allowed file extensions, not
 673   *   including the period. For example, 'bmp jpg gif png'.
 674   *
 675   * @return
 676   *   An array. If the file extension is not allowed, it will contain an error
 677   *   message.
 678   */
 679  function file_validate_extensions($file, $extensions) {
 680    global $user;
 681  
 682    $errors = array();
 683  
 684    // Bypass validation for uid  = 1.
 685    if ($user->uid != 1) {
 686      $regex = '/\.('. @ereg_replace(' +', '|', preg_quote($extensions)) .')$/i';
 687      if (!preg_match($regex, $file->filename)) {
 688        $errors[] = t('Only files with the following extensions are allowed: %files-allowed.', array('%files-allowed' => $extensions));
 689      }
 690    }
 691    return $errors;
 692  }
 693  
 694  /**
 695   * Check that the file's size is below certain limits. This check is not
 696   * enforced for the user #1.
 697   *
 698   * @param $file
 699   *   A Drupal file object.
 700   * @param $file_limit
 701   *   An integer specifying the maximum file size in bytes. Zero indicates that
 702   *   no limit should be enforced.
 703   * @param $user_limit
 704   *   An integer specifying the maximum number of bytes the user is allowed. Zero
 705   *   indicates that no limit should be enforced.
 706   * @return
 707   *   An array. If the file size exceeds limits, it will contain an error message.
 708   */
 709  function file_validate_size($file, $file_limit = 0, $user_limit = 0) {
 710    global $user;
 711  
 712    $errors = array();
 713  
 714    // Bypass validation for uid  = 1.
 715    if ($user->uid != 1) {
 716      if ($file_limit && $file->filesize > $file_limit) {
 717        $errors[] = t('The file is %filesize exceeding the maximum file size of %maxsize.', array('%filesize' => format_size($file->filesize), '%maxsize' => format_size($file_limit)));
 718      }
 719  
 720      // Save a query by only calling file_space_used() when a limit is provided.
 721      if ($user_limit && (file_space_used($user->uid) + $file->filesize) > $user_limit) {
 722        $errors[] = t('The file is %filesize which would exceed your disk quota of %quota.', array('%filesize' => format_size($file->filesize), '%quota' => format_size($user_limit)));
 723      }
 724    }
 725    return $errors;
 726  }
 727  
 728  /**
 729   * Check that the file is recognized by image_get_info() as an image.
 730   *
 731   * @param $file
 732   *   A Drupal file object.
 733   * @return
 734   *   An array. If the file is not an image, it will contain an error message.
 735   */
 736  function file_validate_is_image(&$file) {
 737    $errors = array();
 738  
 739    $info = image_get_info($file->filepath);
 740    if (!$info || empty($info['extension'])) {
 741      $errors[] = t('Only JPEG, PNG and GIF images are allowed.');
 742    }
 743  
 744    return $errors;
 745  }
 746  
 747  /**
 748   * If the file is an image verify that its dimensions are within the specified
 749   * maximum and minimum dimensions. Non-image files will be ignored.
 750   *
 751   * @param $file
 752   *   A Drupal file object. This function may resize the file affecting its size.
 753   * @param $maximum_dimensions
 754   *   An optional string in the form WIDTHxHEIGHT e.g. '640x480' or '85x85'. If
 755   *   an image toolkit is installed the image will be resized down to these
 756   *   dimensions. A value of 0 indicates no restriction on size, so resizing
 757   *   will be attempted.
 758   * @param $minimum_dimensions
 759   *   An optional string in the form WIDTHxHEIGHT. This will check that the image
 760   *   meets a minimum size. A value of 0 indicates no restriction.
 761   * @return
 762   *   An array. If the file is an image and did not meet the requirements, it
 763   *   will contain an error message.
 764   */
 765  function file_validate_image_resolution(&$file, $maximum_dimensions = 0, $minimum_dimensions = 0) {
 766    $errors = array();
 767  
 768    // Check first that the file is an image.
 769    if ($info = image_get_info($file->filepath)) {
 770      if ($maximum_dimensions) {
 771        // Check that it is smaller than the given dimensions.
 772        list($width, $height) = explode('x', $maximum_dimensions);
 773        if ($info['width'] > $width || $info['height'] > $height) {
 774          // Try to resize the image to fit the dimensions.
 775          if (image_get_toolkit() && image_scale($file->filepath, $file->filepath, $width, $height)) {
 776            drupal_set_message(t('The image was resized to fit within the maximum allowed dimensions of %dimensions pixels.', array('%dimensions' => $maximum_dimensions)));
 777  
 778            // Clear the cached filesize and refresh the image information.
 779            clearstatcache();
 780            $info = image_get_info($file->filepath);
 781            $file->filesize = $info['file_size'];
 782          }
 783          else {
 784            $errors[] = t('The image is too large; the maximum dimensions are %dimensions pixels.', array('%dimensions' => $maximum_dimensions));
 785          }
 786        }
 787      }
 788  
 789      if ($minimum_dimensions) {
 790        // Check that it is larger than the given dimensions.
 791        list($width, $height) = explode('x', $minimum_dimensions);
 792        if ($info['width'] < $width || $info['height'] < $height) {
 793          $errors[] = t('The image is too small; the minimum dimensions are %dimensions pixels.', array('%dimensions' => $minimum_dimensions));
 794        }
 795      }
 796    }
 797  
 798    return $errors;
 799  }
 800  
 801  /**
 802   * Save a string to the specified destination.
 803   *
 804   * @param $data A string containing the contents of the file.
 805   * @param $dest A string containing the destination location.
 806   * @param $replace Replace behavior when the destination file already exists.
 807   *   - FILE_EXISTS_REPLACE - Replace the existing file
 808   *   - FILE_EXISTS_RENAME - Append _{incrementing number} until the filename is unique
 809   *   - FILE_EXISTS_ERROR - Do nothing and return FALSE.
 810   *
 811   * @return A string containing the resulting filename or 0 on error
 812   */
 813  function file_save_data($data, $dest, $replace = FILE_EXISTS_RENAME) {
 814    $temp = file_directory_temp();
 815    // On Windows, tempnam() requires an absolute path, so we use realpath().
 816    $file = tempnam(realpath($temp), 'file');
 817    if (!$fp = fopen($file, 'wb')) {
 818      drupal_set_message(t('The file could not be created.'), 'error');
 819      return 0;
 820    }
 821    fwrite($fp, $data);
 822    fclose($fp);
 823  
 824    if (!file_move($file, $dest, $replace)) {
 825      return 0;
 826    }
 827  
 828    return $file;
 829  }
 830  
 831  /**
 832   * Set the status of a file.
 833   *
 834   * @param $file 
 835   *   A Drupal file object.
 836   * @param $status
 837   *   A status value to set the file to. One of:
 838   *   - FILE_STATUS_PERMANENT
 839   *   - FILE_STATUS_TEMPORARY
 840   *
 841   * @return FALSE on failure, TRUE on success and $file->status will contain the
 842   *     status.
 843   */
 844  function file_set_status(&$file, $status) {
 845    if (db_query('UPDATE {files} SET status = %d WHERE fid = %d', $status, $file->fid)) {
 846      $file->status = $status;
 847      return TRUE;
 848    }
 849    return FALSE;
 850  }
 851  
 852  /**
 853   * Transfer file using http to client. Pipes a file through Drupal to the
 854   * client.
 855   *
 856   * @param $source File to transfer.
 857   * @param $headers An array of http headers to send along with file.
 858   */
 859  function file_transfer($source, $headers) {
 860    if (ob_get_level()) {
 861      ob_end_clean();
 862    }
 863    
 864    // IE cannot download private files because it cannot store files downloaded
 865    // over https in the browser cache. The problem can be solved by sending
 866    // custom headers to IE. See http://support.microsoft.com/kb/323308/en-us
 867    if (isset($_SERVER['HTTPS']) && ($_SERVER['HTTPS'] == 'on')) {
 868      drupal_set_header('Cache-Control: private');
 869      drupal_set_header('Pragma: private');
 870    }
 871  
 872    foreach ($headers as $header) {
 873      // To prevent HTTP header injection, we delete new lines that are
 874      // not followed by a space or a tab.
 875      // See http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2
 876      $header = preg_replace('/\r?\n(?!\t| )/', '', $header);
 877      drupal_set_header($header);
 878    }
 879  
 880    $source = file_create_path($source);
 881  
 882    // Transfer file in 1024 byte chunks to save memory usage.
 883    if ($fd = fopen($source, 'rb')) {
 884      while (!feof($fd)) {
 885        print fread($fd, 1024);
 886      }
 887      fclose($fd);
 888    }
 889    else {
 890      drupal_not_found();
 891    }
 892    exit();
 893  }
 894  
 895  /**
 896   * Call modules that implement hook_file_download() to find out if a file is
 897   * accessible and what headers it should be transferred with. If a module
 898   * returns -1 drupal_access_denied() will be returned. If one or more modules
 899   * returned headers the download will start with the returned headers. If no
 900   * modules respond drupal_not_found() will be returned.
 901   */
 902  function file_download() {
 903    // Merge remainder of arguments from GET['q'], into relative file path.
 904    $args = func_get_args();
 905    $filepath = implode('/', $args);
 906  
 907    // Maintain compatibility with old ?file=paths saved in node bodies.
 908    if (isset($_GET['file'])) {
 909      $filepath =  $_GET['file'];
 910    }
 911  
 912    if (file_exists(file_create_path($filepath))) {
 913      $headers = module_invoke_all('file_download', $filepath);
 914      if (in_array(-1, $headers)) {
 915        return drupal_access_denied();
 916      }
 917      if (count($headers)) {
 918        file_transfer($filepath, $headers);
 919      }
 920    }
 921    return drupal_not_found();
 922  }
 923  
 924  
 925  /**
 926   * Finds all files that match a given mask in a given directory.
 927   *
 928   * Directories and files beginning with a period are excluded; this
 929   * prevents hidden files and directories (such as SVN working directories)
 930   * from being scanned.
 931   *
 932   * @param $dir
 933   *   The base directory for the scan, without trailing slash.
 934   * @param $mask
 935   *   The regular expression of the files to find.
 936   * @param $nomask
 937   *   An array of files/directories to ignore.
 938   * @param $callback
 939   *   The callback function to call for each match.
 940   * @param $recurse
 941   *   When TRUE, the directory scan will recurse the entire tree
 942   *   starting at the provided directory.
 943   * @param $key
 944   *   The key to be used for the returned associative array of files. Possible
 945   *   values are "filename", for the path starting with $dir; "basename", for
 946   *   the basename of the file; and "name" for the name of the file without the
 947   *   extension.
 948   * @param $min_depth
 949   *   Minimum depth of directories to return files from.
 950   * @param $depth
 951   *   Current depth of recursion. This parameter is only used internally and
 952   *   should not be passed in.
 953   *
 954   * @return
 955   *   An associative array (keyed on the provided key) of objects with
 956   *   "filename", "basename", and "name" members corresponding to the
 957   *   matching files.
 958   */
 959  function file_scan_directory($dir, $mask, $nomask = array('.', '..', 'CVS'), $callback = 0, $recurse = TRUE, $key = 'filename', $min_depth = 0, $depth = 0) {
 960    $key = (in_array($key, array('filename', 'basename', 'name')) ? $key : 'filename');
 961    $files = array();
 962  
 963    if (is_dir($dir) && $handle = opendir($dir)) {
 964      while (FALSE !== ($file = readdir($handle))) {
 965        if (!in_array($file, $nomask) && $file[0] != '.') {
 966          if (is_dir("$dir/$file") && $recurse) {
 967            // Give priority to files in this folder by merging them in after any subdirectory files.
 968            $files = array_merge(file_scan_directory("$dir/$file", $mask, $nomask, $callback, $recurse, $key, $min_depth, $depth + 1), $files);
 969          }
 970          elseif ($depth >= $min_depth && @ereg($mask, $file)) {
 971            // Always use this match over anything already set in $files with the same $$key.
 972            $filename = "$dir/$file";
 973            $basename = basename($file);
 974            $name = substr($basename, 0, strrpos($basename, '.'));
 975            $files[$$key] = new stdClass();
 976            $files[$$key]->filename = $filename;
 977            $files[$$key]->basename = $basename;
 978            $files[$$key]->name = $name;
 979            if ($callback) {
 980              $callback($filename);
 981            }
 982          }
 983        }
 984      }
 985  
 986      closedir($handle);
 987    }
 988  
 989    return $files;
 990  }
 991  
 992  /**
 993   * Determine the default temporary directory.
 994   *
 995   * @return A string containing a temp directory.
 996   */
 997  function file_directory_temp() {
 998    $temporary_directory = variable_get('file_directory_temp', NULL);
 999  
1000    if (is_null($temporary_directory)) {
1001      $directories = array();
1002  
1003      // Has PHP been set with an upload_tmp_dir?
1004      if (ini_get('upload_tmp_dir')) {
1005        $directories[] = ini_get('upload_tmp_dir');
1006      }
1007  
1008      // Operating system specific dirs.
1009      if (substr(PHP_OS, 0, 3) == 'WIN') {
1010        $directories[] = 'c:\\windows\\temp';
1011        $directories[] = 'c:\\winnt\\temp';
1012        $path_delimiter = '\\';
1013      }
1014      else {
1015        $directories[] = '/tmp';
1016        $path_delimiter = '/';
1017      }
1018  
1019      foreach ($directories as $directory) {
1020        if (!$temporary_directory && is_dir($directory)) {
1021          $temporary_directory = $directory;
1022        }
1023      }
1024  
1025      // if a directory has been found, use it, otherwise default to 'files/tmp' or 'files\\tmp';
1026      $temporary_directory = $temporary_directory ? $temporary_directory : file_directory_path() . $path_delimiter .'tmp';
1027      variable_set('file_directory_temp', $temporary_directory);
1028    }
1029  
1030    return $temporary_directory;
1031  }
1032  
1033  /**
1034   * Determine the default 'files' directory.
1035   *
1036   * @return A string containing the path to Drupal's 'files' directory.
1037   */
1038  function file_directory_path() {
1039    return variable_get('file_directory_path', conf_path() .'/files');
1040  }
1041  
1042  /**
1043   * Determine the maximum file upload size by querying the PHP settings.
1044   *
1045   * @return
1046   *   A file size limit in bytes based on the PHP upload_max_filesize and post_max_size
1047   */
1048  function file_upload_max_size() {
1049    static $max_size = -1;
1050  
1051    if ($max_size < 0) {
1052      $upload_max = parse_size(ini_get('upload_max_filesize'));
1053      $post_max = parse_size(ini_get('post_max_size'));
1054      $max_size = ($upload_max < $post_max) ? $upload_max : $post_max;
1055    }
1056    return $max_size;
1057  }
1058  
1059  /**
1060   * Determine an Internet Media Type, or MIME type from a filename.
1061   *
1062   * @param $filename
1063   *   Name of the file, including extension.
1064   * @param $mapping
1065   *   An optional array of extension to media type mappings in the form
1066   *   'extension1|extension2|...' => 'type'.
1067   *
1068   * @return
1069   *   The internet media type registered for the extension or application/octet-stream for unknown extensions.
1070   */
1071  function file_get_mimetype($filename, $mapping = NULL) {
1072    if (!is_array($mapping)) {
1073      $mapping = variable_get('mime_extension_mapping', array(
1074        'ez' => 'application/andrew-inset',
1075        'atom' => 'application/atom',
1076        'atomcat' => 'application/atomcat+xml',
1077        'atomsrv' => 'application/atomserv+xml',
1078        'cap|pcap' => 'application/cap',
1079        'cu' => 'application/cu-seeme',
1080        'tsp' => 'application/dsptype',
1081        'spl' => 'application/x-futuresplash',
1082        'hta' => 'application/hta',
1083        'jar' => 'application/java-archive',
1084        'ser' => 'application/java-serialized-object',
1085        'class' => 'application/java-vm',
1086        'hqx' => 'application/mac-binhex40',
1087        'cpt' => 'image/x-corelphotopaint',
1088        'nb' => 'application/mathematica',
1089        'mdb' => 'application/msaccess',
1090        'doc|dot' => 'application/msword',
1091        'bin' => 'application/octet-stream',
1092        'oda' => 'application/oda',
1093        'ogg|ogx' => 'application/ogg',
1094        'pdf' => 'application/pdf',
1095        'key' => 'application/pgp-keys',
1096        'pgp' => 'application/pgp-signature',
1097        'prf' => 'application/pics-rules',
1098        'ps|ai|eps' => 'application/postscript',
1099        'rar' => 'application/rar',
1100        'rdf' => 'application/rdf+xml',
1101        'rss' => 'application/rss+xml',
1102        'rtf' => 'application/rtf',
1103        'smi|smil' => 'application/smil',
1104        'wpd' => 'application/wordperfect',
1105        'wp5' => 'application/wordperfect5.1',
1106        'xhtml|xht' => 'application/xhtml+xml',
1107        'xml|xsl' => 'application/xml',
1108        'zip' => 'application/zip',
1109        'cdy' => 'application/vnd.cinderella',
1110        'kml' => 'application/vnd.google-earth.kml+xml',
1111        'kmz' => 'application/vnd.google-earth.kmz',
1112        'xul' => 'application/vnd.mozilla.xul+xml',
1113        'xls|xlb|xlt' => 'application/vnd.ms-excel',
1114        'cat' => 'application/vnd.ms-pki.seccat',
1115        'stl' => 'application/vnd.ms-pki.stl',
1116        'ppt|pps' => 'application/vnd.ms-powerpoint',
1117        'odc' => 'application/vnd.oasis.opendocument.chart',
1118        'odb' => 'application/vnd.oasis.opendocument.database',
1119        'odf' => 'application/vnd.oasis.opendocument.formula',
1120        'odg' => 'application/vnd.oasis.opendocument.graphics',
1121        'otg' => 'application/vnd.oasis.opendocument.graphics-template',
1122        'odi' => 'application/vnd.oasis.opendocument.image',
1123        'odp' => 'application/vnd.oasis.opendocument.presentation',
1124        'otp' => 'application/vnd.oasis.opendocument.presentation-template',
1125        'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
1126        'ots' => 'application/vnd.oasis.opendocument.spreadsheet-template',
1127        'odt' => 'application/vnd.oasis.opendocument.text',
1128        'odm' => 'application/vnd.oasis.opendocument.text-master',
1129        'ott' => 'application/vnd.oasis.opendocument.text-template',
1130        'oth' => 'application/vnd.oasis.opendocument.text-web',
1131        'docm' => 'application/vnd.ms-word.document.macroEnabled.12',
1132        'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
1133        'dotm' => 'application/vnd.ms-word.template.macroEnabled.12',
1134        'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
1135        'potm' => 'application/vnd.ms-powerpoint.template.macroEnabled.12',
1136        'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template',
1137        'ppam' => 'application/vnd.ms-powerpoint.addin.macroEnabled.12',
1138        'ppsm' => 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12',
1139        'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
1140        'pptm' => 'application/vnd.ms-powerpoint.presentation.macroEnabled.12',
1141        'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
1142        'xlam' => 'application/vnd.ms-excel.addin.macroEnabled.12',
1143        'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',
1144        'xlsm' => 'application/vnd.ms-excel.sheet.macroEnabled.12',
1145        'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
1146        'xltm' => 'application/vnd.ms-excel.template.macroEnabled.12',
1147        'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
1148        'cod' => 'application/vnd.rim.cod',
1149        'mmf' => 'application/vnd.smaf',
1150        'sdc' => 'application/vnd.stardivision.calc',
1151        'sds' => 'application/vnd.stardivision.chart',
1152        'sda' => 'application/vnd.stardivision.draw',
1153        'sdd' => 'application/vnd.stardivision.impress',
1154        'sdf' => 'application/vnd.stardivision.math',
1155        'sdw' => 'application/vnd.stardivision.writer',
1156        'sgl' => 'application/vnd.stardivision.writer-global',
1157        'sxc' => 'application/vnd.sun.xml.calc',
1158        'stc' => 'application/vnd.sun.xml.calc.template',
1159        'sxd' => 'application/vnd.sun.xml.draw',
1160        'std' => 'application/vnd.sun.xml.draw.template',
1161        'sxi' => 'application/vnd.sun.xml.impress',
1162        'sti' => 'application/vnd.sun.xml.impress.template',
1163        'sxm' => 'application/vnd.sun.xml.math',
1164        'sxw' => 'application/vnd.sun.xml.writer',
1165        'sxg' => 'application/vnd.sun.xml.writer.global',
1166        'stw' => 'application/vnd.sun.xml.writer.template',
1167        'sis' => 'application/vnd.symbian.install',
1168        'vsd' => 'application/vnd.visio',
1169        'wbxml' => 'application/vnd.wap.wbxml',
1170        'wmlc' => 'application/vnd.wap.wmlc',
1171        'wmlsc' => 'application/vnd.wap.wmlscriptc',
1172        'wk' => 'application/x-123',
1173        '7z' => 'application/x-7z-compressed',
1174        'abw' => 'application/x-abiword',
1175        'dmg' => 'application/x-apple-diskimage',
1176        'bcpio' => 'application/x-bcpio',
1177        'torrent' => 'application/x-bittorrent',
1178        'cab' => 'application/x-cab',
1179        'cbr' => 'application/x-cbr',
1180        'cbz' => 'application/x-cbz',
1181        'cdf' => 'application/x-cdf',
1182        'vcd' => 'application/x-cdlink',
1183        'pgn' => 'application/x-chess-pgn',
1184        'cpio' => 'application/x-cpio',
1185        'csh' => 'text/x-csh',
1186        'deb|udeb' => 'application/x-debian-package',
1187        'dcr|dir|dxr' => 'application/x-director',
1188        'dms' => 'application/x-dms',
1189        'wad' => 'application/x-doom',
1190        'dvi' => 'application/x-dvi',
1191        'rhtml' => 'application/x-httpd-eruby',
1192        'flac' => 'application/x-flac',
1193        'pfa|pfb|gsf|pcf|pcf.Z' => 'application/x-font',
1194        'mm' => 'application/x-freemind',
1195        'gnumeric' => 'application/x-gnumeric',
1196        'sgf' => 'application/x-go-sgf',
1197        'gcf' => 'application/x-graphing-calculator',
1198        'gtar|tgz|taz' => 'application/x-gtar',
1199        'hdf' => 'application/x-hdf',
1200        'phtml|pht|php' => 'application/x-httpd-php',
1201        'phps' => 'application/x-httpd-php-source',
1202        'php3' => 'application/x-httpd-php3',
1203        'php3p' => 'application/x-httpd-php3-preprocessed',
1204        'php4' => 'application/x-httpd-php4',
1205        'ica' => 'application/x-ica',
1206        'ins|isp' => 'application/x-internet-signup',
1207        'iii' => 'application/x-iphone',
1208        'iso' => 'application/x-iso9660-image',
1209        'jnlp' => 'application/x-java-jnlp-file',
1210        'js' => 'application/x-javascript',
1211        'jmz' => 'application/x-jmol',
1212        'chrt' => 'application/x-kchart',
1213        'kil' => 'application/x-killustrator',
1214        'skp|skd|skt|skm' => 'application/x-koan',
1215        'kpr|kpt' => 'application/x-kpresenter',
1216        'ksp' => 'application/x-kspread',
1217        'kwd|kwt' => 'application/x-kword',
1218        'latex' => 'application/x-latex',
1219        'lha' => 'application/x-lha',
1220        'lyx' => 'application/x-lyx',
1221        'lzh' => 'application/x-lzh',
1222        'lzx' => 'application/x-lzx',
1223        'frm|maker|frame|fm|fb|book|fbdoc' => 'application/x-maker',
1224        'mif' => 'application/x-mif',
1225        'wmd' => 'application/x-ms-wmd',
1226        'wmz' => 'application/x-ms-wmz',
1227        'com|exe|bat|dll' => 'application/x-msdos-program',
1228        'msi' => 'application/x-msi',
1229        'nc' => 'application/x-netcdf',
1230        'pac' => 'application/x-ns-proxy-autoconfig',
1231        'nwc' => 'application/x-nwc',
1232        'o' => 'application/x-object',
1233        'oza' => 'application/x-oz-application',
1234        'p7r' => 'application/x-pkcs7-certreqresp',
1235        'crl' => 'application/x-pkcs7-crl',
1236        'pyc|pyo' => 'application/x-python-code',
1237        'qtl' => 'application/x-quicktimeplayer',
1238        'rpm' => 'application/x-redhat-package-manager',
1239        'sh' => 'text/x-sh',
1240        'shar' => 'application/x-shar',
1241        'swf|swfl' => 'application/x-shockwave-flash',
1242        'sit|sitx' => 'application/x-stuffit',
1243        'sv4cpio' => 'application/x-sv4cpio',
1244        'sv4crc' => 'application/x-sv4crc',
1245        'tar' => 'application/x-tar',
1246        'tcl' => 'application/x-tcl',
1247        'gf' => 'application/x-tex-gf',
1248        'pk' => 'application/x-tex-pk',
1249        'texinfo|texi' => 'application/x-texinfo',
1250        '~|%|bak|old|sik' => 'application/x-trash',
1251        't|tr|roff' => 'application/x-troff',
1252        'man' => 'application/x-troff-man',
1253        'me' => 'application/x-troff-me',
1254        'ms' => 'application/x-troff-ms',
1255        'ustar' => 'application/x-ustar',
1256        'src' => 'application/x-wais-source',
1257        'wz' => 'application/x-wingz',
1258        'crt' => 'application/x-x509-ca-cert',
1259        'xcf' => 'application/x-xcf',
1260        'fig' => 'application/x-xfig',
1261        'xpi' => 'application/x-xpinstall',
1262        'au|snd' => 'audio/basic',
1263        'mid|midi|kar' => 'audio/midi',
1264        'mpga|mpega|mp2|mp3|m4a' => 'audio/mpeg',
1265        'f4a|f4b' => 'audio/mp4',
1266        'm3u' => 'audio/x-mpegurl',
1267        'oga|spx' => 'audio/ogg',
1268        'sid' => 'audio/prs.sid',
1269        'aif|aiff|aifc' => 'audio/x-aiff',
1270        'gsm' => 'audio/x-gsm',
1271        'wma' => 'audio/x-ms-wma',
1272        'wax' => 'audio/x-ms-wax',
1273        'ra|rm|ram' => 'audio/x-pn-realaudio',
1274        'ra' => 'audio/x-realaudio',
1275        'pls' => 'audio/x-scpls',
1276        'sd2' => 'audio/x-sd2',
1277        'wav' => 'audio/x-wav',
1278        'alc' => 'chemical/x-alchemy',
1279        'cac|cache' => 'chemical/x-cache',
1280        'csf' => 'chemical/x-cache-csf',
1281        'cbin|cascii|ctab' => 'chemical/x-cactvs-binary',
1282        'cdx' => 'chemical/x-cdx',
1283        'cer' => 'chemical/x-cerius',
1284        'c3d' => 'chemical/x-chem3d',
1285        'chm' => 'chemical/x-chemdraw',
1286        'cif' => 'chemical/x-cif',
1287        'cmdf' => 'chemical/x-cmdf',
1288        'cml' => 'chemical/x-cml',
1289        'cpa' => 'chemical/x-compass',
1290        'bsd' => 'chemical/x-crossfire',
1291        'csml|csm' => 'chemical/x-csml',
1292        'ctx' => 'chemical/x-ctx',
1293        'cxf|cef' => 'chemical/x-cxf',
1294        'emb|embl' => 'chemical/x-embl-dl-nucleotide',
1295        'spc' => 'chemical/x-galactic-spc',
1296        'inp|gam|gamin' => 'chemical/x-gamess-input',
1297        'fch|fchk' => 'chemical/x-gaussian-checkpoint',
1298        'cub' => 'chemical/x-gaussian-cube',
1299        'gau|gjc|gjf' => 'chemical/x-gaussian-input',
1300        'gal' => 'chemical/x-gaussian-log',
1301        'gcg' => 'chemical/x-gcg8-sequence',
1302        'gen' => 'chemical/x-genbank',
1303        'hin' => 'chemical/x-hin',
1304        'istr|ist' => 'chemical/x-isostar',
1305        'jdx|dx' => 'chemical/x-jcamp-dx',
1306        'kin' => 'chemical/x-kinemage',
1307        'mcm' => 'chemical/x-macmolecule',
1308        'mmd|mmod' => 'chemical/x-macromodel-input',
1309        'mol' => 'chemical/x-mdl-molfile',
1310        'rd' => 'chemical/x-mdl-rdfile',
1311        'rxn' => 'chemical/x-mdl-rxnfile',
1312        'sd|sdf' => 'chemical/x-mdl-sdfile',
1313        'tgf' => 'chemical/x-mdl-tgf',
1314        'mcif' => 'chemical/x-mmcif',
1315        'mol2' => 'chemical/x-mol2',
1316        'b' => 'chemical/x-molconn-Z',
1317        'gpt' => 'chemical/x-mopac-graph',
1318        'mop|mopcrt|mpc|dat|zmt' => 'chemical/x-mopac-input',
1319        'moo' => 'chemical/x-mopac-out',
1320        'mvb' => 'chemical/x-mopac-vib',
1321        'asn' => 'chemical/x-ncbi-asn1-spec',
1322        'prt|ent' => 'chemical/x-ncbi-asn1-ascii',
1323        'val|aso' => 'chemical/x-ncbi-asn1-binary',
1324        'pdb|ent' => 'chemical/x-pdb',
1325        'ros' => 'chemical/x-rosdal',
1326        'sw' => 'chemical/x-swissprot',
1327        'vms' => 'chemical/x-vamas-iso14976',
1328        'vmd' => 'chemical/x-vmd',
1329        'xtel' => 'chemical/x-xtel',
1330        'xyz' => 'chemical/x-xyz',
1331        'gif' => 'image/gif',
1332        'ief' => 'image/ief',
1333        'jpeg|jpg|jpe' => 'image/jpeg',
1334        'pcx' => 'image/pcx',
1335        'png' => 'image/png',
1336        'svg|svgz' => 'image/svg+xml',
1337        'tiff|tif' => 'image/tiff',
1338        'djvu|djv' => 'image/vnd.djvu',
1339        'wbmp' => 'image/vnd.wap.wbmp',
1340        'ras' => 'image/x-cmu-raster',
1341        'cdr' => 'image/x-coreldraw',
1342        'pat' => 'image/x-coreldrawpattern',
1343        'cdt' => 'image/x-coreldrawtemplate',
1344        'ico' => 'image/x-icon',
1345        'art' => 'image/x-jg',
1346        'jng' => 'image/x-jng',
1347        'bmp' => 'image/x-ms-bmp',
1348        'psd' => 'image/x-photoshop',
1349        'pnm' => 'image/x-portable-anymap',
1350        'pbm' => 'image/x-portable-bitmap',
1351        'pgm' => 'image/x-portable-graymap',
1352        'ppm' => 'image/x-portable-pixmap',
1353        'rgb' => 'image/x-rgb',
1354        'xbm' => 'image/x-xbitmap',
1355        'xpm' => 'image/x-xpixmap',
1356        'xwd' => 'image/x-xwindowdump',
1357        'eml' => 'message/rfc822',
1358        'igs|iges' => 'model/iges',
1359        'msh|mesh|silo' => 'model/mesh',
1360        'wrl|vrml' => 'model/vrml',
1361        'ics|icz' => 'text/calendar',
1362        'css' => 'text/css',
1363        'csv' => 'text/csv',
1364        '323' => 'text/h323',
1365        'html|htm|shtml' => 'text/html',
1366        'uls' => 'text/iuls',
1367        'mml' => 'text/mathml',
1368        'asc|txt|text|pot' => 'text/plain',
1369        'rtx' => 'text/richtext',
1370        'sct|wsc' => 'text/scriptlet',
1371        'tm|ts' => 'text/texmacs',
1372        'tsv' => 'text/tab-separated-values',
1373        'jad' => 'text/vnd.sun.j2me.app-descriptor',
1374        'wml' => 'text/vnd.wap.wml',
1375        'wmls' => 'text/vnd.wap.wmlscript',
1376        'bib' => 'text/x-bibtex',
1377        'boo' => 'text/x-boo',
1378        'h++|hpp|hxx|hh' => 'text/x-c++hdr',
1379        'c++|cpp|cxx|cc' => 'text/x-c++src',
1380        'h' => 'text/x-chdr',
1381        'htc' => 'text/x-component',
1382        'c' => 'text/x-csrc',
1383        'd' => 'text/x-dsrc',
1384        'diff|patch' => 'text/x-diff',
1385        'hs' => 'text/x-haskell',
1386        'java' => 'text/x-java',
1387        'lhs' => 'text/x-literate-haskell',
1388        'moc' => 'text/x-moc',
1389        'p|pas' => 'text/x-pascal',
1390        'gcd' => 'text/x-pcs-gcd',
1391        'pl|pm' => 'text/x-perl',
1392        'py' => 'text/x-python',
1393        'etx' => 'text/x-setext',
1394        'tcl|tk' => 'text/x-tcl',
1395        'tex|ltx|sty|cls' => 'text/x-tex',
1396        'vcs' => 'text/x-vcalendar',
1397        'vcf' => 'text/x-vcard',
1398        '3gp' => 'video/3gpp',
1399        'dl' => 'video/dl',
1400        'dif|dv' => 'video/dv',
1401        'fli' => 'video/fli',
1402        'gl' => 'video/gl',
1403        'mpeg|mpg|mpe' => 'video/mpeg',
1404        'mp4|f4v|f4p' => 'video/mp4',
1405        'flv' => 'video/x-flv',
1406        'ogv' => 'video/ogg',
1407        'qt|mov' => 'video/quicktime',
1408        'mxu' => 'video/vnd.mpegurl',
1409        'lsf|lsx' => 'video/x-la-asf',
1410        'mng' => 'video/x-mng',
1411        'asf|asx' => 'video/x-ms-asf',
1412        'wm' => 'video/x-ms-wm',
1413        'wmv' => 'video/x-ms-wmv',
1414        'wmx' => 'video/x-ms-wmx',
1415        'wvx' => 'video/x-ms-wvx',
1416        'avi' => 'video/x-msvideo',
1417        'movie' => 'video/x-sgi-movie',
1418        'ice' => 'x-conference/x-cooltalk',
1419        'sisx' => 'x-epoc/x-sisx-app',
1420        'vrm|vrml|wrl' => 'x-world/x-vrml',
1421        'xps' => 'application/vnd.ms-xpsdocument',
1422      ));
1423    }
1424    foreach ($mapping as $ext_preg => $mime_match) {
1425      if (preg_match('!\.('. $ext_preg .')$!i', $filename)) {
1426        return $mime_match;
1427      }
1428    }
1429  
1430    return 'application/octet-stream';
1431  }
1432  
1433  /**
1434   * @} End of "defgroup file".
1435   */


Generated: Mon Jul 9 18:01:44 2012 Cross-referenced by PHPXref 0.7