[ Index ]

PHP Cross Reference of Drupal 6 (gatewave)

title

Body

[close]

/sites/all/modules/project/release/ -> project-release-private-download.php (source)

   1  <?php
   2  
   3  // $Id: project-release-private-download.php,v 1.3 2009/08/07 05:28:23 dww Exp $
   4  
   5  /**
   6   * @file
   7   * Script to serve private file downloads for project releases.
   8   *
   9   * MOTIVATION:
  10   *
  11   * This script is intended for sites that use public file access by default
  12   * (which is much better for regular performance) but wish to restrict access
  13   * to file downloads for their release nodes, and which generates the files
  14   * associated with release nodes (see package-release-nodes.php) instead of
  15   * allowing users to upload files and attach them directly.
  16   *
  17   * INSTRUCTIONS:
  18   *
  19   * 1. (Optional) See if your web server supports the 'X-Sendfile' header.  In
  20   * Apache, you need mod_xsendfile (http://tn123.ath.cx/mod_xsendfile).  If
  21   * your server supports this header, set the 'USE_XSENDFILE' setting below to
  22   * TRUE and the file downloads will be significantly faster and use less RAM.
  23   *
  24   * 2. Configure package-release-nodes.php to generate files into a directory
  25   * outside of your site's webroot (via the "$dest_root" variable).  For
  26   * example:
  27   *
  28   * $dest_root = '/home/package-system';
  29   * $dest_rel = 'releases';
  30   *
  31   * That will generate files like: /home/package-system/releases/foo-1.0.tar.gz
  32   *
  33   * 3. Set the "Downlod link base URL" setting (which can be found at
  34   * http://example.com/admin/project/project-release-settings) to point to an
  35   * unused location (for example "download/").  That will prevent links
  36   * pointing into the public "files" directory, and will cause the URLs to
  37   * download the files attached to release nodes to look something like:
  38   * http://example.com/download/releases/foo-1.0.tar.gz
  39   *
  40   * 4. Create a directory in your web root with the same name specifed above
  41   * (e.g. "download") and place a copy of this script in that directory.  In
  42   * the same directory, you should put a .htaccess file with the following:
  43   *
  44   * # Begin .htaccess
  45   * DirectoryIndex project-release-private-download.php
  46   * <IfModule mod_rewrite.c>
  47   *   RewriteEngine on
  48   *   RewriteRule ^(.*)$ project-release-private-download.php?q=$1 [L,QSA]
  49   * </IfModule>
  50   * <IfModule mod_xsendfile.c>
  51   *   XSendFile on
  52   *   XSendFileAllowAbove on
  53   * </IfModule>
  54   * # End .htaccess
  55   * 
  56   * 5. Configure the FILE_ROOT, DRUPAL_ROOT and SITE_NAME constants below.
  57   * - FILE_ROOT should point to whatever you set $dest_root in step 1.
  58   * - DRUPAL_ROOT should point to the web root for your site.
  59   * - SITE_NAME should match the name of your site (e.g. the 'xxx' part of
  60   *   where your 'sites/xxx/settings.php' file lives).
  61   * - Don't forget to set USE_XSENDFILE to TRUE if your server supports it.
  62   *
  63   * 6. Start creating release nodes and running package-release-nodes.php
  64   *
  65   * 7. Enjoy your private downloads!
  66   *
  67   *
  68   * @author Derek Wright (http://drupal.org/user/46549)
  69   */
  70  
  71  
  72  /**
  73   * Required configuration: directory tree where the real files live.
  74   */
  75  define('FILE_ROOT', '');
  76  
  77  /**
  78   * Required configuration: location of your Drupal installation.
  79   */
  80  define('DRUPAL_ROOT', '');
  81  
  82  /**
  83   * Required configuration: name of your site.
  84   *
  85   * Needed to find the right settings.php file to bootstrap Drupal with.
  86   */
  87  define('SITE_NAME', '');
  88  
  89  /**
  90   * Optional configuration: does your server support the X-Sendfile header?
  91   */
  92  define('USE_XSENDFILE', FALSE);
  93  
  94  
  95  /*
  96   * --------------------------------------------------
  97   * Real work begins, nothing to configure below this. 
  98   * --------------------------------------------------
  99   */
 100  
 101  // Need to be inside the Drupal webroot to properly bootstrap.
 102  if (!chdir(DRUPAL_ROOT)) {
 103    exit(1);
 104  }
 105  
 106  // Setup variables for bootstrap.
 107  $script_name = $argv[0];
 108  $_SERVER['HTTP_HOST'] = SITE_NAME;
 109  $_SERVER['REMOTE_ADDR'] = '127.0.0.1';
 110  $_SERVER['REQUEST_URI'] = '/' . $script_name;
 111  $_SERVER['SCRIPT_NAME'] = '/' . $script_name;
 112  $_SERVER['PHP_SELF'] = '/' . $script_name;
 113  $_SERVER['SCRIPT_FILENAME'] = $_SERVER['PWD'] .'/'. $script_name;
 114  $_SERVER['PATH_TRANSLATED'] = $_SERVER['SCRIPT_FILENAME'];
 115  
 116  // Actually do the bootstrap. Since we're relying on db_rewrite_sql() to
 117  // enforce the access checks on the release node, and since that invokes a
 118  // hook, we need a full bootstrap here, not just DRUPAL_BOOTSTRAP_DATABASE.
 119  include_once  './includes/bootstrap.inc';
 120  drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
 121  
 122  // Make sure we have the path argument for the file to download.
 123  $path = $_GET['q'];
 124  if (empty($path)) {
 125    drupal_not_found();
 126    exit(1);
 127  }
 128  
 129  // Figure out the filename for the release history we want to serve, and make
 130  // sure that file actually exists in our directory.
 131  $full_path = FILE_ROOT . '/' . $path;
 132  if (!is_file($full_path)) {
 133    drupal_not_found();
 134    exit(1);
 135  }
 136  
 137  // Find the release this file is associated with. Due to the db_rewrite_sql(),
 138  // this will enforce node access checks for us, so a user without permission
 139  // to view the given file will be denied. Since we're testing if there's a
 140  // node with a file that uses the given path as its filepath, this protects us
 141  // against prying eyes that might try to access "/../../../etc/passwd" or
 142  // something.  Even if they managed to find a file that actually exists that
 143  // way, it's not going to match a valid release node.  So they're going to get
 144  // a 403, not the file they're trying to steal.
 145  $nid = db_result(db_query(db_rewrite_sql("SELECT n.nid FROM {node} n INNER JOIN {project_release_file} prf ON n.nid = prf.nid INNER JOIN {files} f ON prf.fid = f.fid WHERE n.status = 1 AND f.filepath = '%s'"), $path));
 146  if (empty($nid)) {
 147    drupal_access_denied();
 148    exit(1);
 149  }
 150  
 151  // If we found the release, serve up the file.
 152  $stat = stat($full_path);
 153  $file_size = $stat[7];
 154  $file_mtime = $stat[9];
 155  header('Expires: 0');
 156  header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
 157  header('Last-Modified: '. gmdate('D, d M Y H:i:s', $file_mtime) .' GMT');
 158  header('Content-Type: application/octet-stream'); 
 159  header('Content-Description: File Transfer');
 160  header('Content-Disposition: attachment; filename="' . basename($path) . '"'); 
 161  header('Content-Length: ' . $file_size);
 162  
 163  if (USE_XSENDFILE) {
 164    // Faster and better.
 165    header('X-Sendfile: ' . $full_path);
 166  }
 167  else {
 168    // More portable.
 169    flush();
 170    readfile($full_path);
 171  }
 172  
 173  // If we got this far, invoke our hook to let modules know this happened.
 174  global $user;
 175  module_invoke_all('project_release_download', $nid, $path, $user->uid);
 176  


Generated: Thu Mar 24 11:18:33 2011 Cross-referenced by PHPXref 0.7