background image
HomeRecent PostsDrupalSearchTagsRSSContactAboutAccount

Upload an image using the Forms API and attach it to a image/file field in a CCK node

Eric.London's picture

In this tutorial I'll show you how to upload an image using the Forms API, create a new node, and attach the image to the CCK (filefield/imagefield) field. I wrote this code to work with the modules I primarily use for image processing: cck, filefield, imageapi, imagecache, imagefield, mimedetect, and transliteration.

After I installed those modules, I created a new node type (admin/content/types/add) called "Image" and added a single imagefield field.

Image node fields

Next, I created a custom module with a hook_menu() implementation:

<?php
// NOTE: this variable is used through the code,
// so I thought it would be better to put it in a constant
define('IMAGE_UPLOAD_CONTAINER', 'image_upload');

/**
* Implements hook_menu()
*/
function helper_menu() {

 
// create a blank array of menu items
 
$items = array();
 
 
// define page callback for upload form
  // NOTE: you'll want to restrict permission better [see: access arguments]
 
$items['upload'] = array(
   
'title' => t('Upload'),
   
'description' => t('Upload'),
   
'page callback' => 'drupal_get_form',
   
'page arguments' => array('helper_page_callback_upload_form'),
   
'access arguments' => array('access content'),
   
'type' => MENU_CALLBACK,
  );
 
 
// return menu items
 
return $items;

}
?>

I defined the form function page callback:

<?php
/**
* Implements page callback for upload form
*/
function helper_page_callback_upload_form() {

 
// create an empty form array
 
$form = array();
 
 
// set the form encoding type
 
$form['#attributes']['enctype'] = "multipart/form-data";
 
 
// add a file upload file
 
$form[IMAGE_UPLOAD_CONTAINER] = array(
   
'#type' => 'file',
   
'#title' => t('Upload an image'),
  );
  
 
// add a submit button
 
$form['submit'] = array(
   
'#type' => 'submit',
   
'#value' => 'Submit',
  );
 
 
// return form array
 
return $form;

}
?>

This page callback function results in the following form:

Image node form

Then I added the form validation and submit handler functions:

<?php
/**
* Implements form validation handler
*/
function helper_page_callback_upload_form_validate($form, &$form_state) {

 
// if a file was uploaded, process it.
 
if (isset($_FILES['files']) && is_uploaded_file($_FILES['files']['tmp_name'][IMAGE_UPLOAD_CONTAINER])) {

   
// validate file extension
    // NOTE: you can ellaborate on this code and add additional validation
   
if ($_FILES['files']['type'][IMAGE_UPLOAD_CONTAINER] != 'image/jpeg') {
     
form_set_error(IMAGE_UPLOAD_CONTAINER, 'Invalid file extension.');
      return;
    }

   
// attempt to save the uploaded file
   
$file = file_save_upload(IMAGE_UPLOAD_CONTAINER, array(), file_directory_path());

   
// set error if file was not uploaded
   
if (!$file) {
     
form_set_error(IMAGE_UPLOAD_CONTAINER, 'Error uploading file.');
      return;
    }
      
   
// set files to form_state, to process when form is submitted
   
$form_state['storage'][IMAGE_UPLOAD_CONTAINER] = $file;
      
  }
  else {
   
// set error
   
form_set_error(IMAGE_UPLOAD_CONTAINER, 'Error uploading file.');
    return;  
  }

}

/**
* Implements form submit handler
*/
function helper_page_callback_upload_form_submit($form, &$form_state) {
 
 
// create new node object
 
$new_node = (object) array(
   
'type' => 'image',
   
'uid' => $GLOBALS['user']->uid,
   
'name' => $GLOBALS['user']->name,
   
'title' => t('YOUR NODE TITLE'),
   
'status' => 1,
   
'field_image' => array(
      (array)
$form_state['storage'][IMAGE_UPLOAD_CONTAINER],
    ),
  );
   
 
// save node
 
node_save($new_node);
 
 
// clear form storage, to allow form to submit
 
$form_state['storage'] = array();
 
 
// redirect user, set message, etc!

}
?>

After using the form to upload an image, the following node was created:

New image node

Thank you. This article very

Thank you. This article very usefull for me.

Eric.London's picture

CCK Filefield file extension

Here's one way you could validate the file extension for a CCK filefield:

<?php
$field
= content_fields('field_YOURFIELD', 'YOUR_NODE_TYPE');
if (
strlen($field['widget']['file_extensions'])) {
 
$file_extensions = explode(' ', $field['widget']['file_extensions']);
  if (
count($file_extensions)) {
   
// get pathinfo
   
$path_info = pathinfo($_FILES['files']['name'][IMAGE_UPLOAD_CONTAINER]);
   
    if (!
in_array($path_info['extension'], $file_extensions)) {
     
form_set_error(IMAGE_UPLOAD_CONTAINER, 'Invalid file extension.');
      return;         
    }
   
  }
}
?>

download

Can I download this example as a module, for further learnig?
Thanks so much.

Great FAPI File Upload example

Thanks! This is the only file upload example I've found that works. Maybe I made mistakes with the others, either way this is a great post.

Curious though, why did you use custom validation instead of the file_validators? Are they problematic in some way?

It is a very handy tutorial

It is a very handy tutorial you have made here. No need to have a node form...
I have not read the whole article yet but, can this Form item be used in a block or in panels ?
And, is it possible to assign every uploaded Image to a single node ?
For example, once the node is created, every new upload creates a new Filefield instance in the exact same node. (if the Filefield is set to multiple)

Thank You

Thanks You...It is a very very good article...helped me a lot...

Regards,

Ashraf Mazumder

Eric.London's picture

yes

Yes, this code could be inserted into a module, block, form, etc.

It is possible to attach numerous files to a node, the node's field is an array which could contain numerous file objects [see bold]

// create new node object
$new_node = (object) array(
'type' => 'image',
'uid' => $GLOBALS['user']->uid,
'name' => $GLOBALS['user']->name,
'title' => t('YOUR NODE TITLE'),
'status' => 1,
'field_image' => array(
(array) $form_state['storage'][IMAGE_UPLOAD_CONTAINER],
),

);