You are here

function filefield_source_remote_value in FileField Sources 6

Same name and namespace in other branches
  1. 7 sources/remote.inc \filefield_source_remote_value()

A #filefield_value_callback function.

1 string reference to 'filefield_source_remote_value'
filefield_source_remote_info in sources/remote.inc
Implements hook_filefield_source_info().

File

sources/remote.inc, line 112
A FileField extension to allow referencing of existing files.

Code

function filefield_source_remote_value($element, &$item) {
  if (isset($item['filefield_remote']['url']) && strlen($item['filefield_remote']['url']) > 0 && valid_url($item['filefield_remote']['url']) && $item['filefield_remote']['url'] != FILEFIELD_SOURCE_REMOTE_HINT_TEXT) {
    $field = content_fields($element['#field_name'], $element['#type_name']);
    $url = $item['filefield_remote']['url'];

    // Check that the temporary directory is writable.
    $temporary_directory = file_directory_temp();
    if (!field_file_check_directory($temporary_directory, FILE_MODIFY_PERMISSIONS, $item['filefield_remote']['url'])) {
      return;
    }

    // Check that the destination is writable.
    $directory = filefield_widget_file_path($field);
    if (!field_file_check_directory($directory, FILE_CREATE_DIRECTORY, $item['filefield_remote']['url'])) {
      return;
    }

    // Check the headers to make sure it exists and is within the allowed size.
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_HEADER, TRUE);
    curl_setopt($ch, CURLOPT_NOBODY, TRUE);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
    curl_setopt($ch, CURLOPT_HEADERFUNCTION, '_filefield_source_remote_parse_header');

    // Causes a warning if PHP safe mode is on.
    @curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);
    curl_exec($ch);
    $info = curl_getinfo($ch);
    if ($info['http_code'] != 200) {
      curl_setopt($ch, CURLOPT_HTTPGET, TRUE);
      $file_contents = curl_exec($ch);
      $info = curl_getinfo($ch);
    }
    curl_close($ch);
    if ($info['http_code'] != 200) {
      switch ($info['http_code']) {
        case 403:
          form_error($element, t('The remote file could not be transferred because access to the file was denied.'));
          break;
        case 404:
          form_error($element, t('The remote file could not be transferred because it was not found.'));
          break;
        default:
          form_error($element, t('The remote file could not be transferred due to an HTTP error (@code).', array(
            '@code' => $info['http_code'],
          )));
      }
      return;
    }

    // Update the $url variable to reflect any redirects.
    $url = $info['url'];
    $url_info = parse_url($url);

    // Determine the proper filename by reading the filename given in the
    // Content-Disposition header. If the server fails to send this header,
    // fall back on the basename of the URL.
    //
    // We prefer to use the Content-Disposition header, because we can then
    // use URLs like http://example.com/get_file/23 which would otherwise be
    // rejected because the URL basename lacks an extension.
    $filename = _filefield_source_remote_filename();
    if (empty($filename)) {
      $filename = rawurldecode(basename($url_info['path']));
    }
    $pathinfo = pathinfo($filename);
    $filename = filefield_sources_clean_filename($filename);
    $filepath = file_create_filename($filename, $temporary_directory);
    if (empty($pathinfo['extension'])) {
      form_error($element, t('The remote URL must be a file and have an extension.'));
      return;
    }

    // Perform basic extension check on the file before trying to transfer.
    $extensions = $field['widget']['file_extensions'];
    $regex = '/\\.(' . preg_replace('/[ +]/', '|', preg_quote($extensions)) . ')$/i';
    if (!empty($extensions) && !preg_match($regex, $filename)) {
      form_error($element, t('Only files with the following extensions are allowed: %files-allowed.', array(
        '%files-allowed' => $extensions,
      )));
      return;
    }

    // Check file size based off of header information.
    if (!empty($element['#upload_validators']['filefield_validate_size'][0])) {
      $max_size = $element['#upload_validators']['filefield_validate_size'][0];
      $file_size = $info['download_content_length'];
      if ($file_size > $max_size) {
        form_error($element, t('The remote file is %filesize exceeding the maximum file size of %maxsize.', array(
          '%filesize' => format_size($file_size),
          '%maxsize' => format_size($max_size),
        )));
        return;
      }
    }

    // Set progress bar information.
    $options = array(
      'key' => $element['#type_name'] . '_' . $element['#field_name'] . '_' . $element['#delta'],
      'filepath' => $filepath,
    );
    filefield_source_remote_set_transfer_options($options);
    $transfer_success = FALSE;

    // If we've already downloaded the entire file because the header-retrieval
    // failed, just ave the contents we have.
    if (isset($file_contents)) {
      if ($fp = @fopen($filepath, 'w')) {
        fwrite($fp, $file_contents);
        fclose($fp);
        $transfer_success = TRUE;
      }
    }
    else {
      $ch = curl_init();
      curl_setopt($ch, CURLOPT_URL, $url);
      curl_setopt($ch, CURLOPT_HEADER, FALSE);
      curl_setopt($ch, CURLOPT_WRITEFUNCTION, 'filefield_source_remote_curl_write');

      // Causes a warning if PHP safe mode is on.
      @curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);
      $transfer_success = curl_exec($ch);
      curl_close($ch);
    }
    if ($transfer_success && ($file = field_file_save_file($filepath, $element['#upload_validators'], $directory))) {
      $item = array_merge($item, $file);
    }

    // Delete the temporary file.
    @unlink($filepath);
  }
}