3

How do I programmatically add an image to a file field? I have an url/filepath of an image that I wish to upload. I have tried the following:

$newNode->field_profile_image[0]['value'] = 'http://www.mysite.com/default.gif';

But it does not seem to work.

I have also tried:

$newNode->field_profile_image[0]['value'] = 'sites/default/files/default.gif';

The file does not need to be external to the webiste. I am happy to have it anywhere on the site in question.

seanieb
  • 1,196
  • 2
  • 14
  • 36
Sally
  • 1,749
  • 7
  • 31
  • 39
  • Are you trying to add a default image to a field? If so, you can set that from CCK field's settings. – Koray Al Feb 14 '11 at 18:30

5 Answers5

3

You're probably going to have to use hook_nodeapi to set this correctly. You're going to want to modify it under the "Insert" operation. Make sure that you resave the node after you've added the required fields.

Drupal wants to map the image to an entry in the file table, so simply setting the URL will not work. First off, if it's a remote file, you can use the function listed in the Brightcove module on line 176, brightcove_remote_image, to grab the image and move it into your local directory.

Once the remote image is moved into place, you need to save it into the files table and then properly configure the node's property. I've done it in this method:

////// in NodeAPI /////
    case "insert":
        $node->field_image[0] = _mymod_create_filearray($image_url);
        node_save($node);

This writes the files record, and then returns a properly formatted image array.

///// mymod_create_filearray /////
function _mymod_create_filearray($remote_url){
  if ($file_temp = brightcove_remote_image($remote_url)) {
    $file = new stdClass();
    $file->filename = basename($file_temp);
    $file->filepath = $file_temp;
    $file->filemime = file_get_mimetype($file_temp);
    $file->filesize = filesize($file_temp);

    $file->uid = $uid;
    $file->status = FILE_STATUS_PERMANENT;
    $file->timestamp = time();
    drupal_write_record('files', $file);

    $file = array(
     'fid' => $file->fid,
      'title' => basename($file->filename),
      'filename' => $file->filename,
      'filepath' => $file->filepath,
      'filesize' => $file->filesize,
      'mimetype' => $mime,
      'description' => basename($file->filename),
      'list' => 1,
    );
    return $file;
  }
  else {
    return array();
  }
}

And that should do it. Let me know if you have any questions.

jacobangel
  • 6,896
  • 2
  • 34
  • 35
  • 2
    You might want to check the `field_file_save_file()` function from `field_file.inc` in the filefield module. It does pretty much what your function does, but adds field specific validation and some other niceties. – Henrik Opel Feb 14 '11 at 17:33
  • Oh, BTW, if the addition of the field is placed on the 'presave' operation of hook_nodeapi (instead of 'insert'), there is no need for the additional call to node_save, as it will happen together with the 'normal' node save operation already. – Henrik Opel Feb 14 '11 at 17:41
  • I'll check out that function. Also, regarding the presave, it's important to consider that insert is only run when the node has been created, where as presave is always run on node save. If the user wanted to overwrite the programatically added image, you'd need to adapt your logic using the presave method. – jacobangel Feb 22 '11 at 18:59
2

Check out my Answer to a similar question from a while ago, where I describe how we did pretty much exactly what you need (if I understood the problem correctly).

The main point is to use the field_file_save_file() function from the filefield module for attaching a file (during hook_nodeapi, on operation presave), which will do most of the work for you (more or less what jacobangel's '_mymod_create_filearray()' tries to do, but more tuned to filefields needs, including validation).

This assumes that the file already exists on the servers filesystem somewhere (usually in /tmp), and will correctly 'import' it into Drupal, with corresponding entries in the files table, etc. If you want to import files from remote URLs, you'll need to add the additional step of fetching them as a separate task/functionality first.

As mentioned in the answer linked above, I ended up using the code from the Remote File module as an example for a custom implementation, as we needed some project specific additions - maybe you can use it more directly for your purposes.

Community
  • 1
  • 1
Henrik Opel
  • 19,341
  • 1
  • 48
  • 64
1

using nodeapi you should be able to set the value like you are trying to in the code example, but only or local images. You will most likely need to have the images in the "files" folder in your drupal install, but if that is set up everything else should work without a hitch. When using the nodeapi all the things that would normally happen when you save a node using a form would happen, such as updating the files table etc.

If you wanted to pull the image from the remote site using a module like feeds make it possible to pull the remote images, and create nodes. Depending on your use case you could either use it, or take a look at how it pulls the images and maps them to local files.

mirzu
  • 1,831
  • 2
  • 13
  • 15
  • @mirzu Thanks, I use this method for other field types, but have never done filefield fields that way. You saved me a test. :) – mpdonadio Jan 26 '11 at 11:34
  • @mirzu so would this work: $newNode->field_profile_image[0]['value'] = '/sites/default/files/default.gif'; – Sally Feb 09 '11 at 14:49
  • I believe so. I would look at the code in feeds and particularly the image mapper, since I'm certain that it does exactly what you are trying to do: programicly create nodes with images, and looking at that code is going to answer this and your followup questions. – mirzu Feb 09 '11 at 17:13
  • I don't believe modifying the value works when saving the asset because the image field isn't expecting a 'value' parameter. I believe the value parameter is rendered upon display, but not during save. – jacobangel Feb 10 '11 at 15:42
0

What you try will not work. Drupal offers no way to handle remote files, without the use for a module. AFAIK there is no module that offers an API to upload remote files trough.

berkes
  • 26,996
  • 27
  • 115
  • 206
0

Here is a quick example taken from one of my projects.

  $node = new stdClass;
  $node->title = 'Example Callout';
  $node->type = 'wn_hp_callout';
  // Search examples directory to attach some images.
  $callouts_dir = drupal_get_path('module', 'wn_hp_callout').'/imgs/examples/';
  $callout_imgs = glob($callouts_dir.'*.{jpg,jpeg,png,gif}',GLOB_BRACE);
  // Now add the images and provide imagefield extended additional text.
  foreach($callout_imgs as $img) {
    $img_info = pathinfo($img);
    $field = field_file_save_file($img, array(), file_directory_path() .'/example_callouts/');
    if( !isset($field['data']) ) {
      $field['data'] = array();
    }
    $field['data']['title'] = ucwords(str_replace('_',' ',$img_info['filename']));
    $field['data']['alt'] = 'This is alt text.';
    $node->field_wn_hp_callout_image[] = $field;
   }
   $node = node_submit($node);
   node_save($node);
troynt
  • 1,900
  • 15
  • 21