You are hereBlogs / rahul's blog / Drupal 7 - Handling file uploads and moving files to the public file system

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


rahul's picture

By rahul - Posted on 23 June 2011

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:

 

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

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:

 

$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');
}

 

 

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

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

rahul's picture

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

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

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.

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

rahul's picture

text_summary

You might also be interested in the migarion guide.

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

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

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

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.

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

Thanks,
Mudasser

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

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

rahul's picture

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

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

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.

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

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.

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

rahul's picture

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

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. 

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.

rahul's picture

Hi Michael, the code in this blog post is not a Drupal module at all, so won't run as is. You would need to wrap it up in a .module file, create a .info file for the module, the ui with file upload fields and enable the module in Drupal to be able to use this code.

Hi Rahul,


Thanks for the response.  I was under the impression that this code is already included in your Documents module which I currently have installed and enabled.  If that is not the case, code I just directly paste the code into a text editor and save as upload.module for instance and install?  Do I need to add anything else before or after the code you have shown?  What do I need to put in an info file?  I really appreciate your time on this.

rahul's picture

Oh yes, this code is a part of the Document module and you should be able to upload a document using that module.

For wrapping this code up in a custom Drupal module, please consult the Drupal module author's guide, this is not an appropriate place for discussing that.

Hi Rahul,


Ok.  So can I put something on a page that allows an anonymouse user to upload a file to me?  This is my goal.  Is my best bet to just use PHP on the particular page I need this on? Thanks

Post new comment

The content of this field is kept private and will not be shown publicly.
Type the characters you see in this picture. (verify using audio)
Type the characters you see in the picture above; if you can't read them, submit the form and a new image will be generated. Not case sensitive.

Recent comments