Skip to content

Commit

Permalink
optional proxy downloads for the project filesystem (directus#860)
Browse files Browse the repository at this point in the history
  • Loading branch information
okayawright authored and binal-7span committed Jun 20, 2019
1 parent 1bb80a0 commit 3e0de0d
Show file tree
Hide file tree
Showing 5 changed files with 147 additions and 3 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,8 @@ composer.lock
# This will make sure empty directories has at least one file so it can be tracked by git
!**/.gitkeep
/docs/

#Override the PHP internal server rules for static files
#See https://github.com/slimphp/Slim/issues/1829
#php -S localhost:8000 cliserver.php
public/cliserver.php
2 changes: 2 additions & 0 deletions public/downloads/.htaccess
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
RewriteEngine On
RewriteRule (.*) index.php [L]
94 changes: 94 additions & 0 deletions public/downloads/index.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
<?php

require __DIR__ . '/../../vendor/autoload.php';

use Directus\Util\ArrayUtils;
use Directus\Filesystem\Thumbnailer;

$basePath = realpath(__DIR__ . '/../../');
// Get Project name
$projectName = \Directus\get_api_project_from_request();

try {
$app = \Directus\create_app_with_project_name($basePath, $projectName);
} catch (\Exception $e) {
http_response_code(404);
header('Content-Type: application/json');
echo json_encode([
'error' => [
'error' => 8,
'message' => 'API Project Configuration Not Found: ' . $projectName
]
]);
exit;
}

$filesystem = $app->getContainer()->get('filesystem')->getAdapter();

//Remove the project name from the URL
$path = urldecode(\Directus\get_virtual_path());
if (substr($path, 0, strlen($projectName)) == $projectName) {
$path = substr($path, strlen($projectName));
}

$settings = \Directus\get_directus_proxy_downloads_settings();
$timeToLive = \Directus\array_get($settings, 'proxy_downloads_cache_ttl', 86400);
try {

//Forward HTTP headers
$metadata = $filesystem->getMetadata($path);

header('HTTP/1.1 200 OK');
if (array_key_exists('mimetype', $metadata)) {
header('Content-type: ' . $metadata['mimetype']);
} else {
$mimetype = $filesystem->getMimetype($path);
if ($mimetype) {
header('Content-type: ' . $mimetype);
}
}
if (array_key_exists('size', $metadata)) {
header('Content-Length: ' . $metadata['size']);
} else {
$size = $filesystem->getSize($path);
if ($size) {
header('Content-Length: ' . $size);
}
}
header("Pragma: cache");
header('Cache-Control: max-age=' . $timeToLive);
header('Last-Modified: '. gmdate('D, d M Y H:i:s \G\M\T', time()));
header('Expires: '. gmdate('D, d M Y H:i:s \G\M\T', time() + $timeToLive));

//Forward HTTP body
$resource = $filesystem->readStream($path);
ob_end_flush();
fpassthru($resource);
exit(0);
}

catch (Exception $e) {
$filePath = ArrayUtils::get($settings, 'proxy_downloads_not_found_location');
if (is_string($filePath) && !empty($filePath) && $filePath[0] !== '/') {
$filePath = $basePath . '/' . $filePath;
}

// TODO: Throw message if the error is a invalid configuration
if (file_exists($filePath)) {
$mime = mime_content_type($filePath);

// TODO: Do we need to cache non-existing files?
if ($mime) {
header('Content-type: ' . $mime);
}
header("Pragma: cache");
header('Cache-Control: max-age=' . $timeToLive);
header('Last-Modified: ' . gmdate('D, d M Y H:i:s \G\M\T', time()));
header('Expires: ' . gmdate('D, d M Y H:i:s \G\M\T', time() + $timeToLive));
echo file_get_contents($filePath);
} else {
http_response_code(404);
}

exit(0);
}
34 changes: 31 additions & 3 deletions src/helpers/file.php
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ function append_storage_information(array $rows, array $params = [])
$container = Application::getInstance()->getContainer();

$config = $container->get('config');
$proxyDownloads = $config->get('storage.proxy_downloads');
$fileRootUrl = $config->get('storage.root_url');
$hasFileRootUrlHost = parse_url($fileRootUrl, PHP_URL_HOST);
$isLocalStorageAdapter = $config->get('storage.adapter') == 'local';
Expand All @@ -128,11 +129,17 @@ function append_storage_information(array $rows, array $params = [])

foreach ($rows as &$row) {
$data = [];
$data['url'] = $data['full_url'] = $fileRootUrl . '/' . $row['filename'];

// Add Full url
if ($isLocalStorageAdapter && !$hasFileRootUrlHost) {
if ($proxyDownloads) {
$data['url'] = get_proxy_path($row['filename']);
$data['full_url'] = get_url($data['url']);
} else {
$data['url'] = $data['full_url'] = $fileRootUrl . '/' . $row['filename'];

// Add Full url
if ($isLocalStorageAdapter && !$hasFileRootUrlHost) {
$data['full_url'] = get_url($data['url']);
}
}

// Add Thumbnails
Expand Down Expand Up @@ -278,6 +285,27 @@ function get_thumbnail_path($name, $width, $height, $mode = 'crop', $quality = '
}
}

if (!function_exists('get_proxy_path'))
{
/**
* Returns a relative url for the given file pointing to the proxy
*
* @param string $path
*
* @return string
*/
function get_proxy_path($path)
{
$projectName = get_api_project_from_request();

// env/width/height/mode/quality/name
return sprintf(
'/downloads/%s/%s',
$projectName, $path
);
}
}

if (!function_exists('filename_put_ext')) {
/**
* Appends an extension to a filename
Expand Down
15 changes: 15 additions & 0 deletions src/helpers/settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,21 @@ function get_directus_thumbnail_settings()
}
}

if (!function_exists('get_directus_proxy_downloads_settings')) {
/**
* Get all directus files settings
*
* @return array
*/
function get_directus_proxy_downloads_settings()
{
return get_directus_settings_by_keys([
'proxy_downloads_not_found_location',
'proxy_downloads_cache_ttl',
]);
}
}

if (!function_exists('get_directus_settings_by_keys')) {
/**
* Get all directus files settings
Expand Down

0 comments on commit 3e0de0d

Please sign in to comment.