You are here

public function S3fsStreamWrapper::getExternalUrl in S3 File System 7.2

Same name and namespace in other branches
  1. 7.3 S3fsStreamWrapper.inc \S3fsStreamWrapper::getExternalUrl()
  2. 7 S3fsStreamWrapper.inc \S3fsStreamWrapper::getExternalUrl()

Returns a web accessible URL for the resource.

The format of the returned URL will be different depending on how the S3 integration has been configured on the S3 File System admin page.

Parameters

bool $no_redirect: A custom parameter for internal use by s3fs.

Return value

string A web accessible URL for the resource.

Overrides DrupalStreamWrapperInterface::getExternalUrl

File

./S3fsStreamWrapper.inc, line 311
Drupal stream wrapper implementation for S3 File System.

Class

S3fsStreamWrapper
The stream wrapper class.

Code

public function getExternalUrl() {
  $this
    ->_debug("getExternalUrl() called for {$this->uri}.");

  // In case we're on Windows, replace backslashes with forward-slashes.
  // Note that $uri is the unaltered value of the File's URI, while
  // $s3_key may be changed at various points to account for implementation
  // details on the S3 side (e.g. root_folder, s3fs_public_folder).
  $s3_key = str_replace('\\', '/', file_uri_target($this->uri));

  // If this is a private:// file, it must be served through the
  // system/files/$path URL, which allows Drupal to restrict access
  // based on who's logged in.
  if (file_uri_scheme($this->uri) == 'private') {
    return url("system/files/{$s3_key}", array(
      'absolute' => TRUE,
    ));
  }

  // When generating an image derivative URL, e.g. styles/thumbnail/blah.jpg,
  // if the file doesn't exist, provide a URL to s3fs's special version of
  // image_style_deliver(), which will create the derivative when that URL
  // gets requested.
  $path_parts = explode('/', $s3_key);
  if ($path_parts[0] == 'styles' && substr($s3_key, -4) != '.css') {
    if (!$this
      ->_s3fs_get_object($this->uri)) {

      // The style delivery path looks like: s3/files/styles/thumbnail/...
      // And $path_parts looks like array('styles', 'thumbnail', ...),
      // so just prepend s3/files/.
      array_unshift($path_parts, 's3', 'files');
      return url(implode('/', $path_parts), array(
        'absolute' => TRUE,
      ));
    }
  }

  // Deal with public:// files.
  if (file_uri_scheme($this->uri) == 'public') {

    // Rewrite all css/js file paths unless the user has told us not to.
    if (empty($this->config['no_rewrite_cssjs'])) {
      if (substr($s3_key, -4) == '.css') {

        // Send requests for public CSS files to /s3fs-css/path/to/file.css.
        // Users must set that path up in the webserver config as a proxy into
        // their S3 bucket's s3fs_public_folder.
        return "{$GLOBALS['base_url']}/s3fs-css/" . drupal_encode_path($s3_key);
      }
      elseif (substr($s3_key, -3) == '.js') {

        // Send requests for public JS files to /s3fs-js/path/to/file.js.
        // Like with CSS, the user must set up that path as a proxy.
        return "{$GLOBALS['base_url']}/s3fs-js/" . drupal_encode_path($s3_key);
      }
    }

    // public:// files are stored in S3 inside the s3fs_public_folder.
    $public_folder = !empty($this->config['public_folder']) ? $this->config['public_folder'] : 's3fs-public';

    // If domain root is not set, or the value is set to map to the root
    // folder, include the public folder.
    if ($this->config['domain_root'] == 'none' || $this->config['domain_root'] == 'root') {
      $s3_key = "{$public_folder}/{$s3_key}";
    }
  }

  // Set up the URL settings as speciied in our settings page.
  $url_settings = array(
    'torrent' => FALSE,
    'presigned_url' => FALSE,
    'timeout' => 60,
    'forced_saveas' => FALSE,
    'api_args' => array(
      'Scheme' => !empty($this->config['use_https']) ? 'https' : 'http',
    ),
    'custom_GET_args' => array(),
  );

  // Presigned URLs.
  foreach ($this->presignedURLs as $blob => $timeout) {

    // ^ is used as the delimeter because it's an illegal character in URLs.
    if (preg_match("^{$blob}^", $s3_key)) {
      $url_settings['presigned_url'] = TRUE;
      $url_settings['timeout'] = $timeout;
      break;
    }
  }

  // Forced Save As.
  foreach ($this->saveas as $blob) {
    if (preg_match("^{$blob}^", $s3_key)) {
      $filename = drupal_basename($s3_key);
      $url_settings['api_args']['ResponseContentDisposition'] = "attachment; filename=\"{$filename}\"";
      $url_settings['forced_saveas'] = TRUE;
      break;
    }
  }

  // Allow other modules to change the URL settings.
  drupal_alter('s3fs_url_settings', $url_settings, $s3_key);

  // If a root folder has been set, and domain root is not set, prepend
  // the root folder to the $s3_key at this time.
  if (!empty($this->config['root_folder']) && $this->config['domain_root'] == 'none') {
    $s3_key = "{$this->config['root_folder']}/{$s3_key}";
  }
  if (empty($this->config['use_cname'])) {

    // We're not using a CNAME, so we ask S3 for the URL.
    $expires = NULL;
    if ($url_settings['presigned_url']) {
      $expires = "+{$url_settings['timeout']} seconds";
    }
    else {

      // Due to Amazon's security policies (see Request Parameters section @
      // http://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectGET.html),
      // only signed requests can use request parameters.
      // Thus, we must provide an expiry time for any URLs which specify
      // Response* API args. Currently, this only includes "Forced Save As".
      foreach ($url_settings['api_args'] as $key => $arg) {
        if (strpos($key, 'Response') === 0) {
          $expires = "+10 years";
          break;
        }
      }
    }
    $external_url = $this->s3
      ->getObjectUrl($this->config['bucket'], $s3_key, $expires, $url_settings['api_args']);
  }
  else {

    // We are using a CNAME, so we need to manually construct the URL.
    $external_url = "{$this->domain}/{$s3_key}";
  }

  // If this file is versioned, append the version number as a GET arg to
  // ensure that browser caches will be bypassed upon version changes.
  $meta = $this
    ->_read_cache($this->uri);
  if (!empty($meta['version']) && (isset($this->config['use_versioning']) && $this->config['use_versioning'])) {
    $external_url = $this
      ->_append_get_arg($external_url, $meta['version']);
  }

  // Torrents can only be created for publicly-accessible files:
  // https://forums.aws.amazon.com/thread.jspa?threadID=140949
  // So Forced SaveAs and Presigned URLs cannot be served as torrents.
  if (!$url_settings['forced_saveas'] && !$url_settings['presigned_url']) {
    foreach ($this->torrents as $blob) {
      if (preg_match("^{$blob}^", $s3_key)) {

        // You get a torrent URL by adding a "torrent" GET arg.
        $external_url = $this
          ->_append_get_arg($external_url, 'torrent');
        break;
      }
    }
  }

  // If another module added a 'custom_GET_args' array to the url settings, process it here.
  if (!empty($url_settings['custom_GET_args'])) {
    foreach ($url_settings['custom_GET_args'] as $name => $value) {
      $external_url = $this
        ->_append_get_arg($external_url, $name, $value);
    }
  }
  return $external_url;
}