Jump to content

forcing a download with php


thescientist

Recommended Posts

www.analogstudios.net/music.phpSo I'm learning to use php for forms and what not, and someone in another forum suggested using php for forcing downloads.this is what he gave for php

<div id="content_column">   <?php	$file = file_get_contents($_GET['filename']);	// We get the file name from the query string so that this file can be used for any other file.	header("Content-type: application/octet-stream");	echo $file; //Output the contents of the sound file	?>  <h3>   Analog Music</h3>blah, blah, blah

and this is how I'm calling the song in the HTML <a href="music.php?filename=http://www.analogstudios.net/music/losttime/01 - October Rain.mp3">1) October Rain</a>it just goes to the next page but doesn't bring up any download box. thoughts, ideas?

Link to comment
Share on other sites

EDITED ONCE MORE:You must not have ANY html, text, echo statements, etc., before you send that header command. If you had your error notifications turned on, you'd be getting notified about "Headers already sent" or some such. So get that div stuff out of there, and don't embed this script in any other html, or echo anything after echoing the file contents (it will be interpreted as part of the music file). Your opening <? should be the first characters in that file.You CAN echo some message (or send a whole html file, for that matter) if file_get_contents() returns FALSE, because in that case you wouldn't be sending the music file.The Content-Disposition header turns out to be key to the download thing, and it's where you suggest the filename. The Content-Length header is how the browser knows how many bytes are remaining, and therefore how many estimated seconds remain in the download.I have now tested this code, with an mp3 no less, and it works.

<?php	if (empty ($_GET['filename']) ) {		// do something polite and exit	}	$filename = $_GET['filename'];	if ($file = file_get_contents($filename)) {		header("Content-type: application/octet-stream");		header("Content-Length: " . filesize($filename));		header("Content-Disposition: attachment; filename=$filename");		echo $file;	} else {		// do something polite and exit	}?>

FWIW, the manual's example actually uses readfile(), which is kind of a combined file_get_contents() and echo. But it seems to me that, in the unlikely event something failed, you'd have no graceful way out.

Link to comment
Share on other sites

I believe OP wants to force the browser to display a download dialog so the file will get saved to disk. This will happen anyway if a link goes to a file the browser isn't built to handle, or if the user has set the preferences to handle all files of a certain type that way, but today's browsers usually load an mp3 into a player, which I guess is NOT OP's desire.

Link to comment
Share on other sites

EDITED ONCE MORE:You must not have ANY html, text, echo statements, etc., before you send that header command. If you had your error notifications turned on, you'd be getting notified about "Headers already sent" or some such. So get that div stuff out of there, and don't embed this script in any other html, or echo anything after echoing the file contents (it will be interpreted as part of the music file). Your opening <? should be the first characters in that file.You CAN echo some message (or send a whole html file, for that matter) if file_get_contents() returns FALSE, because in that case you wouldn't be sending the music file.The Content-Disposition header turns out to be key to the download thing, and it's where you suggest the filename. The Content-Length header is how the browser knows how many bytes are remaining, and therefore how many estimated seconds remain in the download.I have now tested this code, with an mp3 no less, and it works.
<?php	if (empty ($_GET['filename']) ) {		// do something polite and exit	}	$filename = $_GET['filename'];	if ($file = file_get_contents($filename)) {		header("Content-type: application/octet-stream");		header("Content-Length: " . filesize($filename));		header("Content-Disposition: attachment; filename=$filename");		echo $file;	} else {		// do something polite and exit	}?>

FWIW, the manual's example actually uses readfile(), which is kind of a combined file_get_contents() and echo. But it seems to me that, in the unlikely event something failed, you'd have no graceful way out.

so i should put that code at the very beginning of my music.php page? and as for the link to music file, do I leave what I have there? the <a href="music.php?filename=http://www.analogstudios.net/music/losttime/01 - October Rain.mp3">1) October Rain</a>
Link to comment
Share on other sites

I said that the PHP code has to go in a file, alone, without any other code.You link to that file from whichever page you want to.
sorry, i think i was getting confused with the .htaccess thing we were talking about....im such a noob, :)
Link to comment
Share on other sites

so i should put that code at the very beginning of my music.php page?
I don't know what all music.php does beyond the download stuff, so I don't have a good answer. It is certainly common to have PHP in a file that runs if the file receives a query string, and HTML that gets output if the file does not receive a query string. But you could have separate files. Your choice.
and as for the link to music file, do I leave what I have there? the <a href="music.php?filename=http://www.analogstudios.net/music/losttime/01 - October Rain.mp3">1) October Rain</a>
You can. I wrote the script with that structure in mind. Using the complete URL is probably overkill if music.php is also located on www.analogstudios.net, but it will get you the correct results.At this point, you should just try some stuff and see what works. Bring it back here if it breaks.
Link to comment
Share on other sites

so i should put that code at the very beginning of my music.php page?
You should probably put the code in its very own file, with nothing else, like get_file.php or something where the only thing it does is send the header and file data. You can't have a script that outputs a file like that output any other data or the file will be corrupted.
Link to comment
Share on other sites

I don't know what all music.php does beyond the download stuff, so I don't have a good answer. It is certainly common to have PHP in a file that runs if the file receives a query string, and HTML that gets output if the file does not receive a query string. But you could have separate files. Your choice.You can. I wrote the script with that structure in mind. Using the complete URL is probably overkill if music.php is also located on www.analogstudios.net, but it will get you the correct results.At this point, you should just try some stuff and see what works. Bring it back here if it breaks.
music.php is just a PHP page because of the two forms i have on the left using the mail() function. I've got both forms working perfectly now with the page validating xhtml transitional and am now attempting to incorporate a forced download. I put the example that DD's gave me into a file called get_file.php
<?php	if (empty ($_GET['filename']) ) {		// do something polite and exit	}	$filename = $_GET['filename'];	if ($file = file_get_contents($filename)) {		header("Content-type: application/octet-stream");		header("Content-Length: " . filesize($filename));		header("Content-Disposition: attachment; filename=$filename");		echo $file;	} else {		// do something polite and exit	}?>

and have this as the link to the song<a href="get_file.php?filename=http://www.analogstudios.net/music/losttime/01 - October Rain.mp3">1) October Rain</a>but it just brings up a blank page with this in the address bar:http://www.analogstudios.net/get_file.php?...ober%20Rain.mp3any thoughts? I'm so obviously super noob, so I'm sure its something simple. Doh!

Link to comment
Share on other sites

It will be best to use a local path to the file instead of the HTTP path. You might just want to use "music/losttime/01 - October Rain.mp3" since that is a relative path from the root of the site. Using functions like file_get_contents and filesize have extra considerations when opening files over HTTP. Also, instead of using filesize($filename) for the content length, use strlen($file).

Link to comment
Share on other sites

It will be best to use a local path to the file instead of the HTTP path. You might just want to use "music/losttime/01 - October Rain.mp3" since that is a relative path from the root of the site. Using functions like file_get_contents and filesize have extra considerations when opening files over HTTP. Also, instead of using filesize($filename) for the content length, use strlen($file).
that gets it to download, but it doesn't save it as an mp3. When the save dialog box opens, it asks to save it as 'music_losttime_01' as opposed to say, October Rain.mp3. So after you download it and open it, it comes up as unknown file type and you have to browse for a program to open it with. So close....thanks for helping me through all this.
Link to comment
Share on other sites

Yeah, you're giving it the full filename, with folder paths and everything. You can use the basename function to extract the filename from a full path, or you can just use a hard-coded filename.
:)
Link to comment
Share on other sites

I'm talking about this line:header("Content-Disposition: attachment; filename=$filename");Which the browser sees like this:header("Content-Disposition: attachment; filename=music/losttime/01 - October Rain.mp3");When it should see this:header("Content-Disposition: attachment; filename=01 - October Rain.mp3");Although I think the browser is having a problem with the spaces also, you might be able to quote the filename or else you'll need to convert the spaces to underscores.

Link to comment
Share on other sites

I'm talking about this line:header("Content-Disposition: attachment; filename=$filename");Which the browser sees like this:header("Content-Disposition: attachment; filename=music/losttime/01 - October Rain.mp3");When it should see this:header("Content-Disposition: attachment; filename=01 - October Rain.mp3");Although I think the browser is having a problem with the spaces also, you might be able to quote the filename or else you'll need to convert the spaces to underscores.
ok, i changed the spaces to underscores and now it downloads as an mp3, but it still comes up as this for the file name: 'music_losttime_01_october_rain.mp3'. Anyway of truncating it down to just the song name or would i have to save the file in the same directory as the php page?
Link to comment
Share on other sites

Dude, you seriously need to try and look for asnwers yourself within the PHP manual. I mean, everyone here is pointing you where to go... what, you want them to kick you there? Oddly enough, I didn't saw a link to it until now, so I'm assuming you never knew about it, which is forgiveable.Anyway... I believe this what you need:

header("Content-Disposition: attachment; filename={urlencode(basename($filename))}");

The two handy functions in this are urlencode() (to avoid the spaces problem) and basename() (to get the name of the file).

Link to comment
Share on other sites

header("Content-Disposition: attachment; filename={urlencode(basename($filename))}");That syntax doesn't work, it won't run the functions inside curly brackets, only do variable replacement. header("Content-Disposition: attachment; filename=" . urlencode(basename($filename)));

Link to comment
Share on other sites

header("Content-Disposition: attachment; filename={urlencode(basename($filename))}");That syntax doesn't work, it won't run the functions inside curly brackets, only do variable replacement. header("Content-Disposition: attachment; filename=" . urlencode(basename($filename)));
thanks, i really appreciate all your help! :)
Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...