Skip to content

Commit 0c83c4f

Browse files
committed
ACP2E-1627: [Cloud] Magento Product Recommendation/Data Services Causing File Download Warning
1 parent 4a66488 commit 0c83c4f

File tree

2 files changed

+179
-29
lines changed

2 files changed

+179
-29
lines changed
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Framework\App\Response;
9+
10+
use Magento\Framework\App\Filesystem\DirectoryList;
11+
use Magento\Framework\App\Http\Context;
12+
use Magento\Framework\App\Request\Http as HttpRequest;
13+
use Magento\Framework\Filesystem;
14+
use Magento\Framework\Filesystem\Driver\File\Mime;
15+
use Magento\Framework\Session\Config\ConfigInterface;
16+
use Magento\Framework\Stdlib\Cookie\CookieMetadataFactory;
17+
use Magento\Framework\Stdlib\CookieManagerInterface;
18+
use Magento\Framework\Stdlib\DateTime;
19+
20+
/**
21+
* @SuppressWarnings(PHPMD.CookieAndSessionMisuse)
22+
*/
23+
class File extends Http
24+
{
25+
/**
26+
* @var Http
27+
*/
28+
private Http $response;
29+
30+
/**
31+
* @var Filesystem
32+
*/
33+
private Filesystem $filesystem;
34+
35+
/**
36+
* @var Mime
37+
*/
38+
private Mime $mime;
39+
40+
/**
41+
* @var array
42+
*/
43+
private array $fileOptions = [
44+
'directoryCode' => DirectoryList::ROOT,
45+
'filePath' => null,
46+
// File name to send to the client
47+
'fileName' => null,
48+
'contentType' => null,
49+
'contentLength' => null,
50+
// Whether to remove after file is sent to the client
51+
'remove' => false,
52+
];
53+
54+
/**
55+
* @param HttpRequest $request
56+
* @param Http $response
57+
* @param CookieManagerInterface $cookieManager
58+
* @param CookieMetadataFactory $cookieMetadataFactory
59+
* @param Context $context
60+
* @param DateTime $dateTime
61+
* @param ConfigInterface $sessionConfig
62+
* @param Filesystem $filesystem
63+
* @param Mime $mime
64+
* @param array $fileOptions
65+
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
66+
*/
67+
public function __construct(
68+
HttpRequest $request,
69+
Http $response,
70+
CookieManagerInterface $cookieManager,
71+
CookieMetadataFactory $cookieMetadataFactory,
72+
Context $context,
73+
DateTime $dateTime,
74+
ConfigInterface $sessionConfig,
75+
Filesystem $filesystem,
76+
Mime $mime,
77+
array $fileOptions = []
78+
) {
79+
parent::__construct($request, $cookieManager, $cookieMetadataFactory, $context, $dateTime, $sessionConfig);
80+
$this->filesystem = $filesystem;
81+
$this->response = $response;
82+
$this->mime = $mime;
83+
$this->fileOptions = array_merge($this->fileOptions, $fileOptions);
84+
}
85+
86+
/**
87+
* @inheritDoc
88+
*/
89+
public function sendResponse()
90+
{
91+
if ($this->fileOptions['filePath']) {
92+
$dir = $this->filesystem->getDirectoryWrite($this->fileOptions['directoryCode']);
93+
$filePath = $this->fileOptions['filePath'];
94+
$contentType = $this->fileOptions['contentType']
95+
?? $dir->stat($filePath)['mimeType']
96+
?? $this->mime->getMimeType($dir->getAbsolutePath($filePath));
97+
$contentLength = $this->fileOptions['contentLength']
98+
?? $dir->stat($filePath)['size'];
99+
$fileName = $this->fileOptions['fileName']
100+
?? basename($filePath);
101+
$this->response->setHttpResponseCode(200);
102+
$this->response->setHeader('Content-type', $contentType, true)
103+
->setHeader('Content-Length', $contentLength)
104+
->setHeader('Content-Disposition', 'attachment; filename="' . $fileName . '"', true)
105+
->setHeader('Pragma', 'public', true)
106+
->setHeader('Cache-Control', 'must-revalidate, post-check=0, pre-check=0', true)
107+
->setHeader('Last-Modified', date('r'), true);
108+
109+
$this->response->sendHeaders();
110+
111+
if (!$this->request->isHead()) {
112+
$stream = $dir->openFile($filePath, 'r');
113+
while (!$stream->eof()) {
114+
// phpcs:ignore Magento2.Security.LanguageConstruct.DirectOutput
115+
echo $stream->read(1024);
116+
}
117+
$stream->close();
118+
if ($this->fileOptions['remove']) {
119+
$dir->delete($filePath);
120+
}
121+
$this->response->clearBody();
122+
}
123+
}
124+
return $this;
125+
}
126+
127+
/**
128+
* @inheritDoc
129+
*/
130+
public function setHeader($name, $value, $replace = false)
131+
{
132+
$this->response->setHeader($name, $value, $replace);
133+
return $this;
134+
}
135+
136+
/**
137+
* @inheritDoc
138+
*/
139+
public function getHeader($name)
140+
{
141+
return $this->response->getHeader($name);
142+
}
143+
144+
/**
145+
* @inheritDoc
146+
*/
147+
public function clearHeader($name)
148+
{
149+
return $this->response->clearHeader($name);
150+
}
151+
}

lib/internal/Magento/Framework/App/Response/Http/FileFactory.php

Lines changed: 28 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88
namespace Magento\Framework\App\Response\Http;
99

1010
use Magento\Framework\App\Filesystem\DirectoryList;
11+
use Magento\Framework\App\ObjectManager;
12+
use Magento\Framework\App\ResponseInterface;
13+
use Magento\Framework\Filesystem;
1114

1215
/**
1316
* Class FileFactory serves to declare file content in response for download.
@@ -17,6 +20,8 @@
1720
class FileFactory
1821
{
1922
/**
23+
* @deprecared
24+
* @see $fileResponseFactory
2025
* @var \Magento\Framework\App\ResponseInterface
2126
*/
2227
protected $_response;
@@ -27,15 +32,24 @@ class FileFactory
2732
protected $_filesystem;
2833

2934
/**
30-
* @param \Magento\Framework\App\ResponseInterface $response
31-
* @param \Magento\Framework\Filesystem $filesystem
35+
* @var \Magento\Framework\App\Response\FileFactory
36+
*/
37+
private $fileResponseFactory;
38+
39+
/**
40+
* @param ResponseInterface $response
41+
* @param Filesystem $filesystem
42+
* @param \Magento\Framework\App\Response\FileFactory $fileResponseFactory
3243
*/
3344
public function __construct(
3445
\Magento\Framework\App\ResponseInterface $response,
35-
\Magento\Framework\Filesystem $filesystem
46+
\Magento\Framework\Filesystem $filesystem,
47+
?\Magento\Framework\App\Response\FileFactory $fileResponseFactory = null
3648
) {
3749
$this->_response = $response;
3850
$this->_filesystem = $filesystem;
51+
$this->fileResponseFactory = $fileResponseFactory
52+
?? ObjectManager::getInstance()->get(\Magento\Framework\App\Response\FileFactory::class);
3953
}
4054

4155
/**
@@ -79,38 +93,23 @@ public function create(
7993
$contentLength = $dir->stat($file)['size'];
8094
}
8195
}
82-
$this->_response->setHttpResponseCode(200)
83-
->setHeader('Pragma', 'public', true)
84-
->setHeader('Cache-Control', 'must-revalidate, post-check=0, pre-check=0', true)
85-
->setHeader('Content-type', $contentType, true)
86-
->setHeader('Content-Length', $contentLength === null ? strlen((string)$fileContent) : $contentLength, true)
87-
->setHeader('Content-Disposition', 'attachment; filename="' . $fileName . '"', true)
88-
->setHeader('Last-Modified', date('r'), true);
8996

9097
if ($content !== null) {
91-
$this->_response->sendHeaders();
92-
if ($isFile) {
93-
$stream = $dir->openFile($file, 'r');
94-
while (!$stream->eof()) {
95-
// phpcs:ignore Magento2.Security.LanguageConstruct.DirectOutput
96-
echo $stream->read(1024);
97-
}
98-
} else {
98+
if (!$isFile) {
9999
$dir->writeFile($fileName, $fileContent);
100100
$file = $fileName;
101-
$stream = $dir->openFile($fileName, 'r');
102-
while (!$stream->eof()) {
103-
// phpcs:ignore Magento2.Security.LanguageConstruct.DirectOutput
104-
echo $stream->read(1024);
105-
}
106-
}
107-
$stream->close();
108-
flush();
109-
if (!empty($content['rm'])) {
110-
$dir->delete($file);
111101
}
112102
}
113-
return $this->_response;
103+
return $this->fileResponseFactory->create([
104+
'fileOptions' => [
105+
'filePath' => $file,
106+
'fileName' => $fileName,
107+
'contentType' => $contentType,
108+
'contentLength' => $contentLength,
109+
'directoryCode' => $baseDir,
110+
'remove' => is_array($content) && !empty($content['rm'])
111+
]
112+
]);
114113
}
115114

116115
/**

0 commit comments

Comments
 (0)