Steps to reproduce:

  • install cck and enable
  • install filefield and enable
  • install cck_field_perms and enable
  • add a filefield to a content type
  • restrict access on the field using cck_field_perms
  • grant view access to authenticated users, but not anonymous users
  • enable "private" file transfers at admin/settings/file-system
  • log out and try to browse directly to the file using the "files/" url

Since the field is restricted users should not be able to download it. This can be overridden by implementing the hook_file_download.

Here is my stab at an implementation, but I think it needs some cleanup.

/**
 * Implentation of hook file_download
 */
function cck_field_perms_file_download($file) {
    if (!user_access('view uploaded files'))
      return -1;

  $file = file_create_path($file);
  $result = db_query("SELECT f.* FROM {files} f WHERE filepath = '%s'", $file);
  if ($file = db_fetch_object($result)) {
    $node = node_load($file->nid);
    if (node_access('view', $node)) {
      $type = $node->type;
      if ($types = variable_get('cfp_types', null)) {
        if ($types[$type]) {
          $disallowed_fields = unserialize(variable_get('cfp_values', null));
          if ($disallowed_fields) { 
            foreach ($disallowed_fields[$type] as $disallowed_field => $value ) {
              if ($value == 0) 
                continue;
              $field = db_fetch_object(db_query("SELECT * FROM {node_field} WHERE field_name = '%s'", $disallowed_field));
              if ($field->type != 'file')
                continue;
              foreach ($node->$disallowed_field as $field_instance) {
                if ($field_instance['fid'] != $file->fid)
                  continue;
                if (!(user_access(_cfp_content_to_readable($type, $disallowed_field, "view")))) {     
                  return -1;
                }
              }
            }
          }
        }
      }

      $type = mime_header_encode($file->filemime);
      return array(
        'Content-Type: '. $type,
        'Content-Length: '. $file->filesize,
      );
    }
    else {
      return -1;
    }
  }
}

Comments

zarko’s picture

I had an issue with Acrobat Reader displaying PDF files. I had to add 'Cache-Control: private' to the successful return array.

doc2@drupalfr.org’s picture

What should the code look like now, please?