我是一名实验室讲师,并试图通过将文件保留在 webroot 之上并强制他们登录(通过大学的 LDAP 进行身份验证)来确保我的学生无法提前下载他们的入门文件,并验证它是否已经过发布time 然后使用 readfile 将文件发送给他们。不幸的是,我发送的任何文件最终都已损坏。
我的代码是:
if (file_exists($path)) {
//header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.basename($path));
//header('Content-Transfer-Encoding: binary');
header('Expires:' . date('r', 0));
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
//header('Pragma: public');
header('Content-Length: ' . filesize($path));
//ob_clean();
//flush();
readfile($path);
exit(0);
}
我什至尝试只发送也没有正确传输的纯文本,结果只是乱码。
编辑:
抱歉,我疏忽了我已经尝试过的内容。我确实尝试发送一个简单的文本文件(尝试在记事本中检查 pdf 以查找 PHP 警告有点多)。
我发送了一个仅包含内容的文件,This is plain text
结果纯属胡言乱语。主要是不可打印的字符。 1f 8b 08 00 00 00 00 00 00 03 0b c9 c8 2c 56 00 a2 82 9c 00
更新:
在其中一台服务器上禁用 gzip,文件仍然损坏。删除ob_clean(); flush()
并且文本文件开始干净地通过(无法相信您在互联网上阅读的所有内容:/)。
Zip 文件仍然损坏,但我的 PDF 现在可以阅读了。再看一些,似乎在文件的开头添加了一个额外的换行符。回顾一下文本文件,它的前面确实有一个额外的换行符,并且最后一个字符丢失了。正如预期的那样,添加+1
到 Content-Length 标头可以让最后一个字符通过,仍然在寻找前置换行符的来源。此外,如果我注释掉readfile
我会得到一个只有 CRLF ( 0d0a
) 的文件。
框架通常用视图和布局“包装”来自控制器的内容,但两者都设置为空白文件,并且头控制器正在检查它们是否为空白,然后跳过该行以回显生成的 HTML。即使这样,exit(0)
也应该确保在传输后只调用析构函数。我通过在布局和视图中放置 echo 语句并相应地增加内容大小来验证这一点,并且该文本没有最终出现在下载的文件中,所以我相对确定换行符不是来自那里。