I'm writing a custom module, and I need it to upload an image. I'm having trouble finding good documentation on this, but I think I'm close.

What am I missing? $file returns false in the form submission.

function mymodule_custom_content_block_form($form_state){
    $form = array();
    $form['custom_content_block_text'] = array(
        '#type' => 'textarea',
        '#title' => t('Block text'),
        '#default_value' => variable_get('mymodule_custom_content_block_text'),
        '#required' => true,
    );
    $form['custom_content_block_image'] = array(
        '#type' => 'file',
        '#name' => 'custom_content_block_image',
        '#title' => t('Block image'),
        '#size' => 40,
        '#description' => t("Image should be less than 400 pixels wide and in JPG format."),
    );  
    $form['submit'] = array(
        '#type' => 'submit',
        '#value' => t('Update'),
    );
    return $form;
}

function mymodule_custom_content_block_form_submit($form, &$form_state){
    if(isset($form_state['values']['custom_content_block_image'])){
        $validators = array('file_validate_extensions' => array('jpg jpeg'));
        $file = file_save_upload('custom_content_block_image', $validators, 'public://');
        if($file == false){
            drupal_set_message(t("Error saving image."), $type = "error", $repeat = false);
        }
        else{
            $file->status = FILE_STATUS_PERMANENT;
            $file = file_save($file);   
        }
    }
    variable_set('mymodule_custom_content_block_text', $form_state['values']['custom_content_block_text']);
    drupal_set_message(t('Custom Content Block has been updated.'));
}
up vote 19 down vote accepted

If you don't mind my saying you're doing this the hard way. Drupal has a managed_file element type that handles most of this logic for you:

function mymodule_custom_content_block_form($form, &$form_state) {
  $form['custom_content_block_image'] = array(
    '#type' => 'managed_file',
    '#name' => 'custom_content_block_image',
    '#title' => t('Block image'),
    '#size' => 40,
    '#description' => t("Image should be less than 400 pixels wide and in JPG format."),
    '#upload_location' => 'public://'
  ); 

  return $form; 
}

function mymodule_custom_content_block_form_submit($form, &$form_state) {
  if (isset($form_state['values']['custom_content_block_image'])) {
    $file = file_load($form_state['values']['custom_content_block_image']);

    $file->status = FILE_STATUS_PERMANENT;

    file_save($file);
  }
}
  • It should be noted that file_save is only available after Drupal 6. – Will Jun 17 '15 at 23:28

With Clive answer my image got deleted after 6 hours. So if someone experienced the same problem that I got. Here is the solution (from Clive's answer with a little addition).

function mymodule_custom_content_block_form($form, &$form_state) {
  $form['custom_content_block_image'] = array(
    '#type' => 'managed_file',
    '#name' => 'custom_content_block_image',
    '#title' => t('Block image'),
    '#size' => 40,
    '#description' => t("Image should be less than 400 pixels wide and in JPG format."),
    '#upload_location' => 'public://'
  ); 

  return $form; 
}

function mymodule_custom_content_block_form_submit($form, &$form_state) {
  if (isset($form_state['values']['custom_content_block_image'])) {
    $file = file_load($form_state['values']['custom_content_block_image']);

    $file->status = FILE_STATUS_PERMANENT;

    $file_saved =file_save($file);
    // Record that the module is using the file. 
    file_usage_add($file_saved, 'mymodule_custom_content_block_form', 'custom_content_block_image', $file_saved->fid); 
  }
}

The solution is to add file_usage_add. From API documentation:

Note: New files are uploaded with a status of 0 and are treated as temporary files which are removed after 6 hours via cron. Your module is responsible for changing the $file objects status to FILE_STATUS_PERMANENT and saving the new status to the database. Something like the following within your submit handler should do the trick.

See: https://api.drupal.org/api/drupal/developer%21topics%21forms_api_reference.html/7.x#managed_file

This attribute should be added to your form in order for it to work with file uploads.

$form['#attributes']['enctype'] = "multipart/form-data";

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.