Search code examples
phpdownloadcorrupt

PHP: Header Force Download Corrupt (MP3 File)


I'm creating a simple website that lets you download songs. However, my script will download the mp3 file, but when I try to open it, it is corrupted in someway. Not only that, but the file size has decreased significantly.

Code:

function send_download($file)
    {
        $basename = basename($file);
        $length   = sprintf("%u", filesize($file));

        header('Content-Description: File Transfer');
        header('Content-Type: application/octet-stream');
        header('Content-Disposition: attachment; filename="' . $basename . '"');
        header('Content-Transfer-Encoding: binary');
        header('Connection: Keep-Alive');
        header('Expires: 0');
        header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
        header('Pragma: public');
        header('Content-Length: ' . $length);

        set_time_limit(0);
        readfile($file);
    }

I have been searching on here and Google for hours. Any help?

Thanks in advance.

Seems this wasn't enough, here is my whole php file:

<?php

error_reporting(0);
echo "<style>
        body {
            font-family: Verdana;
            background-color:#D9DDDB;
            color:black;
        }
    </style>
";

echo "<br><br><br><center><h1>Your Download is Starting...</h1></center><br><br><br><center><p>Copyright&copy; 2015 <font color='blue'>MusicProductionZ</font></p></center>";

if(isset($_GET['access_token'])) {
        if($_GET['access_token'] == '3486784401') {

            if(isset($_GET['file_name'])) {


                // Add More Here
                switch($_GET['file_name']) {
                    case 'fettywap_trapqueen':
                        $filename = "/files/fettywap_trapqueen/Fetty Wap - Trap Queen.mp3";
                        send_download($filename);
                        exit;
                        break;
                    default:
                        break;
                        exit;
                }

            }

        }
    }

    function send_download($file)
    {
        $basename = basename($file);
        $length   = sprintf("%u", filesize($file));

        header('Content-Description: File Transfer');
        header('Content-Type: application/octet-stream');
        header('Content-Disposition: attachment; filename="' . $basename . '"');
        header('Content-Transfer-Encoding: binary');
        header('Connection: Keep-Alive');
        header('Expires: 0');
        header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
        header('Pragma: public');
        header('Content-Length: ' . $length);

        set_time_limit(0);
        readfile($file);
    }

Solution

  • If you're using Apache2 I would highly recommend using mod_xsendfile

    If running Ubuntu or similar you can install it with:

    sudo apt-get install libapache2-mod-xsendfile
    sudo a2enmod xsendfile
    

    Then in your VirtualHost you turn XSendFile on and give approved paths:

    <VirtualHost *:80>
        ......
        <Directory "/var/www/music">
            Options FollowSymLinks
            AllowOverride All
            XSendFile On
            XSendFilePath /home/me/Music
            XSendFilePath /media/me/portable/Music
        </Directory>
    

    Then to actually send the file all you need to do is something like:

    if(isset($_GET['f'])){
        if(is_dir($path.'/'.$_GET['f'])){
            display_files($path,$_GET['f']);
        }else{
            //send selected file
            header('X-SendFile: ' . $path.'/'.$_GET['f']);
            header("Content-type: audio/mpeg");
            header('Content-disposition: attachment; filename="'.basename($_GET['f'].'"'));
        }
    }else{
        display_files($path);
    }
    

    There's no need to worry about echoing text before you send the file or redirecting to an empty download page, as here I have a whole directory listing and some displayed before I send the file with no corruption.