3

I have a views page that is only accessible by a certain user role. This user role also has permission to "view private files" and to "document: download any files" (coming from File Entity Module). The views page displays a table of all private .pdf files that lie in the private file directory and I would like to add a column to this table, using a Views PHP field (at least for prototyping), that displays the corresponding download link next to the file name. As mentioned above, any user that can view the table also has permission to view private files and to download documents, so this should be doable and not be a security issue.

For now, let's assume I always want to display the download link to a fixed private .pdf file, say with file id $fid=17. According to Working with files in Drupal,

once configured, files stored in the private directory are inaccessible via a direct link; however, if Drupal constructs a link to the file, the file will be accessible to anyone who can see the link.

What precisely is meant by "if Drupal constructs a link to the file"? I have read many times that file_create_url() will create a direct link that, if the user has access to view private files, will take the user to the private file. So I tried in my Views PHP field as output code

<?php
$fid = 17;
$file = file_load($fid);
$uri = $file->uri;
$url = file_create_url($uri);
print l(t('Link'), $url);
?>

and the link gets displayed as it should (with reference to mysite.com/system/files/Name_Of_Private_File_17.pdf). But even though the user has permission to view and download private document files, clicking on the link will result in an "Access denied. You are not authorized to access this page."

Can anyone tell me the correct workaround?

4
+50

When I add the field 'File: Download link' to the view it works fine.

The views field handler for the 'File: Download link' has this snippet to check access:

if (!file_entity_access('download', $file)) {
   return;
}

and this snippet to construct the uri for the download link:

$uri = file_entity_download_uri($file);

The code for file_entity_download_uri():

function file_entity_download_uri($file) {
  $uri = array(
    'path' => "file/{$file->fid}/download",
    'options' => array(),
  );
  if (!variable_get('file_entity_allow_insecure_download', FALSE)) {
    $uri['options']['query']['token'] = file_entity_get_download_token($file);
  }
  return $uri;
}

show the download token being added to the options query key of $uri which is returned.

Adding that to the PHP code field:

<?php
    $fid = $row->fid;
    $file = file_load($fid);
    if (file_entity_access('download', $file)) {
        $uri = file_entity_download_uri($file);
        print l(t('Download'), $uri['path'], array('query' => $uri['options']['query']));
    }
?>

results in a download link to the private file.

  • You are right, if I add the field 'File: Download link' then everything works as expected. In this case the download link refers to a URL that contains the file id and a download token. The Views PHP link, however, refers to a URL that contains the file name and not a download token. When I click on this link with the correct permissions then I still get an Access Denied error. – deinqwertz Aug 10 '14 at 21:50
  • Alright, it works if I replace file_create_url() with what is described here: gist.github.com/steffenr/11401484. – deinqwertz Aug 10 '14 at 22:05
  • Yes, I think you've got it. I just checked how the file entity views field handler does it and it also calls $uri = file_entity_download_uri($file); – J. Reynolds Aug 11 '14 at 6:34
  • Would you edit your answer so I can award you the bounty? – deinqwertz Aug 11 '14 at 11:36
  • Gladly, though you deserve it yourself. – J. Reynolds Aug 11 '14 at 14:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.