1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
<?php
namespace JsonApi\Routes\Files;
use JsonApi\Errors\AuthorizationFailedException;
use JsonApi\Errors\InternalServerError;
use JsonApi\Errors\RecordNotFoundException;
use JsonApi\NonJsonApiController;
use Psr\Container\ContainerInterface;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Message\StreamFactoryInterface;
class FileRefsContentShow extends NonJsonApiController
{
use EtagHelperTrait;
public function __construct(
ContainerInterface $container,
private StreamFactoryInterface $streamFactory
) {
parent::__construct($container);
}
public function invoke(Request $request, Response $response, array $args): Response
{
if (!$fileRef = \FileRef::find($args['id'])) {
throw new RecordNotFoundException();
}
if (!Authority::canDownloadFileRef($this->getUser($request), $fileRef)) {
throw new AuthorizationFailedException();
}
return $this->sendFile($request, $response, $fileRef);
}
/**
* Copied and slightly edited for easy merging of future changes
* to sendfile.php.
*
* @SuppressWarnings(CyclomaticComplexity)
* @SuppressWarnings(NPathComplexity)
*/
private function sendFile(Request $request, Response $response, \FileRef $fileRef)
{
//replace bad charakters to avoid problems when saving the file
$fileName = \FileManager::cleanFileName($fileRef->name);
$filetype = $fileRef->getFileType();
$pathFile = $filetype->getPath() ?: $filetype->getDownloadURL();
$contentType = $fileRef->mime_type ?: get_mime_type($fileName);
// check if linked file is obtainable
if ('proxy' == $fileRef->file->metadata['access_type']) {
$linkData = \FileManager::fetchURLMetadata($fileRef->file->metadata['url']);
if (200 != $linkData['response_code']) {
throw new InternalServerError(
_('Diese Datei wird von einem externen Server geladen und ist dort momentan nicht erreichbar!')
);
}
$contentType = $linkData['Content-Type']
? strstr($linkData['Content-Type'], ';', true)
: get_mime_type($fileName);
$filesize = $linkData['Content-Length'] ?: false;
}
if ($filetype->getPath()) {
$filesize = @filesize($pathFile);
if (false === $filesize) {
throw new InternalServerError(
_('Fehler beim Laden der Inhalte der Datei')
);
}
[$done, $response] = $this->handleEtag($request, $response, $fileRef);
if ($done) {
return $response;
}
}
if ('redirect' == $fileRef->file->metadata['access_type']) {
return $response->withRedirect($fileRef->file->metadata['url']);
}
$contentBlacklisted = function ($mime) {
foreach (['html', 'javascript', 'svg', 'xml'] as $check) {
if (false !== stripos($mime, $check)) {
return true;
}
}
return false;
};
if ($contentBlacklisted($contentType)) {
$contentType = 'application/octet-stream';
}
$headers = [
'Content-Type' => $contentType,
'Content-Disposition' => 'attachment; '.encode_header_parameter('filename', $fileName),
];
if ($filesize) {
$headers['Content-Length'] = $filesize;
}
$isHttps = 'https' === $request->getUri()->getScheme();
$headers['Cache-Control'] = $isHttps
? 'private'
: 'no-cache, no-store, must-revalidate';
\Metrics::increment('core.file_download');
foreach ($headers as $key => $value) {
if ($response->hasHeader($key)) {
$response = $response->withAddedHeader($key, $value);
} else {
$response = $response->withHeader($key, $value);
}
}
$fileRef->incrementDownloadCounter();
$stream = $this->streamFactory->createStreamFromFile($pathFile, 'rb');
return $response->withBody($stream);
}
}
|