You are here

public function ProxySubscriber::checkFileOrigin in Stage File Proxy 8

Fetch the file from it's origin.

Parameters

\Symfony\Component\HttpKernel\Event\GetResponseEvent $event: The event to process.

File

src/EventSubscriber/ProxySubscriber.php, line 86

Class

ProxySubscriber
Stage file proxy subscriber for controller requests.

Namespace

Drupal\stage_file_proxy\EventSubscriber

Code

public function checkFileOrigin(GetResponseEvent $event) {
  $config = $this->configFactory
    ->get('stage_file_proxy.settings');

  // Get the origin server.
  $server = $config
    ->get('origin');

  // Quit if no origin given.
  if (!$server) {
    return;
  }

  // Quit if we are the origin, ignore http(s).
  if (preg_replace('#^[a-z]*://#u', '', $server) === $event
    ->getRequest()
    ->getHost()) {
    return;
  }
  $file_dir = $this->manager
    ->filePublicPath();
  $request_path = $event
    ->getRequest()
    ->getPathInfo();
  $request_path = mb_substr($request_path, 1);
  if (strpos($request_path, '' . $file_dir) !== 0) {
    return;
  }

  // Disallow directory traversal.
  if (in_array('..', explode('/', $request_path))) {
    return;
  }

  // Moving to parent directory is insane here, so prevent that.
  if (in_array('..', explode('/', $request_path))) {
    return;
  }
  $alter_excluded_paths_event = new AlterExcludedPathsEvent([]);
  $this->eventDispatcher
    ->dispatch('stage_file_proxy.alter_excluded_paths', $alter_excluded_paths_event);
  $excluded_paths = $alter_excluded_paths_event
    ->getExcludedPaths();
  foreach ($excluded_paths as $excluded_path) {
    if (strpos($request_path, $excluded_path) !== FALSE) {
      return;
    }
  }

  // Note if the origin server files location is different. This
  // must be the exact path for the remote site's public file
  // system path, and defaults to the local public file system path.
  $remote_file_dir = trim($config
    ->get('origin_dir'));
  if (!$remote_file_dir) {
    $remote_file_dir = $file_dir;
  }
  $request_path = rawurldecode($request_path);

  // Path relative to file directory. Used for hotlinking.
  $relative_path = mb_substr($request_path, mb_strlen($file_dir) + 1);

  // If file is fetched and use_imagecache_root is set, original is used.
  $paths = [
    $relative_path,
  ];

  // Webp support.
  $is_webp = FALSE;
  if (strpos($relative_path, '.webp')) {
    $paths[] = str_replace('.webp', '', $relative_path);
    $is_webp = TRUE;
  }
  foreach ($paths as $relative_path) {
    $fetch_path = $relative_path;

    // Is this imagecache? Request the root file and let imagecache resize.
    // We check this first so locally added files have precedence.
    $original_path = $this->manager
      ->styleOriginalPath($relative_path, TRUE);
    if ($original_path && !$is_webp) {
      if (file_exists($original_path)) {

        // Imagecache can generate it without our help.
        return;
      }
      if ($config
        ->get('use_imagecache_root')) {

        // Config says: Fetch the original.
        $fetch_path = StreamWrapperManager::getTarget($original_path);
      }
    }
    $query = $this->requestStack
      ->getCurrentRequest()->query
      ->all();
    $query_parameters = UrlHelper::filterQueryParameters($query);
    $options = [
      'verify' => $config
        ->get('verify'),
    ];
    if ($config
      ->get('hotlink')) {
      $location = Url::fromUri("{$server}/{$remote_file_dir}/{$relative_path}", [
        'query' => $query_parameters,
        'absolute' => TRUE,
      ])
        ->toString();
    }
    elseif ($this->manager
      ->fetch($server, $remote_file_dir, $fetch_path, $options)) {

      // Refresh this request & let the web server work out mime type, etc.
      $location = Url::fromUri('base://' . $request_path, [
        'query' => $query_parameters,
        'absolute' => TRUE,
      ])
        ->toString();

      // Avoid redirection caching in upstream proxies.
      header("Cache-Control: must-revalidate, no-cache, post-check=0, pre-check=0, private");
    }
    if (isset($location)) {
      header("Location: {$location}");
      exit;
    }
  }
}