PHP 强制下载并刷新解决方案不起作用
PHP force download and refresh SOLUTION not working
最终目标:单击第 1 页上的链接,最终下载文件并刷新第 1 页。 使用 PHP 提供不在公共 html 中的下载。
方法:
第 1 页。链接转移到第 2 页,并获取我正在使用的文件的变量引用。
第 2 页。使用刷新第 1 页之前需要更新的信息更新相关 SQL 数据库。设置"首次传递"会话变量。从 get 变量设置会话变量"getvariablereference"。 重定向至第 1 页。
第 1 页。如果设置了第一次传递会话变量。 设置第二遍会话变量。未设置第一遍变量。刷新页面。 重新加载时,将使用更新的 SQL 数据库信息(在第 2 页上更改)重新生成页面。
刷新了第 1 页。如果设置了第二遍会话变量。运行下载服务标头序列。
这是第 1 页。我没有显示第 1 页中具有初始链接的部分。 既然没关系。
// REFERSH IF FIRSTPASS IS LIVE
if ($_SESSION["PASS1"] == "YES"){
$_SESSION["PASS1"] = "no";
$_SESSION["PASS2"] = "YES";
echo "<script>document.location.reload();</script>";
}
if ($_SESSION["PASS2"] == "YES"){
// Grab reference data from session:
$id = $_SESSION['passreference'];
// Serve the file download
//First find the file location
$query = "SELECT * from rightplace
WHERE id = '$id'";
$result = mysql_query($query);
$row = mysql_fetch_array($result);
$filename = $row['file'];
$uploader = $row['uploader'];
// Setting up download variables
$string1 = "/home/domain/aboveroot/";
$string2 = $uploader;
$string3 = '/';
$string4 = $filename;
$file= $string1.$string2.$string3.$string4;
$ext = strtolower (end(explode('.', $filename)));
//Finding MIME type
if($ext == "pdf" && file_exists($file)) {
header("Content-disposition: attachment; filename= '$filename'");
header('Content-type: application/pdf');
readfile($file);
}
if($ext == "doc" && file_exists($file)) {
header("Content-disposition: attachment; filename= '$filename'");
header('Content-type: application/msword');
readfile($file);
}
if($ext == "txt" && file_exists($file)) {
header("Content-disposition: attachment; filename= '$filename'");
header('Content-type: text/plain');
readfile($file);
}
if($ext == "rtf" && file_exists($file)) {
header("Content-disposition: attachment; filename= '$filename'");
header('Content-type: application/rtf');
readfile($file);
}
if($ext == "docx" && file_exists($file)) {
header("Content-disposition: attachment; filename= '$filename'");
header('Content-type: application/vnd.openxmlformats-officedocument.wordprocessingml.document');
readfile($file);
}
if($ext == "pptx" && file_exists($file)) {
header("Content-disposition: attachment; filename= '$filename'");
header('Content-type: application/vnd.openxmlformats-officedocument.presentationml.presentation');
readfile($file);
}
if($ext == "ppt" && file_exists($file)) {
header("Content-disposition: attachment; filename= '$filename'");
header('Content-type: application/vnd.ms-powerpoint');
readfile($file);
}
}
第 2 页上的脚本工作正常。 它会更新 sql 数据库并正确重定向到主页。我还检查了它是否正确设置了"$_SESSION['passreference'];",并且第 1 页上的任何内容都不会取消设置它。
所以,这就是对情况的整个长篇解释。 我被难住了。 正如我所说,发生的情况是第 2 页工作正常。 然后它踢到第 1 页,刷新,然后不推送任何下载。 我知道下载脚本有效,并且文件可以下载(在没有整个刷新序列的情况下进行检查)。
我基本上有两个问题:
谁能发现出了什么问题?
任何人都可以概念化更好的方法吗?
即使给定代码,也很难远程调试这样的东西,您发布的片段可以按照您所说的那样工作。您是否检查过错误日志?最有可能的罪魁祸首是在完成其他输出后发送header()
的问题。
在处理文件下载时,我认为尽可能在新页面/窗口上启动下载会更容易,这样就不会有破坏标题的风险。也许使用启动实际下载的第三页稍微更改的序列:
- 第 1 页链接到第二页以
- 执行魔术,该页面重定向回第 1 页 然后,第 1 页会在
- 新窗口中生成第 3 页,从而启动下载。
在这个答案中,有一个很好的示例代码,用于加载下载的新窗口。
查看您的代码,下载问题可能是 $ext
变量包含意外值,或者 $file
变量包含实际上不存在的文件的名称。
在这两种情况下,您的"如果"条件都不会成立,因此下载不会开始。
我的建议是在" //Finding MIME type
"注释行之前添加以下语句:
$log = "file='".$file."''n";
$log .= "ext='".$ext."''n";
@file_put_contents("/tmp/page1.log", $log, FILE_APPEND);
这样,查看"/tmp/page1.log"文件,您应该能够检查$file
和$ext
变量是否有效地包含预期值。
我使用"/tmp/page1.log"作为日志文件名,因为我认为您正在处理 linux;如果没有,请使用适合您环境的有效路径和文件名调整"file_put_contents"函数的第一个参数。
此外,我会用以下代码替换"if"测试序列:
$content_types = array(
"pdf" => "application/pdf",
"doc" => "application/msword",
"txt" => "text/plain",
"rtf" => "application/rtf",
"docx" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"pptx" => "application/vnd.openxmlformats-officedocument.presentationml.presentation"
);
if (isset($content_types[$ext])) {
if (file_exists($file)) {
header("Content-disposition: attachment; filename= '$filename'");
header('Content-type: '.$content_types[$ext]);
readfile($file);
die("");
} else {
die("** '".$file."' does not exist **");
}
} else {
die("** Unhandled '".$ext."' extension **");
}
显然,你应该以更健壮的方式实现错误处理,而不是像我一样简单地使用"die()"函数,但这只是一个示例。
最后,请注意,还有更好的方法来获取与文件扩展名对应的内容类型;例如,一种解决方案是使用 PHP Fileinfo 函数。
有关此主题的更多信息,请查看此答案。
另请记住,在安全模式下,file_exists函数始终返回 FALSE,并且缓存file_exists函数的结果;有关更多详细信息,请参阅 PHP 手册中的 clearstatcache() 函数。
我只是稍微修改了一下你的PHP代码。特别是你会得到更多关于出了什么问题的信息。只需尝试此代码并阅读以下注释,这些注释解释了如果您收到新的错误消息之一,则发生了什么。另请阅读下面的 NOTE 部分,它解释了为什么您可能无法从 PHP 访问文件,即使它存在并且位于正确的目录中。
- 使用 window.location.reload(); 而不是 document.location...
- 我添加了一个错误()函数。您可以向其添加更多 HTML,以便它在您想要的布局中生成页面。您也可以将错误记录到本地文件中。有一个私有信息参数用于将合理信息作为数据库错误(可能包含 SQL)传递给函数。对于生产用途,不应向用户显示该内容。相反,您可以将其登录到文件中或仅对特权用户(例如管理员)显示。
- 检查天气$id是否设置。如果没有,则返回错误() 消息;如果会话未正确更新,则可能会发生。
- 出于安全原因,我添加了"$id = addslashes($id);"。例如,如果您的 id 可以设置为 $id = "' OR 1"(SQL 注入)之类的值,您可能会遇到麻烦。如果您确定这不会发生,则可以将其删除。
- 它在数据库查询后检查$result变量。例如,如果您的数据库连接未建立或脚本无法连接,这将产生一个 error() 输出来通知您。如果您的 SQL 语法有错误,例如表名错误,也会发生同样的情况。 它还检查天气,从
- 数据库中获取有效的$row。如果没有返回一行,则您的$id可能是错误的(数据库中没有这样的条目)。
- 我将您的字符串操作重写为 $filepath = $rootpath .'"/'" .$uploader .'"/'" .$filename;其中 $rootpath 设置在前面,末尾没有"/";这更容易阅读...
- 扩展和MIME类型现在被放入一个数组中,而不是使用大量的"if-then"块,这更容易维护。此外,块中的代码也相似...所以我们只需要写一次。
- 如果文件扩展名未知,则发送默认 MIME 类型(内容类型:"应用程序/八位字节流")。
- 我们检查 file_exists() 并输出一条错误消息,并给出$filename以允许检查天气路径是否正确......
所以这是源代码:
<?php
function error($message, $info = "") {
echo "ERROR: $message<br>";
echo "PRIVATE-INFO: $info"; // probably you only want to log that into a file?
exit;
}
// REFERSH IF FIRSTPASS IS LIVE
if ($_SESSION["PASS1"] == "YES") {
$_SESSION["PASS1"] = "no";
$_SESSION["PASS2"] = "YES";
echo "<script>window.location.reload();</script>";
exit;
}
if ($_SESSION["PASS2"] == "YES") {
// Grab reference data from session:
$id = $_SESSION['passreference'];
if (!$id) error("Internal Error ('id' not set)");
// Select file location from DB
$id = addslashes($id);
$query = "SELECT * from rightplace WHERE id = '$id'";
$result = mysql_query($query);
if (!$result) error("DB-query execution error", mysql_error());
$row = mysql_fetch_array($result);
mysql_free_result($result);
if (!$row) error("File with ID '$id' was not found in DB.");
$filename = $row['file'];
$uploader = $row['uploader'];
// Setting up download variables
$rootpath = "/home/domain/aboveroot";
$filepath = $rootpath . "/" . $uploader . "/" . $filename;
$ext = strtolower(end(explode('.', $filename)));
// Serve the file download
// List of known extensions and their MIME-types...
$typelist = array(
"pdf" => "application/pdf",
"doc" => "application/msword",
"txt" => "text/plain",
"rtf" => "application/rtf",
"docx" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"pptx" => "application/vnd.openxmlformats-officedocument.presentationml.presentation",
"ppt" => "application/vnd.ms-powerpoint"
);
// set default content-type
$type = "application/octet-stream";
// for known extensions, assign specific content-type
if (!isset($typelist[$ext])) $type = $typelist[$ext];
if (file_exists($filepath)) {
header("Content-disposition: attachment; filename= '$filename'");
header("Content-type: $type");
readfile($filepath);
} else {
error("Error: File '$filepath' was not found!", $filepath);
}
}
?>
笔记:
即使文件存在,也可能发生找不到文件错误。如果发生这种情况,这很可能是一种安全机制,阻止 PHP 脚本访问 HTML 根目录之外的文件。例如,php脚本可以在"chrooted"环境中执行,其中根目录"/"被映射到例如"/home/username/"。因此,如果你想访问"/home/username/dir/file",你需要在你的PHP脚本中写"/dir/file"。如果您的根设置为"/home/username/html",情况可能会更糟;然后,您将无法访问"html"目录下的目录。要解决此问题,您可以在HTML根目录中创建一个目录,并将一个名为".htaccess"的文件放在那里。在其中写入"DENY FROM ALL",这将阻止浏览器请求访问目录(只有脚本才能访问它)。这仅适用于 apache 服务器。但是对于其他服务器软件也有这样的解决方案......有关这方面的更多信息,请访问:http://www.php.net/manual/en/ini.core.php#ini.open-basedir
另一种可能性是您的文件访问权限(对于上传的文件)没有以某种方式设置,您的脚本被允许访问它们。启用某些安全设置(在 linux 服务器上)后,PHP 脚本只能访问与脚本文件的"所有者"集相同的用户拥有的文件。通过"ftp"上传后,这很可能是ftp用户的用户名。如果在 shell 上编辑,这将是当前用户的用户名。=> 但是:上传的文件有时会分配给运行网络服务器的用户(例如"www-data"、"www-run"或"apache")。因此,找出它是什么并将您的脚本分配给此所有者。
- 对于文件上传,您应该使用 move_uploaded_file(...),解释如下:www.php.net/manual/en/function.move-uploaded-file.php ;如果不这样做,文件访问权限可能是错误的,或者您可能无法访问该文件。
- 可以转换显示属性吗?如果没有,什么'这是最好的解决方案
- iPad虚拟键盘-哪一个-javasctript解决方案
- AJAX HTTP基本身份验证解决方案
- 在chrome web商店中打开时,是否有允许执行内容/后台脚本的解决方案
- Chart.js-添加渐变而不是纯色-实现解决方案
- learnyounode杂耍异步解决方案不工作
- 了解因子分解解决方案
- 提交表单后的最佳解决方案
- 计时器在使用 jQuery 一分钟后没有触发,或者每 1 分钟后给出一些其他解决方案来触发功能
- chrome中的意外全局变量有解决方案吗
- 更好的解决方案HTML元素幻灯片从右侧CSS转换
- 使用SeleniumWebdriver将文本复制到文件时出现编译错误的解决方案
- 如何让我的网站上的WEBP图像加载在morzilla firefox中有一个可能的解决方案吗?如果是,那么如何
- JS驱动的常见问题页面的推荐DB解决方案
- 这里有一个更优雅的/DRY/可维护的JS解决方案
- PHP 强制下载并刷新解决方案不起作用
- 在不刷新的情况下更改页面 URL - 是否有跨浏览器解决方案
- jQuery Mobile 嵌套列表刷新解决方案
- Javascript在页面刷新后工作,不知道解决方案
- 如何阻止用户点击任何其他按钮,而页面刷新(从模态窗口解决方案的一部分)