我正在使用 Slim 4。我正在尝试下载文件,但是当我单击链接时,浏览器窗口加载了很多乱码,而不是下载文件。
项目结构
app (Controller is in here)
public (public site is here)
routes
uploads (file to download is here)
vendor
views
路线:
$app->get('/adm/download/', DownloadController::class . ':download')->setName('adm.download');
控制器:
public function download($request, $res, $args) {
$file = "/home/acct/public_html/project/uploads/application/ourfile.jpg";
$response = $res->withHeader('Content-Description', 'File Transfer')
->withHeader('Content-Type', 'application/octet-stream')
->withHeader('Content-Disposition', 'attachment;filename="'.basename($file).'"')
->withHeader('Content-Transfer-Encoding', 'binary')
->withHeader('Expires', '0')
->withHeader('Cache-Control', 'must-revalidate, post-check=0, pre-check=0')
->withHeader('Pragma', 'public')
->withHeader('Content-Length', filesize($file));
ob_clean();
flush();
readfile($file);
return $response;
}
查看:
<a href="{{ url_for('adm.download') }}">Download file</a>
我尝试删除ob_clean()和flush()并将其移动到不同的位置。什么都不起作用。该文件从未被下载。
您描述的乱码很可能是原始 JPEG 文件,因为它是二进制图片格式,这就是当您尝试将其显示为文本时二进制的样子。但是,如果您设置了
application/octet-stream
和 binary
,为什么要尝试将其显示为文本?如果您设置了 attachment
,为什么它会在线显示而不是下载?
因为您向
$response
添加标头,但从未用文件内容填充它。相反,您调用 readfile() 将文件写入输出缓冲区。因此,除非您有一个活动的输出缓冲区,否则就会发生这种情况:
readfile()
开始发出响应正文,因此它会打印内置的和之前设置的标头,然后附加文件内容。\Slim\ResponseEmitter::emit()
处检测到这一点,并完全忽略您的标头,因为否则会触发 无法修改标头信息 - 标头已由 PHP 发送警告。如果您使用的是Slim,则需要一直使用它。最直接的方法是填充响应正文:
$response
->getBody()
->write(file_get_contents($file));
但是有一个专门针对文件的方法:
$streamFactory = new \Slim\Psr7\Factory\StreamFactory();
$response = $res->withHeader('Content-Description', 'File Transfer')
->withHeader('Content-Type', 'application/octet-stream')
->withHeader('Content-Disposition', 'attachment;filename="' . basename($file) . '"')
->withHeader('Content-Transfer-Encoding', 'binary')
->withHeader('Expires', '0')
->withHeader('Cache-Control', 'must-revalidate, post-check=0, pre-check=0')
->withHeader('Pragma', 'public')
->withHeader('Content-Length', filesize($file))
->withBody($streamFactory->createStreamFromFile($file));
return $response;