Slim PHP 下载加载一个带有乱码的页面

问题描述 投票:0回答:1

我正在使用 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()并将其移动到不同的位置。什么都不起作用。该文件从未被下载。

php slim
1个回答
0
投票

您描述的乱码很可能是原始 JPEG 文件,因为它是二进制图片格式,这就是当您尝试将其显示为文本时二进制的样子。但是,如果您设置了

application/octet-stream
binary
,为什么要尝试将其显示为文本?如果您设置了
attachment
,为什么它会在线显示而不是下载?

因为您向

$response
添加标头,但从未用文件内容填充它。相反,您调用 readfile() 将文件写入输出缓冲区。因此,除非您有一个活动的输出缓冲区,否则就会发生这种情况:

  1. PHP 检测到
    readfile()
    开始发出响应正文,因此它会打印内置的和之前设置的标头,然后附加文件内容。
  2. Slim 处理响应并尝试发出您的自定义标头。这是不可能的,因为标头已经发送。 Slim 会在
    \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;
© www.soinside.com 2019 - 2024. All rights reserved.