Syndicate

Feed

File download in Drupal

The attached ebook, Files in Drupal, has been expanded and updated to account for changes in Drupal 6.
Update, May 10th, 2008.

You'll find in the pdf document attached to this posting “10 things you ought to know” about file download in Drupal, from a developer’s perspective. This small guide provides sample code, recipes, concise yet complete explanations, tricks, and a thorough coverage of the module hook function file_download. The document is 6 11 16 17 pages long, it has been expanded and updated to account for changes in Drupal 5 and 6. I also added a 'funny' cover to the book. (My modest attempt at humour.) Typos are corrected pretty much on a daily basis... If you’ve downloaded the document before May 17th, 2008, please redownload it.

In town for some quick in-and-out.

Content at a glance

  1. About the permission “view uploaded files”, p.2
  2. No records of uploaded files being downloaded, p.4
  3. For module developers : the HOOK_file_download, p.5
  4. File toolkit with examples (using clean URLs), p.9
  5. When using the private download method, p.11
  6. Changing when & how the attachment table is displayed, p.12
  7. Uploading two files with the same name, p.14
  8. A word on hot linking, p.15
  9. Images and links in nodes : doing it by hand, p.16
  10. Browsing a folder for specific files the Drupal way, p.17

Summary

Summary of the “10 things you ought to know about file download in drupal” :

  1. The problem : Using Drupal’s in-core upload module, and no “node access control” contributed module, anonymous users can either download all files attachments, or none of them. The trick : in the case where anonymous users are forbidden access to uploaded files, automatically generate a message to inform them that one or more files are attached to a post. Involves : modifications to node.tpl.php and the use of Drupal’s function format_plural(). This section provides sample code safe to copy from the pdf to your template file in your favorite text editor. download permission

  2. The problem : Drupal’s core upload module does not keep track of file downloads, even when the download method is set to private. The trick : install the contributed module download_count. This module writes a descriptive message in your logs whenever a person or robot is attempting to download an attached file. The module also keeps a record of total download hits, and last download time, to display on a dedicated page and in nodes (to which these files are attached). In your tracking of file downloads, you can chose to disregard file attachments with particular extensions. download statistics

  3. This third point explains when, why and how to use the hook function file_download. Using this function, we can :

    • Keep track of file downloads — and this section tells us what files the function can do bookkeeping of.
    • Allow files that aren’t recorded in the upload module’s table {files} to be downloaded by returning an appropriate HTTP header for them.
    • Block the download of particular files of our chosing.

    This section provides two code examples : one in which we allow the download/display of an image that sits outside the web root, and an other in which we allow the download of any file through an “open or save to disk” prompt. module development

  4. This point describes 5 Drupal functions to use when dealing with file download :

    • file_directory_path()
    • variable_get('file_downloads')
    • file_create_url($relativepath)
    • file_create_path($relativepath)
    • theme_image() should be called through the rooter function theme()

    The section explains when to use these functions and what to expect from them. It also provides sample code. file path

  5. This section explains how to use private download — and why we should use the ../privateFolder notation when specifying our File System Path. File System Path for private download

  6. Challenge : we need to change when and how the attachment table is displayed. The solution : we use the themeable function theme_upload_attachments($files) to print the table in node.tpl.php — hence printing the value returned by theme('upload_attachments', $files)or we override that function in template.php. This section provides sample code, and it reminds us of the difference between the variables $teaser and $node->teaser in the template file node.tpl.php : $teaser is a boolean, TRUE if we are to display the teaser as content, while $node->teaser is the content of that teaser. attachment table

  7. What we should know about uploading two files with the same name when using the Drupal core upload module. filename versus filepath

  8. This section explains what hot linking is, and presents 3 different methods to try and prevent it. However, I only recommend the first method, and explain why the others are flawed (these others use the value $_SERVER['HTTP-REFERER']). leaching

  9. The problem : when clean URLs is enabled, we cannot use relative paths to files and images in our html markup. This problem has been discussed on Drupal.org. There are at least 4 solutions to this problem :

    • Use an absolute path, possibly resorting to a subdomain or a virtual host.
    • Use the contributed filter module pathfilter, which has been ported to Drupal 6.
    • Set the input format to php and use the function base_path().
    • Set the input format to php and use the function file_create_url() — when the file we want to link to is inside the File System Path.
    relative versus abolute path with clean URLs

  10. This section provides a recipe to scan directories for particular files using the Drupal function file_scan_directory. It provides sample code on how to pick a random image from a folder and all its subfolders. scanning the file system path folder

Download

[]

The ebook was helpful to you? Post a comment and/or donate. Thank you.

AttachmentSizeHitsLast download
Files-in-Drupal.pdf2.67 MB60521 min 25 sec ago
Last edited by Caroline Schnapp about 6 weeks ago.

One file is attached to this posting. Login or register to download this file.


Comments

I modified the PFD document

... and updated my summary of it.

A quick question...

Hi Caroline, and thanks for offering your lovely ebook to the world. I am using your 'warning message' code in a website, but for some reason the line

<?php print format_ plural(count($files),'file', '@count files'); ?>

Is causing every node to break and I get an empty white page. As soon as I remove that line and just have

You cannot see the attached to this posting because...

etc etc, everything goes back to normal. It seems very strange to me because the format_plural function is nothing unusual. Would you have any idea why this might occur? I can submit the entire node.tpl.php if you like...

Hi there...

<?php print format_ plural(count($files),'file', '@count files'); ?>

There's a space between format_ and plural. Looks like my code is not safe to copy from the PDF file to your own template, so I will fix that. The PDF is fine. When I select the entire code snippet in my PDF file and paste it into my node.tpl.php file (in Aptana) as is, no space appears there.

Fixed!

Thanks for that. It's always the ones right under your nose you can't see.

Always

Thanks for that. It's always the ones right under your nose you can't see.

So true.

The white space

That white space certainly wasn't obvious to me at first. It took me a while to see it. I had time to open Aptana Studio (a long-drag-ass launch) before my eyes caught it, hey, wait a minute....

If it helps other people...

I'm using Smultron on a mac... When I copy and paste from Preview to Smultron I get spaces AND line breaks I now notice. But it might be more to do with Preview. When I get a chance I'll install Adobe Reader and try it out with Textwrangler as well.

Thank you

for accept my registration. I was looking something useful about Drupal's file handling and I found it here. Great article!

WOW Thank you!

You are very welcome.

Thanks a lot!

Thanks a lot for accepting my registration. :)

Altough forcing to register seemed a bit strange at first, it's the perfect way to keep the attention to your site.. and for good reasons. Your PDF about file handling rocks! And your implementation of drupal on this site is remarkably good as well.... pfew :)

Thank you

Thank you so much for this informative article. You are awesome.

Another choice on point 9

You may also want to use the URL replace filter.

I've outlined its use for the specific "image" attachment case on a page explaining how it replaces the img_relocator module , but it is more general that that, usable for all types of URLs.

Hello FGM

There are 2 problems with your module, the URL Replace Filter.

1. There isn't (yet) a Drupal 6 release for it.

2. It doesn't create URL of the form http://, hence links in content displayed on another web site will be broken. Don't forget feeds.

Maybe I am wrong here, and if I am, your project page needs some work:

Original: http://example.com:8080/
Replacement: %baseurl/

Original: http://dev.example.com/
Replacement: %baseurl/

%baseurl is a token for your site's base URL. The above examples assume a site located in the domain's root directory (in which case %baseurl is actually empty).

The module Path Filter has been around. It has been recommended to me in the Drupal forums. It seems to have a good user base, and has been ported to Drupal 6.

Have a splendid day!

URL replace filter

Hi Caroline,

Thanks for your comments. Note that this is David Lesieur's module, not mine.

The problem you mentioned had indeed been in the issue queue for url_replace_filter for a few days when I suggested this module. The patch is currently awaiting RTBC by David.

Regarding the D6 version, someone suggested that the module might be replaced by flexifilter and, although I haven't verified things, I looks like this might be a good option. I don't know yet if David intends to do a D6 port or send users to flexifilter.

Path filter seems to be more limited, allowing only the "internal:" prefix to be redefined, but it confirms there has been several answers to the need for "solid" URLs.

What's a "PFD" document?

@Caroline >I modified the PFD document.

What's a PFD? a pretty fucking document?

...

PFD stands for pretty fucked document. You were close.

Great writeup

Thanks for the writeup. Really appreciated!

Explain protection

Hello,

Thank you for the great explanation, it really gave me a lot of insight, it would be nice if you had a real world example which implements all that you say in the book.

Could you please let me know how you protect the download of the book and request registration, is it a module, or custom code?

Thanks

Custom code added to node.tpl.php.

The answer to your question is given in the ebook, point #1.

Thank you, thank you

So in your example you are just reprinting the attachment table without the links instead of printing the message.. Cool now I get it

No.

So in your example you are just reprinting the attachment table without the links instead of printing the message...

Instead of printing the message? On top of printing the message! The message and the attachment table are 2 different things. The message is generated by some php code in node.tpl.php. Now, if you want the attachment table without the links, that would be the work of the contributed module download_count. I thought you were talking only about the message that says 'blabla... login or register to download files'...

oO > o

page not found?

Hi,

Thanks for the book. It's really helpful. I'm running into a problem, though, that maybe you know the answer to. I'm trying to set up private files, so I moved my files dir to ../../private_files/mysite/ and changed the setting on the file system page. I have a page with a list of pdfs which I generate by doing a directory scan in a custom module. (The files have been manually uploaded.) It seems to be working the way it should: the files are all listed, and have urls like http://mysite.com/system/files/docs/myfile.pdf. But when you click on one of the links, you get Page Not Found.

I've cleared the cache, and I thought it might have been a permissions issue, but private_files and everything below is set to 777. (Does it actually need to be that open?) The File System admin page gives all kinds of dire warnings about changing the privacy setting after the site has been running, which I've done, but isn't at all specific about what the problems might be. I could imagine they'd be with paths in uploaded files, but I'm not dealing with that here. Any other ideas?

TIA!

P.S. I'm on D5 for this project. P.P.S. Ooooh! Duh! The files have to exist in the database in order for drupal to know anything about their permissions. Hmm.... that's a drag. I really want to have sub-directories for these files, which means I really don't want to use drupal's file upload system.

Private upload

The files have to exist in the database in order for drupal to know anything about their permissions. Hmm.... that's a drag. I really want to have sub-directories for these files, which means I really don't want to use drupal's file upload system.

Check out this module: http://drupal.org/project/private_upload

Private upload

http://drupal.org/project/private_upload

Yeah, I found that. (Thanks, though.) As far as I can tell, you get one level of hierarchy -- main and private, but you still don't get the ability to have a structure to your uploads. There's also http://drupal.org/project/filebrowser, which may do the trick, but I haven't had a chance to look at it yet.

Thanks for sharing!

Hi, I arrived after reading some of your comments on Drupal.org. Very usefull information, thank you!

Chears, Joep

Great documentation

Thanks for sharing your knowledge. Some parts of Drupal are not always easy to understand, your ebook helps a lot.

Post new comment

The content of this field is kept private and will not be shown publicly.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.
  • You may post code using <code>...</code> (generic) or <?php ... ?> (highlighted PHP) tags.
  • Allowed HTML tags: <a> <b> <i> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <sup> <sub> <dd> <del> <blockquote> <img> <q> <p> <div>

More information about formatting options

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
1 + 0 =
Solve this simple math problem and enter the result. E.g. for 1+3, enter 4.