[development] hook_fileapi (file products and download permission)

Dave Cohen drupal at dave-cohen.com
Mon May 8 18:22:58 UTC 2006


I'm starting work on an ecommerce module to sell MP3 files.  To
accomplish this, I'd like to introduce some hooks which the
audio.module would invoke, and my ecommerce module would
implement.  

I think the hooks could be applied in other contexts, maybe
eventually becoming part of Drupal core.  That's why I'm sending
this to a large audience.  I hope all interested parties will let
me know if the direction sounds right.  

I'd like to start solving my problem immediately, making changes 
to audio.module and an ecommerce module.  But I'm open to
other approaches if consensus is that the following ideas need
work.

SPECIFIC PROBLEM
----------------

I'm creating an ecommerce product to sell access to files,
specifically MP3 audio files.  While there exists a generic file
product in the ecommerce module, the audio module is superior
when it comes to MP3s.  So, I want to use audio module nodes as
my products.

The difficulty lies in download permissions.  I want only users
who have purchased an MP3 to be able to download it.  But
audio.module controls its own downloads.  So how to make
audio.module obey my product permissions?

GENERAL PROBLEM
---------------

In Drupal today there are a handful of modules which deal with
the uploading and downloading of files.  Examples include
upload.module, audio.module and the ecommerce file product.  Each
of these modules contains it's own functions to handle saving and
downloading of files.  

Each of these modules has overlapping functionality because there
is no file management piece of Drupal that meets the needs of all
of them.  While people are working towards better file management
in core, in the 4.7 timeframe we have to accept that many modules
will be doing some facet of file management.  This is a problem
for anyone wishing to develop modules that customize file
upload/download behavior.

PROPOSAL
--------

To solve the problem I propose the following APIs.  Any file
management module (ie upload.module, audio.module) would have to
invoke these hooks to be considered "well behaved".  Third-party
modules implement the hooks in order to have influence over the
file managing modules.

The APIs fall into two categories:

1) Notification of file events (uploads, downloads)

2) Grant permission to allow file events.

In the APIs, files are identified by a numerical $fid and a
string $realm.  Together, these combine to form a unique file
identifier.  In the case of upload.module, each file has an $fid
from the files table, and the realm could be 'upload'.  In the
case of audio.module, each node has one file so the $nid is also
the $fid, and the realm would be 'audio'.

The file management modules would have to implement logic like
this when performing file operations:

  if (user does not have explicit permission to perform operation) {
    $result = module_invoke hook_file_access for the operation;
    if ($result contains TRUE) {
      perform the operation;
      module_invoke hook_fileapi; // notify that operation has occurred
    else
      do not perform; // (access denied)
  }
  else {
    // user has explicit permission to perform op
    perform the operation;
    module_invoke hook_fileapi; // notify that operation has occurred
  }

Here are function signatures for the hooks as I imagine them:


/**
 * hook_fileapi
 * 
 * This hook is invoked when file events occur.
 * 
 * @param $fid
 *   A numeric file id
 * @param $realm
 *   A string, combined with $fid ensures a unique file identification
 * @param $node
 *   The node, if any, with which the file is associated.
 * @param $op
 *   The type of event ('upload', 'download', 'update', 'delete')
 * @param $info
 *   Associative array of file details ('filesize', 'filepath', 
'filemime',...)
 * 
 * @return 
 *   Nothing
 */
function hook_fileapi($fid, $realm, $node, $op, $info) {
  // third party module code goes here.
}

/**
 * hook_file_access
 * 
 * This hook gives us a chance to allow file operations which would
 * otherwise not be permitted.
 * 
 * @param $fid
 *   A numeric file id or NULL if $op is 'upload'
 * @param $realm
 *   A string, combined with $fid ensures unique file identification
 * @param $node
 *   The node, if any with which the file is assiciated
 * @param $op
 *   The type of event ('upload', 'download', 'update', 'delete')
 * @param $info
 *   Associative array of file details ('filesize', 'filepath', 
'filemime',...)
 * @param $account
 *   The user who may or may not have permission to perform the operation
 * 
 * @return
 *   TRUE, if and only if the user is allowed to perform the operation
 */
function hook_file_access($fid, $realm, $node, $op, $info, $account) {
  // third-party logic here
  if ($is_allowed)
	return TRUE;
}

RELATED READING
---------------

http://drupal.org/node/33708 (permissions and audio module)
http://groups.drupal.org/file-api (file api discussion on groups.drupal.org)
http://dave-cohen.com/node/1045 (my own ideas about Drupal file management)
http://dave-cohen.com/node/1050 (creating ecommerce products out of nodes)

I realize this is a long post.  Thanks for reading.


More information about the development mailing list