Definition

file_save_upload($source, $validators = array(), $destination = FALSE, $replace = FILE_EXISTS_RENAME)
drupal/includes/file.inc, line 801

Description

Saves a file upload to a new location.

The file will be added to the files table as a temporary file. Temporary files are periodically cleaned. To make the file a permanent file call assign the status and use file_save() to save it.

Parameters

$source A string specifying the name of the upload field to save.

$validators An optional, associative array of callback functions used to validate the file. See @file_validate for a full discussion of the array format.

$destination A string containing the directory $source should be copied to. If this is not provided or is not writable, the temporary directory will be used.

$replace A boolean indicating whether an existing file of the same name in the destination directory should overwritten. A false value will generate a new, unique filename in the destination directory.

Return value

An object containing the file information, or FALSE in the event of an error.

Related topics

Namesort iconDescription
File interfaceCommon file handling functions.

Code

function file_save_upload($source, $validators = array(), $destination = FALSE, $replace = FILE_EXISTS_RENAME) {
  global $user;
  static $upload_cache;

  // Return cached objects without processing since the file will have
  // already been processed and the paths in _FILES will be invalid.
  if (isset($upload_cache[$source])) {
    return $upload_cache[$source];
  }

  // Add in our check of the the file name length.
  $validators['file_validate_name_length'] = array();


  // If a file was uploaded, process it.
  if (isset($_FILES['files']['name'][$source]) && is_uploaded_file($_FILES['files']['tmp_name'][$source])) {
    // Check for file upload errors and return FALSE if a lower level system
    // error occurred.
    switch ($_FILES['files']['error'][$source]) {
      // @see http://php.net/manual/en/features.file-upload.errors.php
      case UPLOAD_ERR_OK:
        break;

      case UPLOAD_ERR_INI_SIZE:
      case UPLOAD_ERR_FORM_SIZE:
        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');
        return FALSE;

      case UPLOAD_ERR_PARTIAL:
      case UPLOAD_ERR_NO_FILE:
        drupal_set_message(t('The file %file could not be saved, because the upload did not complete.', array('%file' => $source)), 'error');
        return FALSE;

        // Unknown error
      default:
        drupal_set_message(t('The file %file could not be saved. An unknown error has occurred.', array('%file' => $source)), 'error');
        return FALSE;
    }

    // Build the list of non-munged extensions.
    // @todo: this should not be here. we need to figure out the right place.
    $extensions = '';
    foreach ($user->roles as $rid => $name) {
      $extensions .= ' ' . variable_get("upload_extensions_$rid",
      variable_get('upload_extensions_default', 'jpg jpeg gif png txt html doc xls pdf ppt pps odt ods odp'));
    }

    // Begin building file object.
    $file = new stdClass();
    $file->uid      = $user->uid;
    $file->status   = FILE_STATUS_TEMPORARY;
    $file->filename = file_munge_filename(trim(basename($_FILES['files']['name'][$source]), '.'), $extensions);
    $file->filepath = $_FILES['files']['tmp_name'][$source];
    $file->filemime = file_get_mimetype($file->filename);
    $file->filesize = $_FILES['files']['size'][$source];

    // Rename potentially executable files, to help prevent exploits.
    if (preg_match('/\.(php|pl|py|cgi|asp|js)$/i', $file->filename) && (substr($file->filename, -4) != '.txt')) {
      $file->filemime = 'text/plain';
      $file->filepath .= '.txt';
      $file->filename .= '.txt';
    }

    // If the destination is not provided, or is not writable, then use the
    // temporary directory.
    if (empty($destination) || file_check_path($destination) === FALSE) {
      $destination = file_directory_temp();
    }

    $file->source = $source;
    $file->destination = file_destination(file_create_path($destination . '/' . $file->filename), $replace);

    // Call the validation functions specified by this function's caller.
    $errors = file_validate($file, $validators);

    // Check for errors.
    if (!empty($errors)) {
      $message = t('The specified file %name could not be uploaded.', array('%name' => $file->filename));
      if (count($errors) > 1) {
        $message .= theme('item_list', $errors);
      }
      else {
        $message .= ' ' . array_pop($errors);
      }
      form_set_error($source, $message);
      return FALSE;
    }

    // Move uploaded files from PHP's upload_tmp_dir to Drupal's temporary
    // directory. This overcomes open_basedir restrictions for future file
    // operations.
    $file->filepath = $file->destination;
    if (!move_uploaded_file($_FILES['files']['tmp_name'][$source], $file->filepath)) {
      form_set_error($source, t('File upload error. Could not move uploaded file.'));
      watchdog('file', 'Upload error. Could not move uploaded file %file to destination %destination.', array('%file' => $file->filename, '%destination' => $file->filepath));
      return FALSE;
    }

    // If we made it this far it's safe to record this file in the database.
    if ($file = file_save($file)) {
      // Add file to the cache.
      $upload_cache[$source] = $file;
      return $file;
    }
  }
  return FALSE;
}