使用 PHP 下载 XLSX 文件

6

我需要让 xlsx 文件从我的网站下载(但不是直接打开文件的URL,如:http://site.com/file.xlsx

以下是PHP代码:

        $file = "somefile.xlsx";
        header('Content-Description: File Transfer');
        header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
        header('Content-Disposition: attachment; filename='.basename($file));
        header('Content-Transfer-Encoding: binary');
        header('Expires: 0');
        header('Cache-Control: must-revalidate');
        header('Pragma: public');
        header('Content-Length: ' . filesize($file));
        ob_clean();
        flush();
        readfile($file);

文件已下载,其扩展名为.xlsx,但在尝试在MS Excel中打开此文件时,文件未打开并出现错误:Excel无法打开文件.xlsx,因为文件格式或文件扩展名无效
请问,为什么会发生这种情况?我错在哪里了?

下载的文件包含什么内容? - Pekka
1
如果Excel抱怨该文件不包含有效的电子表格,我们必须假设它知道自己在说什么。有两种可能性:somefile.xlsx一开始就无效,或者在下载过程中添加了一些垃圾。如果您将下载的文件保存到磁盘并使用文本编辑器(而不是Excel)打开,您可能会发现哪些内容不属于该文件。 - Álvaro González
@ Pekka 웃,Álvaro --- 非常感谢,我遇到了错误。 - Oto Shavadze
请注意,如果您不希望通过直接链接访问文件,您应将该文件放置在Web服务器根目录之外,或者配置您的Web服务器禁止下载该文件类型。 - e4c5
4个回答

9

经过多年,我遇到了同样的问题,在搜索之后,我又回到了这里))

以下是解决方案,对我有效:

$file = "somefile.xlsx";
// define file $mime type here
ob_end_clean(); // this is solution
header('Content-Description: File Transfer');
header('Content-Type: ' . $mime);
header("Content-Transfer-Encoding: Binary");
header("Content-disposition: attachment; filename=\"" . basename($file) . "\"");
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
readfile($file);

4

你必须在其他文件的中间使用此代码。

头部的问题是它们需要在页面上首先设置。如果您在它们之前有任何一个空格被回显,它们将无法工作。因此,在设置头部之前,您需要执行ob_clean() [清除缓冲区]。

尝试:

    ob_clean();
    flush();
    $file = "somefile.xlsx";
    header('Content-Description: File Transfer');
    header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
    header('Content-Disposition: attachment; filename='.basename($file));
    header('Content-Transfer-Encoding: binary');
    header('Expires: 0');
    header('Cache-Control: must-revalidate');
    header('Pragma: public');
    header('Content-Length: ' . filesize($file));
    readfile($file);

2
使用 flush() 仍然导致错误。在设置头之前仅使用 ob_clean() 对我有用。 - seantunwin

2

移除:

ob_clean();
flush();

在代码末尾添加:
exit();

问题在于flush()函数也会将一些垃圾内容写入*.xlsx文件中,这将破坏你的文件,即使你使用了ob_clean()函数也无济于事。
为了更好地理解,请前往php.net网站并阅读flush()、ob_flush()之间的区别,你会发现在这种情况下甚至不需要它们。因此,你也不需要ob_clean()函数。

1
@OTARIKI 我搜索了一个可用的代码,找到了你的代码,进行了修复并使用了它。这就是为什么我也添加了答案 :) - besciualex

0
这对我有效:
    header('Content-Description: File Transfer');
    header("Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
    header("Content-Disposition: attachment; filename=\"".basename($fileLocation)."\"");
    header("Content-Transfer-Encoding: binary");
    header("Expires: 0");
    header("Pragma: public");
    header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
    header('Content-Length: ' . filesize($fileLocation)); //Remove

    ob_clean();
    flush();

    readfile($fileLocation);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接