You are here

function cdn_basic_farfuture_download in CDN 6.2

Same name and namespace in other branches
  1. 7.2 cdn.basic.farfuture.inc \cdn_basic_farfuture_download()
1 string reference to 'cdn_basic_farfuture_download'
cdn_menu in ./cdn.module
Implementation of hook_menu().

File

./cdn.basic.farfuture.inc, line 12
Far Future expiration setting for basic mode.

Code

function cdn_basic_farfuture_download($token, $ufi, $path) {

  // Validate the token to make sure this request originated from CDN.
  $path_info = pathinfo($path);
  $sec_token = _cdn_hmac_base64($ufi . $path_info['filename'], drupal_get_private_key() . _cdn_get_hash_salt());
  if ($token != $sec_token) {
    header('HTTP/1.1 403 Forbidden');
    exit;
  }

  // Disallow downloading of files that are also not allowed to be downloaded
  // by Drupal's .htaccess file.
  if (preg_match("/\\.(engine|inc|info|install|make|module|profile|test|po|sh|php([3-6])?|phtml|.*sql|theme|tpl(\\.php)?|xtmpl)\$|^(\\..*|Entries.*|Repository|Root|Tag|Template)\$/", $path)) {
    header('HTTP/1.1 403 Forbidden');
    exit;
  }
  if (!file_exists($path)) {
    watchdog('cdn', 'CDN Far Future 404: %file.', array(
      '%file' => $path,
    ), WATCHDOG_ALERT);
    header('HTTP/1.1 404 Not Found');
    exit;
  }

  // Remove some useless/unwanted headers.
  $remove_headers = explode("\n", CDN_BASIC_FARFUTURE_REMOVE_HEADERS);
  $current_headers = array();
  foreach (headers_list() as $header) {
    $parts = explode(':', $header);
    $current_headers[] = $parts[0];
  }
  foreach ($remove_headers as $header) {
    if (in_array($header, $current_headers)) {

      // header_remove() only exists in PHP >=5.3
      if (function_exists('header_remove')) {
        header_remove($header);
      }
      else {

        // In PHP <5.3, we cannot remove headers. At least shorten them to save
        // every byte possible and to stop leaking information needlessly.
        drupal_set_header($header . ':');
      }
    }
  }

  // Remove all previously set Cache-Control headers, because we're going to
  // override it. Since multiple Cache-Control headers might have been set,
  // simply setting a new, overriding header isn't enough: that would only
  // override the *last* Cache-Control header. Yay for PHP!
  if (function_exists('header_remove')) {
    header_remove('Cache-Control');
  }
  else {
    drupal_set_header("Cache-Control:");
    drupal_set_header("Cache-Control:");
  }

  // Default caching rules: no caching/immediate expiration.
  drupal_set_header("Cache-Control: private, must-revalidate, proxy-revalidate");
  drupal_set_header("Expires: " . gmdate("D, d M Y H:i:s", time() - 86400) . "GMT");

  // Instead of being powered by PHP, tell the world this resource was powered
  // by the CDN module!
  drupal_set_header("X-Powered-By: Drupal CDN module");

  // Instruct intermediate HTTP caches to store both a compressed (gzipped)
  // and uncompressed version of the resource.
  drupal_set_header("Vary: Accept-Encoding");

  // Determine the content type.
  drupal_set_header("Content-Type: " . _cdn_basic_farfuture_get_mimetype(basename($path)));

  // Support partial content requests.
  drupal_set_header("Accept-Ranges: bytes");

  // Browsers that implement the W3C Access Control specification might refuse
  // to use certain resources such as fonts if those resources violate the
  // same-origin policy. Send a header to explicitly allow cross-domain use of
  // those resources. (This is called Cross-Origin Resource Sharing, or CORS.)
  drupal_set_header("Access-Control-Allow-Origin: *");

  // If the extension of the file that's being served is one of the far future
  // extensions (by default: images, fonts and flash content), then cache it
  // in the far future.
  $farfuture_extensions = variable_get(CDN_BASIC_FARFUTURE_EXTENSIONS_VARIABLE, CDN_BASIC_FARFUTURE_EXTENSIONS_DEFAULT);
  $extension = drupal_strtolower(pathinfo($path, PATHINFO_EXTENSION));
  if (in_array($extension, explode("\n", $farfuture_extensions))) {

    // Remove all previously set Cache-Control headers, because we're going to
    // override it. Since multiple Cache-Control headers might have been set,
    // simply setting a new, overriding header isn't enough: that would only
    // override the *last* Cache-Control header. Yay for PHP!
    if (function_exists('header_remove')) {
      header_remove('Cache-Control');
    }
    else {
      drupal_set_header("Cache-Control:");
      drupal_set_header("Cache-Control:");
    }

    // Set a far future Cache-Control header (480 weeks), which prevents
    // intermediate caches from transforming the data and allows any
    // intermediate cache to cache it, since it's marked as a public resource.
    drupal_set_header("Cache-Control: max-age=290304000, no-transform, public");

    // Set a far future Expires header. The maximum UNIX timestamp is somewhere
    // in 2038. Set it to a date in 2037, just to be safe.
    drupal_set_header("Expires: Tue, 20 Jan 2037 04:20:42 GMT");

    // Pretend the file was last modified a long time ago in the past, this will
    // prevent browsers that don't support Cache-Control nor Expires headers to
    // still request a new version too soon (these browsers calculate a
    // heuristic to determine when to request a new version, based on the last
    // time the resource has been modified).
    // Also see http://code.google.com/speed/page-speed/docs/caching.html.
    drupal_set_header("Last-Modified: Wed, 20 Jan 1988 04:20:42 GMT");
  }

  // GET requests with an "Accept-Encoding" header that lists "gzip".
  if (isset($_SERVER['HTTP_ACCEPT_ENCODING']) && strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== FALSE) {

    // Only send gzipped files for some file extensions (it doesn't make sense
    // to gzip images, for example).
    if (in_array($extension, explode("\n", CDN_BASIC_FARFUTURE_GZIP_EXTENSIONS))) {

      // Ensure a gzipped version of the file is stored on disk, instead of
      // gzipping the file on every request.
      $gzip_path = file_directory_path() . '/' . CDN_BASIC_FARFUTURE_GZIP_DIRECTORY . "/{$path}.{$ufi}.gz";
      if (!file_exists($gzip_path)) {
        _cdn_basic_farfuture_create_directory_structure(dirname($gzip_path));
        file_put_contents($gzip_path, gzencode(file_get_contents($path), 9));
      }

      // Make sure zlib.output_compression does not gzip our gzipped output.
      ini_set('zlib.output_compression', '0');

      // Prepare for gzipped output.
      drupal_set_header("Content-Encoding: gzip");
      $path = $gzip_path;
    }
  }

  // Conditional GET requests (i.e. with If-Modified-Since header).
  if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {

    // All files served by this function are designed to expire in the far
    // future. Hence we can simply always tell the client the requested file
    // was not modified.
    drupal_set_header("HTTP/1.1 304 Not Modified");
  }
  else {
    _cdn_transfer_file($path);
  }
  exit;
}