'PHP Download MP3 files from directory on server

I am attempting to download MP3 files to the user computer located in a directory named "songs" on the server. I have been able to run a script which downloads these files through the browser. However, these files download strictly as text with .mp3 extension. I want these files to be playable mp3 files upon downloading from the server.

Here is my PHP script.

<?php

$link = mysqli_connect("...","...","....","...") or die("Error ".mysqli_error($link));

if(mysqli_connect_errno())
{echo nl2br("Failed to connect to MySQL:". mysqli_connect_error() . "\n");}
else
{echo nl2br("Established Database Connection \n");}

//Script currently downloads a list of all songs found on server

$target = "songs/"; 


if ($handle = opendir($target)) {
    while (false !== ($entry = readdir($handle))) {
        if ($entry != "." && $entry != "..") {
            echo $entry."'>".$entry."</a>\n";
        }
    }
    closedir($handle);
}


$file = basename($_GET['file']);
$file = 'Songs_From_Server'.$file;

if(!$file){ // file does not exist
    die('file not found');
} else {


    header("Cache-Control: private");
    header("Content-type: audio/mpeg3");
    header("Content-Transfer-Encoding: binary");
    header("Content-Disposition: attachment; filename=".basename($file));   


    readfile($file);

}

?>

Here is an example of the result I get in a txt file.

Established Database Connection
01 In 1983 He Loved To Fly.mp3'>01 In 1983 He Loved To Fly.mp3



Solution 1:[1]

First, header()should be sent before any output which includes echo, print_r, any html, a blank space before the opening tag(eg. <?php). Refer to the manual

Second, if you want to response with the content of a file to the browser, your script should not output anything else. Any output besides the content will be considered a part of the content. Unless you send it as multipart and your client is able to handle it.

So, an example

<?php

$fileName = $_GET['file'];
$path = '/directory/contains/mp3/';
$file = $path.$fileName;

if (!file_exists($file)) {
    http_response_code(404);
    die();
}

header("Cache-Control: private");
header("Content-type: audio/mpeg3");
header("Content-Transfer-Encoding: binary");
header("Content-Disposition: attachment; filename=".$fileName);
//So the browser can display the download progress
header("Content-Length: ".filesize($file));

readfile($file);

Solution 2:[2]

This worked for me

header("Content-type: application/mp3");
header("Content-Disposition: attachment; filename=".$s['song_name']);
header('Pragma: no-cache');
header('Expires: 0');
//So the browser can display the download progress
readfile('uploads/'.$s['song_mp3']);
exit;

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Brahim Khallota
Solution 2 Tushar Saha