Community Documentation

Programmatically creating nodes with ImageFields

Last updated January 8, 2009. Created by yched on December 17, 2007.
Edited by webchick, dopry. Log in to edit this page.

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

Needed file id for this to work

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.

ImageField seems to drop a subdirectory

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.

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

CCK upload fields and attachments

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);

<?php
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

D6 code

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

FileField

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:

<?php

$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
   
),
);
?>

Is this also supposed to

Is this also supposed to work in D6?

Drupal 6?

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>";

Did you get this working ?

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

Did you find a solution?

Same here

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

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

I have related response here:

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

This works for imagefield in Drupal 6

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

Thanks David, very clean :)

Thanks David, very clean :)

Level09 Studios
------------------
Simple Drupal Themes :
http://www.level09.net

Property Management Built with Drupal:
http://www.smsar.me

Creating a node with the Image module

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" />

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

<?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);
?>

Is it possible to insert a

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?

Only works for insert node for me

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.

Erlend Strømsvik
erlend@nymedia.no
Ny Media AS - www.nymedia.no

Limits on image sizes

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.

Of course

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! =)

I know how to save node and I

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?

Yevgeniy Kadatskiy | http://www.databasepublish.com

Do files need to sit under

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.

****Me and Drupal :)****
Clickbank IPN - Sell online or create a membership site with the largest affiliate network!
Review Critical - One of my sites

For D6

Check this out for D6
http://drupal.org/node/330421

****Me and Drupal :)****
Clickbank IPN - Sell online or create a membership site with the largest affiliate network!
Review Critical - One of my sites

imagefield_import

D7 Version

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);

Thanks for the snippit, I

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.

Thanks for the D7 code!

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!

Great, the D7 code works for me!

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

Laurens Meurs
Rotterdam, the Netherlands

file_save_data

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

When updating in Drupal 7

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);

Can anyone suggest the

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...?

You have to create a new,

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

About this page

Drupal version
Drupal 5.x

Structure Guide

Drupal’s online documentation is © 2000-2012 by the individual contributors and can be used in accordance with the Creative Commons License, Attribution-ShareAlike 2.0. PHP code is distributed under the GNU General Public License.