Here's a snippet for programmatically creating nodes with imagefields:

<?php
  $node = new StdClass();
  $node->type = 'official_photo';
  $node->title = t('Sample official photo');
  $node->taxonomy[4] = 15; // Candid shots gallery
  $file_temp = file_get_contents('./profiles/multisite/files/official-photo.png');
  $file_temp = file_save_data($file_temp, file_directory_path() .'/official_photos/official-photo.png', FILE_EXISTS_RENAME);
  $node->field_photo = array(
    array(
      'fid' => 'upload',
      'title' => basename($file_temp),
      'filename' => basename($file_temp),
      'filepath' => $file_temp,
      'filesize' => filesize($file_temp),
    ),
  );
  $node->uid = 1;
  $node->status = 1;
  $node->active = 1;
  $node->promote = 1;
  node_save($node);
?>

You'll have to add the code for your other fields if any, obviously

Comments

jmlavarenne’s picture

I could not get this to work until I added

'fid' => 'upload' like this :

$node->field_the_name_of_the_field = array(
  array(
      'fid' => 'upload',
      'title' => basename($file_temp),
      'filename' => basename($file_temp),
      'filepath' => $file_temp,
      'filesize' => filesize($file_temp),
    ),
  );

As far as I can tell, this makes sure the files table is populated correctly.

eoneillPPH’s picture

Our script, using the code above, sends this to node_save:

//print_r($node->field___mt_photo) outputs
Array(
    [0] => Array
        (
            [fid] => upload
            [title] => 61539_aa.jpg
            [filename] => 61539_aa.jpg
            [filepath] => files/images/61539/61539_aa.jpg
            [filesize] => 137735
        )
)

And yet, after node save, what's happened is this:

//print_r($node->field___mt_photo) outputs
Array(
    [0] => Array
        (
            [fid] => 1530
            [title] => 61539_aa.jpg
            [filename] => 61539_aa.jpg
            [filepath] => files/images/61539_aa_2.jpg
            [filesize] => 137735
        )
)

The image has been uploaded to files/images/ instead of files/images/61539/. AND(!) it's a duplicate (_aa_2.jpg). And yet, on occasion, it DOES keep the numbered subdirectory... seemingly without rhyme or reason. Appears to me that one of the functions drops the last subdirectory. Since other images (not attached to any node) go in there BEFORE we run node_submit/node_save, we know the directory is writable. (I also have it print the result of 'is_writable' first, and the directories are always writable.) Another thing I do is retrieve the fid if it exists first, and if it does, I send that instead of fid=>upload, but since I search by the file path the image SHOULD be in, it comes back empty for these messed-up-path images.

I'm hoping someone may have an idea how to fix this problem, or even what the problem is.

dewparadise’s picture

Hi,
How can I change this to get it working in Drupal 6?

alex_b’s picture

This custom node_save() function uploads CCK fields or files as attachments (besides handling changed value and returning the node object when done).

Usage:

$form_values['title'] = 'Demo file and picture upload';
$form_values['files']['upload'] = array('http://example.com/path/to/file.pdf');
$form_values['field_my_image']['upload'] = array('http://example.com/path/to/image.png');
my_node_save('my_content_type', $form_values);
function my_node_save($node, $form_values = array()) {
  if (is_string($node)) {
    $node = array('type' => $node);
  }
  else {
    $node = (array) $node;
  }
  $form_id = $node['type'] .'_node_form';
  
  // If uid is set load user and fill in name.
  // To circumvent uid reset in node_submit().
  // @todo: roll patch for D7.
  if ($form_values['uid']) {
    $account = user_load(array('uid' => $form_values['uid']));
    $form_values['name'] = $account->name;
  }
  // Store changed date - we will set it manually at end of function.
  if ($form_values['changed']) {
    $changed = $form_values['changed'];
  }
  else if ($form_values['created']) {
    $changed = $form_values['created'];
  }
  // @todo: multiple file uploads not tested.
  foreach ($form_values as $field_name => $value) {
    if (is_array($value) && is_array($value['upload'])) {
      foreach ($value['upload'] as $upload) {
        if (!$file_data = file_get_contents($upload)) {
          drupal_set_message(t('Couldn\'t read file !url', array('!url' => $upload)), 'error');
          return FALSE;
        }
        if (!$file_temp = file_save_data($file_data, file_directory_path().'/'.basename($upload), FILE_EXISTS_RENAME)) {
          drupal_set_message(t('Couldn\'t save file.'), 'error');
          return FALSE;
        }
        $i = 0;
        $file = array(
          'fid' => 'upload_'. $i,
          'title' => basename($file_temp),
          'filename' => basename($file_temp),
          'filepath' => $file_temp,
          'filesize' => filesize($file_temp),
          'list' => 1, // always list
          'filemime' => mimedetect_mime($file_temp),
        );
        // File upload likes objects, others like arrays.
        $file = ($field_name == 'files') ? (object) $file : $file;
        $node[$field_name]['upload_'. $i] = $file;
        $i++;
      }
      unset($form_values[$field_name]);
    }
  }
  
  $path = explode('/', drupal_execute($form_id, $form_values, $node));
  if (is_numeric($path[1])) {
    $node = node_load($path[1]);
    // If changed present, set manually - node_save() set changed to time().
    if ($changed) {
      db_query('UPDATE {node} SET changed = %d WHERE nid = %d', $changed, $node->nid);
      $node->changed = $changed;
    }
    return $node;
  }
}

Twitter: http://twitter.com/lx_barth

pfournier’s picture

Above code did not work for me. Issue #292904: Mass import/upload? may help you in Drupal 6.

matteogeco’s picture

To attach a file in a "File" field (i.e. the field type supplied by FileField module) you have to add a "description" item to the field array, like this:

$node->field_file = array(
    array(
	'fid' => 'upload',
	'title' => basename($file_temp),
	'filename' => basename($file_temp),
	'filepath' => $file_temp,
	'filesize' => filesize($file_temp),
	'list' => 1, // always list
	'filemime' => mimedetect_mime($file_temp),
	'description' =>  basename($file_temp),// <-- add this
	),
);
trogie’s picture

Is this also supposed to work in D6?

wanderingstan’s picture

I too am having trouble getting this to work in Drupal 6. The node gets created, but the CCK image field is empty.

This is the code I'm using:

  $filepath = file_directory_path() . '/tmp/DSC00630.JPG';  
  $file_temp = file_get_contents($filepath);
  $file_temp = file_save_data($file_temp, file_directory_path() .'/' . $image_unique_id . '.jpg', FILE_EXISTS_RENAME);
  
  // Build the node.
  $node = new stdClass();
  $node->type = 'story';
  $node->uid = $user->uid;
  $node->name = $user->name;
  $node->title = 'Testing Node Creation ' . time();
  $node->body = 'Testing';
  $node->teaser = 'Testing';
  $node->status = 1;
  $node->active = 1;
  $node->promote = 1;
  $node->field_photo = array(
    array(
      'fid' => 'upload',
      'title' => basename($file_temp),
      'filename' => basename($file_temp),
      'filepath' => $file_temp,
      'filesize' => filesize($file_temp),
      'description' =>  basename($file_temp),
      'list' => 1,
    ),
  );
  node_save($node);
 
  print"<pre>";
  print_r($node);
  print"</pre>";
ianhaycox’s picture

I've been tearing my hair out for hours, but no luck.

Did you find a solution?

greg.harvey’s picture

And no luck with David's post below either. =(

dewparadise’s picture

Hi
what to change to get it working in drupal 6. I followed david's post but not working. anyhelp pls?

nathanjo’s picture

I have related response here: http://drupal.org/node/458778#comment-1653696

davidwhthomas’s picture

I uploaded the files to the dest in the files dir but I needed to associate them with the existing nodes.

Here's the code

<?php
function mymodule_attach_files(){
  // query the db for nodes of the selected type to attach files to
  $result = db_query("SELECT nid FROM {node} WHERE type = '%s'", 'supplies_equipment');
  // loop through result set
  while($row = db_fetch_object($result)){
    // load the node object
    $node = node_load($row->nid);
    // add uploaded images to node data structure
    // images exist in dest folder but need saving to node, check if matching file exists
    if(  file_exists( file_directory_path().'/images/supplies/'.$node->field_e_number[0]['value'].'.jpg' )){
      // path to existing file to attach to node
      // filename matches cck e-number field
      $image = file_directory_path().'/images/supplies/'.$node->field_e_number[0]['value'].'.jpg'; 
      // Load up the CCK field
      $field = content_fields('field_images', 'supplies_equipment');
      // Load up the appropriate validators
      $validators = array_merge(filefield_widget_upload_validators($field), imagefield_widget_upload_validators($field));
      // Where do we store the files?
      $files_path = filefield_widget_file_path($field);
      // Create the file object, replace existing file with new file as source and dest are the same
      $file = field_file_save_file($image, $validators, $files_path, FILE_EXISTS_REPLACE);
      // Apply the file to the field, this sets the first file only, could be looped
      $node->field_images = array(0 => $file); 
      // Save the node with image data
      node_save($node);
    }
  }
}
?>

hope it helps.

DT

level09’s picture

Thanks David, very clean :)

matbintang’s picture

I'm stuck trying to create the necessary array for the image_node_form.

Does anyone know what the array should contain.

<input type="file" name="files[image]"  class="form-file" id="edit-image" size="40" />
dewparadise’s picture

How can I chnage this code to get it working in Drupal 6

  $node = new StdClass();
  $node->type = 'official_photo';
  $node->title = t('Sample official photo');
  $node->taxonomy[4] = 15; // Candid shots gallery
  $file_temp = file_get_contents('./profiles/multisite/files/official-photo.png');
  $file_temp = file_save_data($file_temp, file_directory_path() .'/official_photos/official-photo.png', FILE_EXISTS_RENAME);
  $node->field_photo = array(
    array(
      'fid' => 'upload',
      'title' => basename($file_temp),
      'filename' => basename($file_temp),
      'filepath' => $file_temp,
      'filesize' => filesize($file_temp),
    ),
  );
  $node->uid = 1;
  $node->status = 1;
  $node->active = 1;
  $node->promote = 1;
  node_save($node);
jh3’s picture

Is it possible to insert a image title into each image node while using this snippet or something of the like? For example, along with the $file object, I would want a title and maybe alt text to be inserted with each object. Where would this information go?

erlendstromsvik’s picture

When working on a node which already exists, this function is called:
filefield_field_update($node, $field, &$items, $teaser, $page)
This one will delete every old image associated with the node and which is not present in it's third parameter.

MvdVelde’s picture

If it still doen't work, try adding the following piece of code:

<?php

// pretend we're saving the node from a node form to please modules like filefield_paths
          $node->form_id = $node->type .'_node_form';

?>

(taken from the imagefield_import module)

ngaur’s picture

I tried just about every code example on this page and others that I could find. Nothing worked. Just silent failure.

Eventually I realized that the images I was uploading were larger than the maximum file size I had set, and the automatic scaling down of images which would occur if I uploaded images through a web form was not being done.

So far I don't know the incantation to get drupal to scale the images as it imports them, and I think I'm just going to do it from the command line with ImageMagick.

I've been using drush to run my import script in drupal context. I'm thinking that if I'd been working through a web interface some error messages might have been displayed. Maybe there's some call I need to make to get the error messages that need displaying.

Any pointers on these issues much apreciated.

greg.harvey’s picture

Drupal always has to upload the image before it can act on it (e.g. process a resize), so if you set an image file size that is too restrictive then it will never get as far as resizing, because it will refuse the upload.

If your intention is to upload and resize a batch of images on the server, I would remove the file size restriction for the duration of the import and let Image Field do it's thing. Then reinstate the file size limit afterwards, if you are concerned users will upload silly-big files.

See ImageCache and ImageAPI modules for more powerful dynamic image manipulation options, including ImageMagick integration within Drupal.

Hope that helps! =)

furamag’s picture

I know how to save node and I need just to add image field to node before save it. I tried to use this part of code:

  $file_temp = file_get_contents('./profiles/multisite/files/official-photo.png');
  $file_temp = file_save_data($file_temp, file_directory_path() .'/official_photos/official-photo.png', FILE_EXISTS_RENAME);
  $node->field_photo = array(
    array(
      'fid' => 'upload',
      'title' => basename($file_temp),
      'filename' => basename($file_temp),
      'filepath' => $file_temp,
      'filesize' => filesize($file_temp),
    ),
  );

But every time when I use $_FILES['tmp_name']['image'] instead of "./profiles/multisite/files/official-photo.png" and $_FILES['name']['image'] instead of "/official_photos/official-photo.png" I have error "file_get_contents()... Filename cannot be empty". What I do wrong?

giorgio79’s picture

Do files need to sit under sites/default/files...?

Also, did anyone success with Filefield Paths module and programmatic CCK Image upload? For me it is not putting it in the path I set as default.

giorgio79’s picture

akaserer’s picture

guybedford’s picture

Here's a D7 Version

$path = './sites/default/files/test.jpg';
$filetitle = 'test';
$filename = 'test.jpg';

$node = new StdClass();

$file_temp = file_get_contents($path);
$file_temp = file_save_data($file_temp, 'public://' . $filename, FILE_EXISTS_RENAME);

$node->title = $filetitle;
$node->uid = 1;
$node->status = 1;
$node->type = '[content_type]';
$node->language = 'und';
$node->field_images = array(
    'und' => array(
        0 => array(
            'fid' => $file_temp->fid,
            'filename' => $file_temp->filename,
            'filemime' => $file_temp->filemime,
            'uid' => 1,
            'uri' => $file_temp->uri,
            'status' => 1
        )
    )
);
$node->field_taxonomy = array('und' => array(
    0 => array(
        'tid' => 76
    )
));
node_save($node);
m4olivei’s picture

Thanks for the snippit, I found that I needed to put a 'display' key set to 1 in the $node->field_images['und'][0] array, other than that, worked like a charm.

hermes_costell’s picture

+1
Also needed 'display' set to '1' (or at least have it not be NULL)

Heads-up: Drupal 7 will reach its End of Life on February 30th, 2517.

boregar’s picture

I used it in a loop to do a mass import of a huge amount of images.
It really saved me a lot of time!

drupalcms.ir’s picture

if you mean multiple upload please let me have the codes. thanks

lmeurs’s picture

Great, the D7 code works for me! Lovely that the images get resized automatically...

Laurens Meurs
wiedes.nl

funkeyrandy’s picture

the d7 version works perfect for me IF the file is in the drupal root directory...however, when i move the file to my modules folder, it says that the temp file could not be copied...

$path = './path-to-uploaded-image/'.$id;
$filetitle = 'test';
$filename = $id;
$file_temp = file_get_contents($path);
$file_temp = file_save_data($file_temp, 'public://' . $filename,
FILE_EXISTS_RENAME);

i suspect it has something to do with the public:// reference...so my question, is how do i get a file that exists in my module folder copied back to sites/default/files??

ive tried just about everything path and permissions wise that i can think of....again, this works fine if the script is in my drupal root

thanks!!!

r

richardp’s picture

I kept running into a problem when I would update an existing image field with my own rendered images, they'd get deleted off the file system as soon as I called node_save(). If I never called node_save(), it didn't get deleted.

What I had to do, was use the drupal function file_usage_add(). Check it out on drupal's API.

My code which works for D7, updating existing nodes:

  $file = ~~FUNCTION WHICH RETURNS NEW DRUPAL FILE OBJECT();
  
  // IMPORTANT!  If you don't do this, your file gets deleted.  Fun!
  file_usage_add($file, "MODULENAME", "node", $user->uid);
  
  // Save this file information into the node!   
  $node = node_load($nid);
  
  $node->field_upload_image['und'][0] = array(
    'fid' => $file->fid,
    'filename' => $file->filename,
    'filemime' => $file->filemime,
    'uid' => 1,
    'uri' => $file->uri,
    'status' => 1,
  );
  
  node_save($node);
jonodunnett’s picture

Can anyone suggest the correct way of making this (or any) php/drupal code execute? I can make a mypage.php but if I just run this some of the drupal code won't execute. Is there a "proper" place to execute scripts from?

This is probably a very basic question and it seems like it should be easy to do. Making a new module seems a bit overkill but perhaps that is the way...?

richardp’s picture

You have to create a new, custom module. It's basically just a PHP file, renamed to .module, so it can contain whatever PHP code you want. But in order to establish a "path" or URL for a function to run on, you also have to tinker with the hook_menu function.

You should try to find a beginner's guide to module development in Drupal. It isn't necessarily hard or difficult, but it's more involved than creating a simple PHP script.

Richard

andyhu’s picture

file_usage_add($file, "MODULENAME", "node", $user->uid);

Should it be $node->nid instead of $user->uid? Otherwise after the node has been deleted, the attached image will not be removed.
So it will be something like this:

file_usage_add($file, 'file', 'node', $node->nid);
Chim’s picture

Good spot, thanks for taking the time to point this out.

rinki.sharma’s picture

Hi all,
It is quite easy to add a node programmatically in Drupal 7. But it gets little bit complex when we need to add an image to this node as well. Here is one example of this.you can try

http://findnerd.com/list/view/Attaching-image-files-to-nodes-programmati...