The title might be confusing but I'll try to explain here.

I have a sample of file. This file is a simple .xml file but with .ciff extension and a specific encoding (the encoding used is UCS2-LE BOM).

The contents in the TEST001.ciff are:

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

that's all.

Now I'm trying to download this file from a browser (not showing the content but actually download it in the downloads folder) and this is the code I'm using so far in my download.php file:

<?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'); 
?>

So far so good, when i click on the download hyperlink a file TEST001.ciff is downloaded into my downloads folder BUT when I open the downloaded file i can see this content:

<!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 " ? > 

The part at the bottom of the code above looks like this in Notepad++ enter image description here

Is it possible that I can download an exact copy of the original file? Where have i gone wrong in my code?

2 Answers

2
TheKvist On Best Solutions

You're problem is most certainly the inclusion of PHP files that contain HTML surrounding your actual download logic. PHP just outputs HTML if present in included files and so you're getting the included HTML followed by your file contents. The solution is probably to move the download logic before the inclusion of the files containing HTML and you should be fine.

0
Vidal On

This will read the file and send it to the browser as download.

Here the php code.

$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;
}