Search code examples
drupaldrupal-7fileapi

Uploading and saving a file programmatically to Drupal nodes


I am trying to create a node based on a custom form submission. Everything works great except for the images that get uploaded.

I can capture them fine and set them in the form object cache. When I pass the data into the function to create the node, I get this error:

"The specified file could not be copied, because no file by that name exists. Please check that you supplied the correct filename."

I also receive the error multiple times, despite only submitting one or two images at a time.

Here is the code I am using. $uploads is passed in and is an array of file objects returned from file_save_upload() in a previous step:

if (isset($uploads)) {
    foreach ($uploads as $upload) {
      if (isset($upload)) {
        $file = new stdClass;
        $file->uid = 1;
        $file->uri = $upload->filepath;
        $file->filemime = file_get_mimetype($upload->uri);
        $file->status = 1;  

        $file = file_copy($file, 'public://images');

        $node->field_image[$node->language][] = (array) $file;
      }
    }
  }

  node_save($node);

I also tried this:

if (isset($uploads)) {
    foreach ($uploads as $upload) {
        $upload->status = 1;  

        file_save($upload);

        $node->field_image[$node->language][] = (array) $upload;
      }
    }
  }

  node_save($node);

The second causes a duplicate key error in MySQL on the URI field. Both of these examples I saw in tutorials, but neither are working?


Solution

  • For Drupal 7, I played around with this quite a bit and found the best way (and only way that I've got working) was to use Entity metadata wrappers

    I used a managed file form element like so:

      // Add file upload widget
      // Use the #managed_file FAPI element to upload a document.
      $form['response_document'] = array(
        '#title' => t('Attach a response document'),
        '#type' => 'managed_file',
        '#description' => t('Please use the Choose file button to attach a response document<br><strong>Allowed extensions: pdf doc docx</strong>.'),
        '#upload_validators' => array('file_validate_extensions' => array('pdf doc docx')),
        '#upload_location' => 'public://my_destination/response_documents/',
      );
    

    I also pass along the $node object in my form as a value

    $form['node'] = array('#type' => 'value', '#value' => $node);
    

    Then in my submission handler I simply do the following:

      $values = $form_state['values'];
      $node = $values['node'];
      // Load the file and save it as a permanent file, attach it to our $node.
      $file = file_load($values['response_document']);
      if ($file) {
        $file->status = FILE_STATUS_PERMANENT;
        file_save($file);
    
        // Attach the file to the node.
        $wrapper = entity_metadata_wrapper('node', $node);
        $wrapper->field_response_files[] = array(
          'fid' => $file->fid,
          'display' => TRUE,
          'description' => $file->filename,
        );
        node_save($node);
      }