View source
<?php
namespace Drupal\stage_file_proxy;
use Drupal\Component\Utility\UrlHelper;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\StreamWrapper\PublicStream;
use Drupal\Core\StreamWrapper\StreamWrapperManager;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
use Psr\Log\LoggerInterface;
class FetchManager implements FetchManagerInterface {
protected $client;
protected $fileSystem;
protected $logger;
protected $configFactory;
public function __construct(Client $client, FileSystemInterface $file_system, LoggerInterface $logger, ConfigFactoryInterface $config_factory) {
$this->client = $client;
$this->fileSystem = $file_system;
$this->logger = $logger;
$this->configFactory = $config_factory;
}
public function fetch($server, $remote_file_dir, $relative_path, array $options) {
try {
$url = $server . '/' . UrlHelper::encodePath($remote_file_dir . '/' . $relative_path);
$options['Connection'] = 'close';
$response = $this->client
->get($url, $options);
$result = $response
->getStatusCode();
if ($result != 200) {
$this->logger
->warning('HTTP error @errorcode occurred when trying to fetch @remote.', [
'@errorcode' => $result,
'@remote' => $url,
]);
return FALSE;
}
$file_dir = $this
->filePublicPath();
$destination = $file_dir . '/' . dirname($relative_path);
if (!$this->fileSystem
->prepareDirectory($destination, FileSystemInterface::CREATE_DIRECTORY | FileSystemInterface::MODIFY_PERMISSIONS)) {
$this->logger
->error('Unable to prepare local directory @path.', [
'@path' => $destination,
]);
return FALSE;
}
$destination = str_replace('///', '//', "{$destination}/") . $this->fileSystem
->basename($relative_path);
$response_headers = $response
->getHeaders();
$content_length = array_shift($response_headers['Content-Length']);
$response_data = $response
->getBody()
->getContents();
if (isset($content_length) && strlen($response_data) != $content_length) {
$this->logger
->error('Incomplete download. Was expecting @content-length bytes, actually got @data-length.', [
'@content-length' => $content_length,
'@data-length' => $content_length,
]);
return FALSE;
}
if ($this
->writeFile($destination, $response_data)) {
return TRUE;
}
$this->logger
->error('@remote could not be saved to @path.', [
'@remote' => $url,
'@path' => $destination,
]);
return FALSE;
} catch (GuzzleException $e) {
}
$this->logger
->error('Stage File Proxy encountered an unknown error by retrieving file @file', [
'@file' => $server . '/' . UrlHelper::encodePath($remote_file_dir . '/' . $relative_path),
]);
return FALSE;
}
public function filePublicPath() {
return PublicStream::basePath();
}
public function styleOriginalPath($uri, $style_only = TRUE) {
$scheme = StreamWrapperManager::getScheme($uri);
if ($scheme) {
$path = StreamWrapperManager::getTarget($uri);
}
else {
$path = $uri;
$scheme = $this->configFactory
->get('system.file')
->get('default_scheme');
}
if (strpos($path, 'styles') === 0) {
return preg_replace('/styles\\/.*\\/(.*)\\/(.*)/U', '$1://$2', $path);
}
elseif ($style_only == FALSE) {
return "{$scheme}://{$path}";
}
else {
return FALSE;
}
}
protected function writeFile($destination, $data) {
$dir = $this->fileSystem
->dirname($destination) . '/';
$temporary_file = $this->fileSystem
->tempnam($dir, 'stage_file_proxy_');
$temporary_file_copy = $temporary_file;
$parts = pathinfo($destination);
$extension = '.' . $parts['extension'];
if ($extension === '.gz') {
$parts = pathinfo($parts['filename']);
$extension = '.' . $parts['extension'] . $extension;
}
$temporary_file = str_replace(substr($temporary_file, 0, strpos($temporary_file, 'stage_file_proxy_')), $dir, $temporary_file) . $extension;
if (!@rename($temporary_file_copy, $temporary_file)) {
@unlink($temporary_file_copy);
return FALSE;
}
$filepath = $this->fileSystem
->saveData($data, $temporary_file, FileSystemInterface::EXISTS_REPLACE);
if ($filepath) {
if (!@rename($filepath, $destination)) {
@unlink($destination);
if (!@rename($filepath, $destination)) {
@unlink($filepath);
}
}
}
$result = FALSE;
if (file_exists($destination) & filesize($destination) != 0) {
$result = TRUE;
}
return $result;
}
}