PHP readfile()下载原始文件的精确副本

时间:2019-02-22 16:15:16

标签: php

标题可能会令人困惑,但我将在此处进行解释。

我有一个文件样本。该文件是一个简单的.xml文件,但具有.ciff扩展名和特定的编码(使用的编码为UCS2-LE BOM)。

TEST001.ciff中的内容是:

<?xml version="1.0" encoding="UTF-16"?>

仅此而已。

现在,我正尝试从浏览器下载此文件(不显示内容,而是实际上将其下载到downloads文件夹中),这是到目前为止我在download.php文件中使用的代码:

<?php
require_once('../../../private/initialize.php');
require_login();

// Redirect if the logged in user is not with admin level
if($session->level == 'user') {
    redirect_to(url_for('/index.php'));
}

include(SHARED_PATH . '/staff_header.php');

if (!empty(h($_GET['filename']))) {

    // We have filename request, lets try download it
    if (file_exists('Files/' . h($_GET['filename']))) { 

        // We have the file on the server so we can download it
        header("Pragma: public");
        header('Content-Description: File Transfer');
        header('Content-Type: application/octet-stream');
        header('Content-Disposition: attachment; filename="'.basename('Files/' . h($_GET['filename'])).'"');
        header('Expires: 0');
        header('Cache-Control: must-revalidate');
        header('Content-Length: ' . filesize('Files/' . h($_GET['filename'])));
        readfile('Files/' . h($_GET['filename']));
        exit;

    } else {
        // The file was not found on the server
        $session->message('The requested file was not found on the server.', false);
        redirect_to(url_for('staff/ciff/index.php'));
    }
} else {
    // The file request was invalid
    $session->message('Invalid file request.', false);
    redirect_to(url_for('staff/ciff/index.php'));
}

include(SHARED_PATH . '/staff_footer.php'); 
?>

到目前为止,当我单击下载超链接时,当我打开下载的文件时,文件TEST001.ciff被下载到我的下载文件夹中,但是可以看到以下内容:

<!doctype html>

<html lang="en">
<head>
<title>NESI Ticketing - Admin Area</title>
<meta charset="utf-8">
<link rel="stylesheet" media="all" href="/nesiticket/public/stylesheets/staff.css" />
</head>

<body>
<header>
  <h1>NESI Ticketing User Area</h1>
</header>

<navigation>
  <ul>
            <li>Hello,  FirstName LastName</li><br />
    <li><a href="/nesiticket/public/index.php">Home Page</a></li>
    <span>&nbsp;</span>
    <li><a href="/nesiticket/public/staff/index.php">Main Menu</a></li>
    <span>&nbsp;</span>
    <li><a href="/nesiticket/public/staff/logout.php">Logout</a></li>
          </ul>
</navigation>

ÿþ< ? x m l   v e r s i o n = " 1 . 0 "   e n c o d i n g = " U T F - 1 6 " ? > 

上面代码底部的部分在Notepad ++中看起来像这样 enter image description here

是否可以下载原始文件的精确副本?我的代码在哪里出错了?

2 个答案:

答案 0 :(得分:3)

问题肯定是包含HTML的PHP​​文件的出现。 如果PHP解析器遇到<?php ?>标记之外的其他任何内容,则该标记将作为字符串回显给接受它的任何客户端(您的浏览器,作为文件)。

如果这种包含发生在您的实际下载逻辑周围(例如在staff_header.php中),其中包含在输出中看到的HTML,就在实际文件内容之前,您当然会得到同时包含这两个文件的文件, HTML和文件内容,甚至可能使用错误的编码。

可能的解决方案各不相同,并且由于您已经在使用包含文件之类的PHP进行了比较低的工作,因此如果您在包含staff_header.php之前就将下载逻辑移到了正确的位置,可能就足够了。

随着下载代码的退出,如果您进行下载,将永远不会包含标头,但是请注意,通常,将这样的逻辑混淆起来是很不干净的。

即使是只是一个包含if子句的PHP文件来决定是否应执行下载或HTML逻辑,我还是建议将这种逻辑分开并以更高的顺序进行管理。

答案 1 :(得分:0)

这将读取文件并将其下载下载到浏览器。

这是php代码。

$filename = 'Files/' . h($_GET['filename'];

if(file_exists($filename)){

    //Get file type and set it as Content Type
    $finfo = finfo_open(FILEINFO_MIME_TYPE);
    header('Content-Type: ' . finfo_file($finfo, $filename));
    finfo_close($finfo);

    //Use Content-Disposition: attachment to specify the filename
    header('Content-Disposition: attachment; filename='.basename($filename));

    //No cache
    header('Expires: 0');
    header('Cache-Control: must-revalidate');
    header('Pragma: public');

    //Define file size
    header('Content-Length: ' . filesize($filename));

    ob_clean();
    flush();
    readfile($filename);
    exit;
}