我是一名实验室讲师,试图确保我的学生不能提前下载他们的入门文件,方法是将文件保存在webroot之上,并强迫他们登录(通过大学的LDAP进行身份验证),验证是否已过发布时间,然后使用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语句并相应地增加内容大小来验证这一点,并且文本不会出现在下载的文件中,所以我相对确信换行符不是来自那里。
确保PHP脚本不包含<?php ?>
标记中的空行。一般情况下,请确保除了文件之外,没有其他内容得到响应。
如果您在这里发布生成的文件内容,将非常有帮助。尝试使用一个简单的单行文本文件。