Programmatically Attach Files to Node in Drupal 7

We may encounter with situations that require files to be attached to node programmatically rather than user uploads it. It will be the usual case if the file is generated by the system itself.

In this article we try to show how we can attach a PDF file to file field of a node. Assuming default file type field is used. Here are the steps of logic we going to follow.

  • Create a file object representing our physical file
  • Make it a managed file by calling file_save()
  • Fill file field with file's properties and fill field's other properties like display and description
  • Save the node to make attachment effective.

We have valid node object $node. Then we need to build a file object from its path.

// We have complete file path.
$file_path = '/whatever/path/to/file/sample.pdf';

$file = new stdClass;
$file->uid = $node->uid;
$file->filename = pathinfo($file_path, PATHINFO_BASENAME);
$file->uri = $file_path;
$file->filemime = file_get_mimetype($file_path);
// Make it permanent, otherwise it will get deleted later.
$file->status = FILE_STATUS_PERMANENT;

// Save file object to make it a 'managed file'.

// We will save file under this location.
$destination = 'public://PDFs/';

// Make sure destination directory exists before moving files to that path.
// This will create directory if it does not exists.
file_prepare_directory($destination, FILE_CREATE_DIRECTORY);

// Now attach file to the file field.
$node->field_pdf[$node->language][0] = (array) $file;

// Default file type field comes with this extra properties.
$node->field_pdf[$node->language][0]['display'] = 1;
$node->field_pdf[$node->language][0]['description'] = 'Our special PDF';

// Save node to make the attachment effective.

We can make the file private by changing the stream wrapper from 'public://' to 'private://'. That is, change value of $destination from 'public://PDFs/' to 'private://PDFs/'. Private files will be accessible only to users those have access to that node where file belongs. You must have configured your private directory in your Drupal. You can find that configuration at 'admin/config/media/file-system' page.