Drupal 7 - Handling file uploads and moving files to the public file system

rahul's picture

This was the most time consuming aspect for the recent port of my Document module for Drupal 7.

You would be knowing that File system API underwent a complete revamp in Drupal 7 (see this and this link, a very good introduction of the changes and new concepts is available on Randy Fay's blog). In Drupal 6, handling file uploads was this easy:

 

{syntaxhighlighter brush: as3;fontsize: 100; first-line: 1; }$file = file_save_upload('file_form_field_name', array(), 'relative_path_to_files_folder'); if ($file !== 0) { //Set the status of the uploaded file. file_set_status($file, FILE_STATUS_PERMANENT); }{/syntaxhighlighter}

Drupal 7 has completely overhauled the File API introducing things like stream wrappers and managed/unmanaged apis etc. You would appreciate the architecture behind these changes in D7 once you understand how it works. But till you do so, it might really get onto you to get it working. And this is what happened to me during the D7 port of the Document module.

I made the following mistakes during the path (which you should avoid obviously):

  1. The first mistake I made was not to pass the stream wrapper's scheme to the file_save_upload method. In D7 and using managed File API, you need to pass in the stream wrapper's scheme compulsarily. I originally tried with this:

    $file = file_save_upload('document_filepath', array(), 'docs', FILE_EXISTS_RENAME);

    Here "docs" is a sub-folder inside the files folder to which I wanted to save the uploaded file to. Because I wanted to save to the public file-system path, I should have used the "public://" scheme as belows:

    $file = file_save_upload('document_filepath', array(), 'public://docs'), FILE_EXISTS_RENAME);
     
  2. The base path of the file-system you are trying to save the file to should not be passed to the file_save_upload method. Suppose your public file-system's path is "sites/default/files". And you want to save the uploaded file to "sites/default/files/docs". Then this is the call you should make:

    $file = file_save_upload('document_filepath', array(), 'public://docs'), FILE_EXISTS_RENAME);

    while I originally tried with this (which was wrong):

    $file = file_save_upload('document_filepath', array(), 'public://sites/default/files/docs'), FILE_EXISTS_RENAME);
  3. Finally the uploaded file's path in the $file object is now represented by:
    $file->uri
    in Drupal 7 as opposed to:
    $file->filepath
    in Drupal 6.

So, here's the complete code from the Document module to handle a file upload and save it to the public file-system path:

 

{syntaxhighlighter brush: php;fontsize: 100; first-line: 1; }$file = file_save_upload('document_filepath', array(), 'public://' . variable_get('document_path', ''), FILE_EXISTS_RENAME); if ($file) { $fid = $file->fid; $doc_url = file_create_url($file->uri); //Set the status of the uploaded file. $file->status = FILE_STATUS_PERMANENT; file_save($file); } else { drupal_set_message(t('Please select a document to upload.'), 'error'); }{/syntaxhighlighter}

 

 

PHP: 

Comments

  I am unable to upload zif files...when I try to upload ,a wraning  "The specified file sample.zip could not be uploaded. Only files with the following extensions are allowed: jpg jpeg gif png txt doc xls pdf ppt pps odt ods odp." is shown...

Kindly give me a solution ...I tried configuring manage fields etc..but nothing worked..

By narendra (not verified)

You need to edit the file field of your content type. Under the field's label and helptext you will find the "allowed extensions", where you can add "zip".

By Wouter (not verified)
rahul's picture

Thanks Wouter for providing assistance here. You beat me by a few moments in providing answer to Narendra Smile

By rahul

  Actually I have copied a module called word2book compatible with drupal 6 to drupal 7 ..In which I am uploading a zip file consist of filtered html files and this module will convert those into books...I have done some changes in .module file like pathe change public:// ,clone() etc  as a result  title is getting posted but not the content when I view it under content menu only tule is shown not the body of it...Kindly give me a solution ..

By narendra (not verified)
rahul's picture

Hi narendra, I do not see any module called word2book on drupal.org, so most probably you have a custom or proprietary module with you. I would not be able to help here.

By rahul

Can you please tell me equivelent function for  node_teaser( ) of drupal 6 in drupal 7

By Narendra Shanbhag (not verified)
rahul's picture

text_summary

You might also be interested in the migarion guide.

By rahul

Thankx Rahul for your support...

Basically I am uploading zip file containing filtered html files and my module will convert in  to book.. Now I am able to display Index and  headings of book,pages  that I am uploading but..not able to view the body ...

I tried following code for assigning values to node->body

$child_node->body = array(
    'und' => array(
      array(
        'value'  => $body,
        'summary' => text_summary($body),
        'format' => '1',
        'safe_value' => $body,
        'safe_summary' => text_summary($body),
      )
    ),
  );
// othe code related to reirect and all   

  node_save($child_node);

But the thing is book shows index and on clicking on perticular page it rediredcts ..in the redirected page I am able to view Tiltle ,Next page prev page ,up but not body ...can you pls sugeest me anything which I need to take care off

By Narendra Shanbhag (not verified)
rahul's picture

Please see the documentation for node_object_prepare method Call that method and print_r its return value, that would help you. I am planning to write a blog post on this aspect, that might help you. I will try to write that blog post soon (maybe by tomorrow).

By rahul

i have created an object for stdClass ...but its showing a notice Undefined property: stdClass::$book in word2book_module_upload_form_submit() (line 319 of /var/www/drupal7/sites/all/modules/word2book/word2book.module) ...in this line   I have condition         if($node->book['bid'] == 0 || !isset($node->book['bid'])){

$node->book['bid'] = $node->nid;
        node_save($node);
        $status=1;

}

In drupal 7 how ton get rid of this notice without turning off the drupal  messages ...Kindly explain thanks

By Narendra Shanbhag (not verified)
rahul's picture

Hi Narendra, I have already said that I would not be able to help on proprietary modules not available off d.o. Also please take care to keep your comments related to the blog post. I would remove any further comment that does not relate specifically to the blog post where you are making it.

By rahul

I have no words to express my gratitude for such a helpful post.

Thanks,
Mudasser

By Mudasser (not verified)

In which file should I change/add this code?

$file = file_save_upload('document_filepath', array(), 'public://' . variable_get('document_path', ''), FILE_EXISTS_RENAME); if ($file) {   $fid = $file->fid;   $doc_url = file_create_url($file->uri);   //Set the status of the uploaded file.   $file->status = FILE_STATUS_PERMANENT;   file_save($file); } else {   drupal_set_message(t('Please select a document to upload.'), 'error'); }
By Mikkelsen (not verified)
rahul's picture

document.module - line 316 I believe..
BTW, you are posting it at a wrong place, this question should goto the Document module's page

By rahul

Hi, I've read through the post above about not been able to upload a zip, I'm also unable to upload a docx type (and zips).

I looked for the file field on the document content type, but all i see title, body and document types. So I'm unable to change the accepted file types, am I missing something?

Thank
chris

By Chris (not verified)
rahul's picture

Hi Chris, please ensure the extension is allowed in your file-system settings.

By rahul

Want to create thumbnail of uploaded images as well as. Anny idea??

By mausmee (not verified)
rahul's picture

Hi mausmee, D7 has Image module in the core which provides many useful operations (including resizing images by specifying Image styles in Administration area). You would want to check out Image module's documenation to see how to use Image styles to manually resize images in code.

By rahul

Thank u, Can u tell me how drupal's user module create thumbnail of user's profile pic??

By mausmee (not verified)
rahul's picture

Mausmee, research before you ask, you should not expect readymade answers for your work. Use public api methods from image.module, specifically image_style_url.

By rahul

Thank u  so much for your advice. Hv researched a lot and then asked to u. Actly hv asked to a wrong person.

By mausmee (not verified)
rahul's picture

Okay so, after these replies, you feel like I am the wrong person to ask these questions to, great!!!

By rahul

Hi Rahul,

Thank you for the insightful article. I was hoping you could help me with a question:

I am trying to find out how to rename an image filename upon upload. I am using file_save_upload() and I am able to control the filename in the {file_managed} database table with this:

$file->filename = 'avatar' . '-' . $user->uid . '-' . REQUEST_TIME . '.' . $info['extension'];

However, it does not affect the filenames of the image files themselves  (that end up in my designated folder directory):

\sites\default\files\avatar_selection

I was hoping you can help me understand how to automatically rename an image filename upon upload. Here is a link to the function code snippet I am working with just in case it is helpful: http://pastebin.com/kwRfUPuQ

Many thnx for your time and consideration.

All the best,
Ben

rahul's picture

Hi mcferren, I am running short of time, so can't research much. But I recall I did it for some project earlier. One easy solution might be to use file_save_upload to save the file and then use file_move (or file_copy followed by file_delete) to have the end file with your desired filename.

Another option might be to use file_save_data to save raw file stream to your desired destination (this function allows you to specify the file name also).

There might be other (better) options but this is all I could recollect quickly. 

By rahul

HI, Thanks to share this.

Hi Rahul,


I am new to Drupal.  Using Drupal 7.  I am simply trying to create a form that allows users to upload a file to me from a particular page.  I have your module installed but am not sure how I can accomplish this.  Please help.

Add new comment