You are here

function webfm_send_file in Web File Manager 5

Same name and namespace in other branches
  1. 5.2 webfm.module \webfm_send_file()

webfm_send_file - streams a file privately for download

If $fid arg is numeric then file path is referenced via db, otherwise the arg ...is a urlencoded path that must be converted and concatenated to base file dir

Parameters

object $fid - file id:

bool $attach - 1 = attach / 0 = inline:

1 string reference to 'webfm_send_file'
webfm_menu in ./webfm.module
Implementation of hook_menu().

File

./webfm.module, line 2431

Code

function webfm_send_file($fid, $attach = false) {
  global $user;
  $match = FALSE;
  $f = false;

  // User has either admin access, webfm access or view attach access
  if ($user->uid == 1 || user_access('administer webfm')) {

    // Admins have total access
    $webfm_perm = WEBFM_ADMIN;
    $match = TRUE;
  }
  else {
    if (user_access('access webfm')) {
      $webfm_perm = WEBFM_USER;
    }
    else {
      if (user_access('view webfm attachments')) {
        $webfm_perm = WEBFM_ATTACH_VIEW;
      }
      else {
        $webfm_perm = 0;
      }
    }
  }
  if (is_numeric($fid)) {
    if (($f = webfm_get_file_record($fid)) === FALSE) {
      print theme('page', "");
      return;
    }
    else {
      if ($f->uid == $user->uid) {

        // Even if file has been moved to an inaccessible dir this works
        $match = TRUE;
      }
    }
  }
  else {
    if ($webfm_perm == WEBFM_ADMIN) {

      // Only allow admins to download files without fid
      $f = new stdClass();
      $str_arr = array();
      $str_arr = split('[~]', rawurldecode($fid));
      $f->fpath = file_directory_path() . "/" . implode('/', $str_arr);
      if (!is_file($f->fpath)) {
        print theme('page', "");
        return;
      }
      else {
        $match = TRUE;
      }
    }
    else {
      print theme('page', "");
      return;
    }
  }

  // Files that have been attached are always considered public to whoever can
  // access that node (nodeaccess security)
  if ($match == FALSE && $webfm_perm != WEBFM_ADMIN) {
    if ($f->perm & WEBFM_FILE_ACCESS_PUBLIC_VIEW) {
      $match = TRUE;
    }
    else {
      if ($webfm_perm == WEBFM_USER || $webfm_perm == WEBFM_ATTACH_VIEW) {

        //Check if the file is attached to a node
        $query = 'SELECT nid FROM {webfm_attach} WHERE fid = %d';
        $result = db_query($query, $f->fid);
        if ($result !== FALSE) {
          while ($dbfid = db_fetch_array($result)) {
            $node = node_load($dbfid['nid']);
            if (node_access('view', $node)) {
              $match = TRUE;
              break;
            }
          }
        }
      }
    }
  }

  // Files that are viewable via the filebrowser UI are downloadable
  if ($match == FALSE && $webfm_perm == WEBFM_USER && (webfm_file_view_access($f) || webfm_file_mod_access($f))) {
    $match = TRUE;
  }
  if (!$match) {
    drupal_access_denied();
    return;
  }
  $name = basename($f->fpath);

  //filenames in IE containing dots will screw up the

  //filename unless we add this
  if (strstr($_SERVER['HTTP_USER_AGENT'], "MSIE")) {
    $name = preg_replace('/\\./', '%2e', $name, substr_count($name, '.') - 1);
  }

  // Get file extension
  $type = webfm_mime_type($name);

  //download headers:
  $header = array();
  if ($attach === '1') {

    // prompt for download file or view
    $header[] = 'Pragma: no-cache';
    $header[] = 'Cache-Control: no-cache, must-revalidate';
    $header[] = 'Content-Disposition: attachment; filename="' . $name . '";';
    if (!empty($f->fid)) {
      $cnt = array();
      $cnt['dl_cnt'] = (int) $f->dl_cnt + 1;
      webfm_dbupdate_file($f->fid, '', $cnt);
    }
  }
  else {

    // view file via browser
    $header[] = 'Pragma: public';

    // required
    $header[] = 'Expires: 0';
    $header[] = 'Cache-Control: must-revalidate, post-check=0, pre-check=0';
    $header[] = 'Content-Transfer-Encoding: binary';
    $header[] = 'Content-Disposition: inline; filename="' . $name . '";';

    // consider an app run inside the browser as a 'download'
    if (!empty($f->fid) && strpos($type, "application") === 0) {
      $cnt = array();
      $cnt['dl_cnt'] = (int) $f->dl_cnt + 1;
      webfm_dbupdate_file($f->fid, '', $cnt);
    }
  }
  $header[] = 'Content-Type: ' . $type;
  $header[] = 'Content-Length: ' . (string) @filesize($f->fpath);
  $header[] = 'Connection: close';

  //drupal file_transfer will fail if file is not inside file system directory
  file_transfer($f->fpath, $header);
}