Adobe在线阅读器没有阅读所有pdf?

时间:2012-01-16 11:11:55

标签: header adobe-reader php

正如标题所说,我制作了一个脚本来阅读pdf文件。只能打开特定文件。所有上次修改至2008年9月29日的文件都可以打开。之后的所有文件都不能。

这是我的代码:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"   http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Stienser Omroeper</title>
</head>

<body>

<?php
$file = 'E:/Omrop/'.$_GET['y'].'/'.$_GET['f'];
$filename = $_GET['f'];

header('Content-type: application/pdf');
header('Content-Disposition: inline; filename="' . $filename . '"');
header('Content-Transfer-Encoding: binary');
header('Content-Length: ' . filesize($file));
header('Accept-Ranges: bytes');
@readfile($file);
?>
</body>
</html>

$ _GET包含y(地图结构的年份)和f(文件名)。如果我回复$ file后使用我的电脑上运行的链接它完美的工作。在浏览器中我收到消息此文件已损坏且无法修复..

任何人的想法?

1 个答案:

答案 0 :(得分:1)

此代码包含文件系统遍历漏洞。您没有执行导致该文件的参数的验证。磁盘上的文件被盲目打开并送到客户端。

如果您使用的是Unix系统怎么办?如果有人提交?y=&f=../../../etc/passwd会怎样?

这甚至没有涉及到您没有对用户所需的文件名进行任何类型的清理这一事实。用户可以在那里提交完全虚假的数据,并获得完全虚假的文件名。

此代码不会执行任何错误检查,甚至在使用readfile向用户投放文件时明确地将错误关闭。这是你问题的根源。没有人知道出了什么问题。

所以,我们可以解决这个问题。

首先,您需要对yf进行一些验证。你提到y是一年,所以

$year = (int)$_GET['y'];

应该做的伎俩。通过强制它成一个整数,你可以消除那里的任何可怕性。

f会变得有点棘手。您还没有告诉我们文件命名的内容。您将要添加一些模式匹配验证,以确保只查找有效的文件名。例如,如果所有PDF都命名为“report_something_0000.pdf”,那么您需要验证,比如说

$file = null;
if(preg_match('/^report_something_\d{4}\.pdf$/', $_GET['f'])) {
    $file = $_GET['f'];
}

现在我们已经有了有效的文件名和有效的年份目录,下一步是确保文件存在

$path = 'E:/Omrop/' . $year . '/' . $file;
if(!$file || !file_exists($path) || !is_readable($path)) {
    header('HTTP/1.0 404 File Not Found', true, 404);
    header('Content-type: text/html');
    echo "<h1>404 File Not Found</h1>";
    exit;
}

如果由于模式匹配失败而未设置$file,或者未找到生成的文件路径,则脚本将保释并显示错误消息。

我将猜测您打开旧版PDF的问题是由于文件不存在或权限不当造成的。您正在为Adobe Reader提供正确的标题,然后没有数据。

您还需要对用户提供的所需文件名执行相同类型的完整性检查。再说一次,我不知道你的要求,但要确保没有任何虚假可以潜入。

接下来,摆脱readfile前面的@。它会抑制任何实际错误,你会想要看到它们。因为您可能不希望在输出中看到它们,所以请务必设置error log

最后......这段代码怎么工作? 您正在HTML中间发出标题!不仅如此,您还要提供明确的内容长度。你应该从中得到很多错误。你确定你没有意外地复制/粘贴一些错误的代码吗?也许你忘了你打电话给ob_start()的顶部的一个部分?无论如何,在开始<?php标记之前抛弃所有