Hello,

I currently have this setup for a "download a mp3" php page:

<?php
include "class.php";
$account = new account(0);
$id = $_GET['id'];
$u = $_COOKIE['username'];
$a = mysql_fetch_array(mysql_query("SELECT * FROM items WHERE id='$id'"));
$file = $a['actualPath'];
header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-Disposition: attachment; filename=$file");
header("Content-Type: audio/mpeg");
header("Content-Transfer-Encoding: binary");
$q = mysql_query("SELECT * FROM boughtItems WHERE username='$u' AND item='$id'");
if(mysql_num_rows($q) >= 1 || $account->isAdmin() || $account->isServiceRep() || $account->isLoggedIn()){
	//Allow download
	$account->newDownload($id);
	readfile($file);
	print "You may close this tab/window";
}else{
	print "Error: Not authorized";
}
?>

I know that the SQL isn't the best... but let me quickly explain the actual code (functions):

$_COOKIE is a username determining if they are logged in (I know... sessions would likely be better)

$account is a class file (class.php)
isAdmin() checks if admin, returns true/false respectivly
isServiceRep() and isLoggedIn() do the same.

newDownload() is essentially a hit counter.

Then we have the headers, This is where (i think) the issue is.

My headers work in Chrome (I actually get the file) but don't work in:

  • Firefox (In fact it grabs the wrong filename, it assumes a folder, eg full/song.mp3 is really full_song.mp3)
  • Opera (Shows a 0 byte file, gets filename right though.)
  • IE (Same a firefox)
  • Safari (Similar to firefox - shows a - instead of a _)

As well, the text doesn't show up (print) with it's current code or echo.

If anyone can help me with these issues, I would greatly appreciate it!

(If you are looking for a URL of the above code: )

-- Turt2Live

Dani AI

Generated

A few practical fixes that address the cross-browser behaviour seen by and build on the directions from and .

Common causes: sending the full path in the Content-Disposition filename (browsers mangle slashes), missing Content-Length, leftover output or BOM before headers, output compression interfering with binary streaming, and printing text after the file stream (that text is not shown and may corrupt the download). The best-practice approach is: send only the basename for the filename, quote and escape the name, provide an RFC5987-style filename* for UTF-8 names, set Content-Length, clear output buffers and turn off zlib compression, then stream and exit.

Example header sequence to use (replace variables safely and confirm filesize() and file_exists() first):

// $file = '/path/to/full/song.mp3';
$base = basename($file);
$escaped = str_replace('"', '\"', $base);
if (ob_get_level()) { ob_end_clean(); }
@ini_set('zlib.output_compression', '0');

header('Content-Description: File Transfer');
header('Content-Type: audio/mpeg');
header('Content-Disposition: attachment; filename="'.$escaped.'"; filename*=UTF-8\'\''.rawurlencode($base));
header('Content-Length: '.filesize($file));
readfile($file);
exit;

Extra notes: do not echo any HTML before/after streaming. For secure production code replace mysql_* with prepared statements (mysqli/PDO), validate/sanitize IDs to prevent path traversal, and use sessions instead of raw cookies for auth. Older IE over HTTPS may also need Pragma: public and specific cache headers; log download attempts server-side rather than trying to print a message into the file stream.

Recommended Answers

All 3 Replies

Hi, try this......

Download My Hit Single

<?PHP
 // Define the path to file
 $file = 'ryboe_tag_cloud.zip';

 if(!file)
 {
     // File doesn't exist, output error
     die('file not found');
 }
 else
 {
     // Set headers
     header("Cache-Control: public");
     header("Content-Description: File Transfer");
     header("Content-Disposition: attachment; filename=$file");
     header("Content-Type: application/zip");
     header("Content-Transfer-Encoding: binary");

     // Read the file from disk
     readfile($file);
 }
 ?>

web development in toronto

I tried those headers, and it caused the same browsers with problems to download it as a .zip file... not .mp3

<?php
include "class.php";
$account = new account(0);
$id = $_GET['id'];
$u = $_COOKIE['username'];
$a = mysql_fetch_array(mysql_query("SELECT * FROM items WHERE id='$id'"));

$path = $_SERVER['DOCUMENT_ROOT'].$a['actualPath']; // make sure file exists at this path 
$fullPath = $path.$_GET['download_file'];

if ($fd = fopen ($fullPath, "r")) {
    $fsize = filesize($fullPath);
    $path_parts = pathinfo($fullPath);
    $ext = strtolower($path_parts["extension"]);
    switch ($ext) {
        case "pdf":
        header("Content-type: application/pdf"); 
        header("Content-Disposition: attachment; filename=\"".$path_parts["basename"]."\"");
        break;
        default;
        header("Content-type: application/octet-stream");
        header("Content-Disposition: filename=\"".$path_parts["basename"]."\"");
    }
    header("Content-length: $fsize");
    header("Cache-control: private"); 
    while(!feof($fd)) {
        $buffer = fread($fd, 2048);
        echo $buffer;
    }
}
fclose ($fd);
exit;
?>
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.