Solved

force download for mp3 files

Posted on 2006-07-03
10
339 Views
Last Modified: 2008-02-01
I have downloadedable files on my server for clients to download, however I dont want them played in the browser, I want the download prompt to happen

what do I have to do...  as of right now all I have is the actual link to the mp3 file
0
Comment
Question by:prowebinteractive
  • 2
  • 2
  • 2
  • +2
10 Comments
 
LVL 49

Expert Comment

by:Roonaan
ID: 17034864
You have to write a download.php file which is called like downloadmp3.php?filemysoundfile.mp3

then have it like this:
<?php

  $mp3dir = 'mp3/';
 
  if(empty($_GET['file'])) exit('File not found');
 
  $file = basename($_GET['file']);
 
  if(!is_file($mp3dir.$file)) exit('File not found');
 
  header('Content-type:attachment;filename='.$file);
  readfile($mpd3dir.$file);
?>

-r-
0
 

Author Comment

by:prowebinteractive
ID: 17034955
doesnt appear to work

I get this error:

mp3Complete/BlackcacoDaleconlacinturacomplete.mp3
Warning: Cannot modify header information - headers already sent by (output started at /home/bcadmin/public_html/newsite/myOrder.php:14) in /home/bcadmin/public_html/newsite/myOrder.php on line 19
0
 
LVL 1

Accepted Solution

by:
duckax earned 250 total points
ID: 17034973
If you want to support download resuming as well as send the filesize to the user, you will need a few more lines of code.

I got this code off php.net with a little modification so that it supports IE
You pass the file using GET i.e. script.php?file=song.mp3
Modify $fpath to the directory where your mp3 is stored

<?php
$fname = $_GET['file'];
$fpath = "downloads/$fname";
$fsize = filesize($fpath);
$bufsize = 20000;

if(isset($_SERVER['HTTP_RANGE']))  //Partial download
{
   if(preg_match("/^bytes=(\\d+)-(\\d*)$/", $_SERVER['HTTP_RANGE'], $matches)) { //parsing Range header
       $from = $matches[1];
       $to = $matches[2];
       if(empty($to))
       {
           $to = $fsize - 1;  // -1  because end byte is included
                               //(From HTTP protocol:
// 'The last-byte-pos value gives the byte-offset of the last byte in the range; that is, the byte positions specified are inclusive')
       }
       $content_size = $to - $from + 1;

       header("HTTP/1.1 206 Partial Content");
       header('Cache-Control: public');
       header("Content-Range: $from-$to/$fsize");
       header("Content-Length: $content_size");
       header("Content-Type: application/force-download");
       header("Content-Disposition: attachment; filename=$fname");
       header("Content-Transfer-Encoding: binary");

       if(file_exists($fpath) && $fh = fopen($fpath, "rb"))
       {
           fseek($fh, $from);
           $cur_pos = ftell($fh);
           while($cur_pos !== FALSE && ftell($fh) + $bufsize < $to+1)
           {
               $buffer = fread($fh, $bufsize);
               print $buffer;
               $cur_pos = ftell($fh);
           }

           $buffer = fread($fh, $to+1 - $cur_pos);
           print $buffer;

           fclose($fh);
       }
       else
       {
           header("HTTP/1.1 404 Not Found");
           exit;
       }
   }
   else
   {
       header("HTTP/1.1 500 Internal Server Error");
       exit;
   }
}
else // Usual download
{
   header("HTTP/1.1 200 OK");
   header('Cache-Control: public');
   header("Content-Length: $fsize");
   header("Content-Type: application/force-download");
   header("Content-Disposition: attachment; filename=$fname");
   header("Content-Transfer-Encoding: binary");

   if(file_exists($fpath) && $fh = fopen($fpath, "rb")){
       while($buf = fread($fh, $bufsize))
           print $buf;
       fclose($fh);
   }
   else
   {
       header("HTTP/1.1 404 Not Found");
   }
}
?>
0
 
LVL 1

Expert Comment

by:duckax
ID: 17034989
You cannot include any other output at the beginning of the script. Remove any non-php, blank lines, print and echo statements
0
IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 
LVL 1

Expert Comment

by:dimakh
ID: 17036748
Hi prowebinteractive,

I'm posting in reference with both of the above posts.
both solution may work with your problem.
please add following code at the start of page. so you wont get any warning messages saying "headers already sent by..." no matter if you are adding any other codes before sending out headers.


<?php
ob_start();
?>

Add above code at very start of your script (at 1st line itself) and your problem will be resolved.

please check this and let me know if you still any error message on this.

Thanks.
0
 
LVL 49

Expert Comment

by:Roonaan
ID: 17036765
>doesnt appear to work

>I get this error:

>mp3Complete/BlackcacoDaleconlacinturacomplete.mp3
>Warning: Cannot modify header information - headers already sent by (output started at /home/bcadmin/public_html/newsite/myOrder.php:14) in >/home/bcadmin/public_html/newsite/myOrder.php on line 19

As mentioned. You should call the file on its own. Not embed it into html.

-r-
0
 
LVL 1

Expert Comment

by:dimakh
ID: 17070791
Hi,

here is the complete code for forced download:
<?
      $url_path      = $music_full_song.$file_name;     // absolute path for the mp3 file
      
      header("Pragma: public"); // required
      header("Expires: 0");
      header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
      header("Cache-Control: private",false); // required for certain browsers
      header("Content-Type: application/force-download");
      // change, added quotes to allow spaces in filenames
      header("Content-Disposition: attachment; filename=\"".basename($file_name)."\";" );
      header("Content-Transfer-Encoding: binary");
      header("Content-Length: ".filesize($url_path));
      readfile("$url_path");
      exit();
?>

you should open this file in a new page/window .

Thanks.
0
 
LVL 2

Assisted Solution

by:Linky
Linky earned 250 total points
ID: 17108268
If you are going to use a script to force download MP3, make sure you do:

$filename = str_replace('/', '', $filename);
$filename = str_replace('..', '', $filename);

Before processing it. Because someone can easily type stuff like song.php?file=../../somefile.ext and possibly get files that contain password information or server info that you do not want them getting.

Just as a security measure.
0

Featured Post

Better Security Awareness With Threat Intelligence

See how one of the leading financial services organizations uses Recorded Future as part of a holistic threat intelligence program to promote security awareness and proactively and efficiently identify threats.

Join & Write a Comment

Consider the following scenario: You are working on a website and make something great - something that lets the server work with information submitted by your users. This could be anything, from a simple guestbook to a e-Money solution. But what…
Since pre-biblical times, humans have sought ways to keep secrets, and share the secrets selectively.  This article explores the ways PHP can be used to hide and encrypt information.
Learn how to match and substitute tagged data using PHP regular expressions. Demonstrated on Windows 7, but also applies to other operating systems. Demonstrated technique applies to PHP (all versions) and Firefox, but very similar techniques will w…
The viewer will learn how to count occurrences of each item in an array.

758 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

22 Experts available now in Live!

Get 1:1 Help Now