PHP网站显示文件而不是下载

3

我在Azure的Linux Web应用程序服务上运行一个PHP 8网站。当用户按下按钮时,我希望动态生成一个文件(从数据库读取数据)并将其下载。但实际上它会在页面上显示文件内容。以下是代码:

header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Type: text/csv; charset=utf-8');
header("Content-Disposition: attachment; filename=geodata.csv");
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize("geodata.csv"));

$file = fopen('php://output', 'w') 
            or die ("Unable to create file in write mode");
if (ob_get_contents()) ob_end_clean();
    fputcsv($output, array('name','loc','zip'), chr(6));
    $mrows = mysqli_query($myconnection, "SELECT name,loc,zip FROM geo_tbl WHERE sp = 'FL'");
    while ($mrow = mysqli_fetch_assoc($mrows)) {
        fputcsv($file, $mrow, chr(6));
    }
    fclose($file);
    readfile("geodata.csv");
    exit();

谢谢


你是否已经将PHP配置到你的Web服务器中? - RiggsFolly
没有看到你在哪里连接数据库,所以如果 $myconnection 从未设置,mysqli_query() 可能无法工作。 - RiggsFolly
只是补充一下,我可以看到在Azure上使用的Web服务器是nginx/1.14.2,PHP版本是8.0.3。 - Redzon
它正在显示文件的内容。因此,它成功获取了数据,但是只是将数据粘贴到页面上,而没有显示下载菜单。 - Redzon
@Alan。那是很好的观察。可惜,它没有解决问题。仍然看到内容。 - Redzon
显示剩余9条评论
3个回答

0

0

我看到代码存在以下几个问题:

  1. 正如Alan指出的那样,你有重复的Content-Type头文件。如果你把文件保存为附件,你只需要使用一个即可。

  2. 你在设置csv文件的Content-Type头文件之后,才输出die消息,导致消息无法正确显示。所以,在设置内容头之前应该先执行fopen语句。

  3. 你正在将输出的一部分发送到变量$output而不是$file,并且这个变量似乎没有被定义,例如:fputcsv($output, array('name','loc','zip'), chr(6));

  4. 你正在使用header('Content-Length: ' . filesize("geodata.csv"));设置一个Content-Length头文件,但此时你还不知道内容的长度。

  5. Content-Disposition头文件中应该在文件名周围加上双引号。

虽然不是错误,本身,但您正在使用 fetch_assoc 检索行,因此 $mrow 将包含键和值。您实际上只需要使用 fetch_row。我还对您使用的列分隔符 chr(6)(一个 ACK 字符)提出了疑问。您可能想使用 chr(9)(TAB)吗?

我认为以下是您所需的全部内容:

<?php

//define (DELIMITER, chr(9)); // Shouldn't it be this?
define (DELIMITER, chr(6));

if (ob_get_contents()) {
    ob_end_clean();
}
$file = fopen('php://output', 'w') or die ("Unable to create file in write mode");

header('Content-Type: text/csv');
header('Content-Disposition: attachment; filename="geodata.csv"');
header('Pragma: no-cache');
header('Expires: 0');

fputcsv($file, array('name','loc','zip'), DELIMITER);
$mrows = mysqli_query($myconnection, "SELECT name,loc,zip FROM geo_tbl WHERE sp = 'FL'");
while ($mrow = mysqli_fetch_row($mrows)) {
    fputcsv($file, $mrow, DELIMITER);
}
fclose($file);

0

正如其他人所说,您的代码存在几个问题。

但是,如果您只删除第二个content-type头,并将其保留为application/octet-stream,这应该会强制下载。

但是,您的内容长度将不会正确报告。也许将内容读入变量中,然后将该字符串的长度作为content-length头。


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