I have a webform with a file field configured to private files. When I'm logged in as a superuser (uid=1) and trying to download the file, I get access denied.

I was trying to debug this, and this is what I noticed.

All private files served by the file_download() function that is called in the system.module. This function validates if the file exists and request the file headers using file_download_headers() function that triggers hook_file_download().

In the webform_file_download() function the module determines whether the file was a webform upload and grant or deny file access based on access to the submission. It validates access permission by calling webform_submission_access(). When I run dpm($account) in this function, I get an anonymous user when I'm trying to access the private file. When I browse recent log messages I have the entry below:

access denied   06/02/2015 - 11:23  system/files/webform/cv-uploads/cv.pdf  Anonymous

When I change the URL to file that doesn't exist, I get this:

page not found  06/02/2015 - 11:26  system/files/webform/cv-uploads/cv.FDP  admin

As you can see for some reasons when the module is trying to get access to the file that does exist, I get access denied and the user is anonymous. When the file doesn't exist, I get page not found and the user is a logged in user.

Any ideas why this happens?


I've added the following code to my index.php but I still get anonymous user when I'm trying to access the file.

define('DRUPAL_ROOT', getcwd());

require_once DRUPAL_ROOT . '/includes/bootstrap.inc';

+ global $user;
+ watchdog('user', '<pre>'. print_r($user, TRUE) . '</pre>');


I've copied over the whole site including database and files to my local machine, and I'm not experiencing this issue. There's should be some settings that does this on the live site.


I've noticed that on the live site we have a list of disabled functions that I'm not aware of. Maybe it will help somehow.

disable_functions = apache_child_terminate, apache_setenv, define_syslog_variables, escapeshellarg, escapeshellcmd, eval, exec, fp, fput, ftp_connect, ftp_exec, ftp_get, ftp_login, ftp_nb_fput, ftp_put, ftp_raw, ftp_rawlist, highlight_file, ini_alter, ini_get_all, ini_restore, inject_code, mysql_pconnect, passthru, php_uname, phpAds_remoteInfo, phpAds_XmlRpc, phpAds_xmlrpcDecode, phpAds_xmlrpcEncode, popen, posix_getpwuid, posix_kill, posix_mkfifo, posix_setpgid, posix_setsid, posix_setuid, posix_setuid, posix_uname, proc_close, proc_get_status, proc_nice, proc_open, proc_terminate, shell_exec, system, xmlrpc_entity_decode, parse_ini_file,show_source,shell_exec
  • What is the account id the dpm($account) gives you? Feb 9, 2015 at 13:10
  • It's 0. Here's the serialized string a:4:{s:3:"uid";i:0;s:8:"hostname";s:15:"xxx.xxx.xxx.xxx";s:5:"roles";a:1:{i:1;s:14:"anonymous user";}s:5:"cache";i:0;} Feb 9, 2015 at 13:30

2 Answers 2


If you are using private file system every module can prevent you from downloading a file. It comes from file_download_header function:

function file_download_headers($uri) {
  // Let other modules provide headers and control access to the file.
  // module_invoke_all() uses array_merge_recursive() which merges header
  // values into a new array. To avoid that and allow modules to override
  // headers instead, use array_merge() to merge the returned arrays.
  $headers = array();
  foreach (module_implements('file_download') as $module) {
    $function = $module . '_file_download';
    $result = $function($uri);
    if ($result == -1) {
      // Throw away the headers received so far.
      $headers = array();
    if (isset($result) && is_array($result)) {
      $headers = array_merge($headers, $result);
  return $headers;

So basically you should discover which implementation of hook_file_download returns -1. You can do that by printing (or writing into watchdog) value of $function variable inside if ($result == -1) { statement (so you will know that this function is responsible for giving -1 result).

However, there is also other case when you'll get access_denied() - if none implementation of hook_file_download will return file headers.

So try to figure out which function (=> module) prevents you from downloading file, then debug that function and try to deduct why.

  • I did that and it returns just "webform". That's why I was debugging webform_file_download(). Feb 13, 2015 at 9:28

The problem was caused by the Varnish on the server. Below is the settings for Varnish.

# Always cache the following file types for all users. This list of extensions
# appears twice, once here and again in vcl_fetch so make sure you edit both
# and keep them equal.

if (req.url ~ "(?i)\.(pdf|asc|dat|txt|doc|xls|ppt|tgz|csv|png|gif|jpeg|jpg|ico|swf|css|js)(\?.*)?$") {
  unset req.http.Cookie;

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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