473,498 Members | 1,218 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Download files without <a>

nathj
938 Recognized Expert Contributor
Hi,

I am working on a system, as you may have seen from my other posts, that allows members to download files. When they download a file I want to store the user ID and the file ID in a table along with the last download time and how many times they have downloaded.

I have the SQL for this already - so no problems there.

Unfortunately you can't use AJAX for this as the code in the onclick() won't fire if there is a URL in the href - the default handler for the URL is fired in stead.

So my idea was simple. Have the link go to a php page that updates the table in the database, downloads the file and then returns the user to where they were originally.

This leads me to my question. How do you download the file in PHP? It may a php file, an m3u file or anything for that matter.

I've read around the low level file functions but all this will do, as far as I can tell, is put the file contents into a local variable. How can I get the file to the clients PC and store the fact that they have done so?

Any help, suggestions or pointer greatly appreciated.

Cheers
nathj

PS How do you get the email notification and signature to set for every post - I have to keep editing my posts to set it?
Sep 5 '07 #1
12 2651
ak1dnar
1,584 Recognized Expert Top Contributor
How do you get the email notification and signature to set for every post - I have to keep editing my posts to set it?
Control Panel >> New Subscribed Threads >> Set the notification check box for threads, and bottom of the panel you can find instant email notifications.
Sep 5 '07 #2
ronnil
134 Recognized Expert New Member
Hi nathj

The answer is in fact painfully simple. What you need is headers (I don't remember your other posts so I don't know how much you have messed with this)

this should get you going (hopefully)

this file we call "download.php"
Expand|Select|Wrap|Line Numbers
  1. <?php
  2. /*
  3. We'll pretend that info about the file is stored in the table "file_table", here we need at least to store the mimetype and the filename. The file is in this case actually stored another place on your server, but could might as well be stored inside the database. for simplicity the files are stored in the same directory as this one (download.php), with their own filename. I'd suggest you name them uniquely, e.g. give them the time uploaded as prefix
  4. */
  5.  
  6. //Get the file id using $_GET
  7. $fid = $_GET['fid'];
  8. //we'll just pretend that your userid is stored in $_SESSION['uid']
  9. $uid = $_SESSION['uid'];
  10.  
  11. //insert the file is downloaded
  12. $sql = "INSERT INTO file_downloaded (uid,fid) VALUES (" . $uid . "," . $fid . ")";
  13. $result = mysql_query($sql) or die('Could not update, you can\'t have the file :P');
  14. //only give the user the file if the query was succesful
  15. if($result)
  16. {
  17.     $sql = "SELECT * FROM file_table WHERE fid=" . $fid . " LIMIT BY 0,1";
  18.     $result = mysql_query($sql) or die('Could not find file');
  19.  
  20.     if($result && mysql_num_rows($result) <> 0)
  21.     {
  22.         $row = mysql_fetch_assoc($result);
  23.         //Tells the browser the mime-type of the file.
  24.         header('Content-type:' . $row['mime_type']);
  25.         //Tells the browser the size of the file.  A kind gesture to let people know how long they have to wait until downloads finish
  26.  
  27.     header('Content-length: ' . $row['file_size']);
  28.         //Tells the browser to download no matter what and gives the correct filename in "save as"
  29.  
  30.     header('Content-disposition: attachment; Filename="' . $row['filename'] . '"');
  31.         //reads the file and outputs it directly. you could also 
  32.         //echo fread(fopen($row['filename'],'r'),filesize($row['filename']));
  33.         //or
  34.  
  35.         //echo $row['file_content'];
  36.         //if you stored the file in a db
  37.     readfile($row['filename']);
  38.     }
  39. }
  40.  
  41. ?>
  42.  
This should be working (haven't tested it). You and others may use it freely :)

Hope it helps :)
Sep 5 '07 #3
ronnil
134 Recognized Expert New Member
heh.. forgot to say

You link to this file, either with onclick or with <a href=""></a>, either way you put the file id in the query like http://yoursite.com/path/to/download.php?fid=3245

and then you should get a download query
Sep 5 '07 #4
pbmods
5,821 Recognized Expert Expert
Heya, nathj.

Simply add 'return false;' to the onclick handler of the anchor tag:
Expand|Select|Wrap|Line Numbers
  1. <a href="http://gohereifnojavascript/" onclick="window.location.href='nogohereinstead'; return false;">Check it out!</a>
  2.  
Sep 5 '07 #5
gregerly
192 Recognized Expert New Member
Hey Nathj,

There is a new buzz word floating around call "hijax", the act of javascript hijacking a normal <a> tag. The idea is that you link to the file normally with the href att. so if javascript isn't available, your user will still be able to get the file. If javascript is available, it will "Hijak" the using the onclick. The key point to this is that the javascript needs to have "return false" as pbmods already mentioned. This will make the href not fire, and you can do what you want with your javascript. Personally, I think hijax is the way to go as it doesn't assume the existence of javascript, and users can still get their content if no javascript is available.

Greg
Sep 5 '07 #6
nathj
938 Recognized Expert Contributor
Hi Everyone,

That's loads of help thank you to all of you. I think I am going to go the way Ronnil suggests. This could be exactly hat I'm after. If I get stuck I'll post back.

Thanks again to everyone for the help. It's sent me off trawling the net and reading all sorts of stuff, so that's great.

Cheers
nathj
Sep 6 '07 #7
gregerly
192 Recognized Expert New Member
Hi Everyone,

That's loads of help thank you to all of you. I think I am going to go the way Ronnil suggests. This could be exactly hat I'm after. If I get stuck I'll post back.

Thanks again to everyone for the help. It's sent me off trawling the net and reading all sorts of stuff, so that's great.

Cheers
nathj
Hey Nathj,

I'm pretty sure that way will work, but an empty href in an <a> tag may cause validation to fail (if that's something you care about).

Greg
Sep 6 '07 #8
nathj
938 Recognized Expert Contributor
Hi,

I've now had a play around and guess what - I've got a bit stuck again.

Here's the inside scoop:

1. I have a file download.php which displays the files to download. In this there is a line for the file that looks like this:
[html]
<a id="3" class="inlineLink" href="lib/recorddownload.php?item=3" title="What Good Looks Like - Session 1(mp3)">What Good Looks Like - Session 1(mp3)</a>
[/html]

2. I have a file recorddownload.php which records the fact that a member downloaded a file and then runs the download:
[php]
<?php
session_start();
/*
File: lib/recorddownload.php
Author: Nathan Davies
Created: 09/08/2007
Purpose: To record when a member downloads a file
*/

// the calling file
$lcCallingFile = $_SERVER['HTTP_REFERER'] ;

// Update the database
if(!empty($_GET['item']))
{
require_once($_SERVER['DOCUMENT_ROOT'].'/lib/dataobjects.php'); // any page may then create a data connection for that page. This keeps connections active only for as long as they are required
$loDB = new dataObject("database", "user", "password", "connection");

// get the variables and information relating to the supplied file ID
$lnFileID = $_GET['item'] ;
// array of extension to mime types
$laExtList = array (

// archives
'zip' => 'application/zip',

// documents
'pdf' => 'application/pdf',
'doc' => 'application/msword',
'xls' => 'application/vnd.ms-excel',
'ppt' => 'application/vnd.ms-powerpoint',

// executables
'exe' => 'application/octet-stream',

// images
'gif' => 'image/gif',
'png' => 'image/png',
'jpg' => 'image/jpeg',
'jpeg' => 'image/jpeg',

// audio
'mp3' => 'audio/mpeg',
'm3u' => 'audio/x-mpegurl',
'wav' => 'audio/x-wav',

// video
'mpeg' => 'video/mpeg',
'mpg' => 'video/mpeg',
'mpe' => 'video/mpeg',
'mov' => 'video/quicktime',
'avi' => 'video/x-msvideo'
) ;

// now establish the file information from the database
$lcSelectFile = "
SELECT
a.name, a.URL
FROM download a
WHERE a.ID = $lnFileID" ;

$laFileInfo = $loDB->queryGetData($lcSelectFile) ;

if($laFileInfo)
{
foreach($laFileInfo as $lcFile)
{
$lcFileName = $lcFile['name'] ;
$lcFilePath = $lcFile['URL'] ;
$lcFileExt = substr($lcFilePath, strpos($lcFilePath, '.') + 1) ;
$lcMimeType = $laExtList[$lcFileExt] ;
}

// update the database
$lnLeaderID = $_SESSION['userID'] ;
// first check that the leader does not already have the download associated with them, if they do there is no reason to load it again.
$lcCheckSQL = "SELECT a.ID, a.frequency + 1 as newFrequency from leaderdownloadassociation a WHERE a.leaderID = $lnLeaderID AND a.downloadID = $lnFileID" ;
$laAssociation = $loDB->queryGetData($lcCheckSQL) ;
if($laAssociation)
{
// update the frequency
$lnFrequency = $laAssociation[0]['newFrequency'] ;
$lcUpdate = "UPDATE leaderdownloadassociation set frequency = $lnFrequency, editdate = now() WHERE leaderID = $lnLeaderID AND downloadID = $lnFileID" ;
$loDB->iQuery($lcUpdate) ;
}
else // first download
{
$lcTableName = "leaderdownloadassociation" ;
$lcFieldList = "leaderID, downloadID, frequency, createdate, editdate" ;
$lcValueList = "$lnLeaderID, $lnFileID, 1, now(), now()";
$loDB->queryInsert($lcTableName, $lcFieldList, $lcValueList, false) ;
}

// download the file
header("Content-Type: " . $lcMimeType);
header("Content-Length: " . filesize($lcFilePath));
header('Content-Disposition: attachment; filename="' . $lcFileName .'"');
readfile($lcFilePath);
}
}

// return to the calling page
header("Location:$lcCallingPage");

?>
[/php]

The database updates perfectly - that's great, the only trouble is I get an error when I come to the downloading part of the process:
[html]
<html><head></head><body><pre>&lt;br /&gt;
&lt;b&gt;Warning&lt;/b&gt;: filesize() [&lt;a href='function.filesize'&gt;function.filesize&lt;/a&gt;]: stat failed for http://www.christianleadership.org.uk/m3u/eddiegibbs_session1.m3u in &lt;b&gt;/homepages/29/d210214908/htdocs/lib/recorddownload.php&lt;/b&gt; on line &lt;b&gt;97&lt;/b&gt;&lt;br /&gt;

&lt;br /&gt;
&lt;b&gt;Warning&lt;/b&gt;: Cannot modify header information - headers already sent by (output started at /homepages/29/d210214908/htdocs/lib/recorddownload.php:97) in &lt;b&gt;/homepages/29/d210214908/htdocs/lib/recorddownload.php&lt;/b&gt; on line &lt;b&gt;97&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;

&lt;b&gt;Warning&lt;/b&gt;: Cannot modify header information - headers already sent by (output started at /homepages/29/d210214908/htdocs/lib/recorddownload.php:97) in &lt;b&gt;/homepages/29/d210214908/htdocs/lib/recorddownload.php&lt;/b&gt; on line &lt;b&gt;98&lt;/b&gt;&lt;br /&gt;
http://www.christianleadership.org.uk/download/audio/eddiegibbs_session1.mp3&lt;br /&gt;

&lt;b&gt;Warning&lt;/b&gt;: Cannot modify header information - headers already sent by (output started at /homepages/29/d210214908/htdocs/lib/recorddownload.php:97) in &lt;b&gt;/homepages/29/d210214908/htdocs/lib/recorddownload.php&lt;/b&gt; on line &lt;b&gt;104&lt;/b&gt;&lt;br /&gt;
</pre></body></html>
[/html]

This is all a bit of mystery to me. I guess what this is saying is that headers have already been set so you can't set any more. But I'm not sure where they have been set or if they have been set.If anyone could explain this to me that would be fantastic.

On the plus side all these troubles are helping me to get a better understanding of how PHP works in this regard.

Cheers
nathj
Sep 6 '07 #9
nathj
938 Recognized Expert Contributor
Hi,

Well A new problem now. Having played around with the code all afternoon I can now get the download correct using headers but I can't get the database to update. Alternatively I can get the database to update but the downloaded file is a php file listing header errors because content has already been sent.

So here's the state of play at present:

The Call
[html]
<a id="3" class="inlineLink" href="lib/recorddownload.php?item=3&amp;id=1&amp;extra=eddie gibbs_session1.m3u&amp;extra2=audio/x-mpegurl&amp;extra3=76" title="What Good Looks Like - Session 1(mp3)">What Good Looks Like - Session 1(mp3)</a>
[/html]

The PHP code:
[php]
<?php
/*
File: lib/recorddownload.php
Author: Nathan Davies
Created: 09/08/2007
Purpose: To record when a member downloads a file
*/
// the calling file
$lcCallingFile = $_SERVER['HTTP_REFERER'] ;
$lcBaseCall = substr($lcCallingFile, 1, strpos($lcCallingfile, '?')-1) ;
// download the file
header("Content-Type: " . $_GET['extra2']);
header("Content-Length: " . $_GET['extra3']);
header('Content-Disposition: attachment; filename="' . $_GET['extra'] .'"');
readfile($lcFilePath);
// update the db
require_once($_SERVER['DOCUMENT_ROOT'].'/lib/dataobjects.php');
$loDB = new dataObject("database", "user", "password", "server");

$lnLeaderID = $_GET['id'] ;
// first check that the leader does not already have the download associated with them, if they do there is no reason to load it again.
$lcCheckSQL = "SELECT a.ID, a.frequency + 1 as newFrequency from leaderdownloadassociation a WHERE a.leaderID = $lnLeaderID AND a.downloadID = $lnFileID" ;
$laAssociation = $loDB->queryGetData($lcCheckSQL) ;
if($laAssociation)
{
// update the frequency
$lnFrequency = $laAssociation[0]['newFrequency'] ;
$lcUpdate = "UPDATE leaderdownloadassociation set frequency = $lnFrequency, editdate = now() WHERE leaderID = $lnLeaderID AND downloadID = $lnFileID" ;
$loDB->iQuery($lcUpdate) ;
}
else // first download
{
$lcTableName = "leaderdownloadassociation" ;
$lcFieldList = "leaderID, downloadID, frequency, createdate, editdate" ;
$lcValueList = "$lnLeaderID, $lnFileID, 1, now(), now()";
$loDB->queryInsert($lcTableName, $lcFieldList, $lcValueList, false) ;
}
?>
[/php]

Ultimately I need to put some error trapping around this but initially I just want it to work. So at present I have the file downloading fine but the database does not get updated and I know the code itself is fine as I have tested just that part.

Any suggestions greatly appreciated.

Cheers
nathj
Sep 6 '07 #10
ak1dnar
1,584 Recognized Expert Top Contributor
Once you call for the download headers, script execution stops.
So first Insert the data to the Table(s), then call for the header as the last part of the script execution.
Sep 6 '07 #11
nathj
938 Recognized Expert Contributor
Once you call for the download headers, script execution stops.
So first Insert the data to the Table(s), then call for the header as the last part of the script execution.
Hi,

That makes sense. However, I'm about to go on holiday for 2 weeks and I haven't started packing yet so I better try this when I get back - I'll let you know how I get on.

Thanks to everyone for all the help.

Cheers
nathj
Sep 6 '07 #12
nathj
938 Recognized Expert Contributor
Hi,

Having had 2 sunny weeks Italy I have returned to the wonderful grey that only British weather can produce. So without the temptation to lounge around outside reading all day I have returned to work - my boss is most thankful.

I have now switched the order of the code around and all works a treat. I'm really pleased with this and very greatful for all the help I have received on this part of my project.

Many thanks
nathj
Sep 25 '07 #13

Sign in to post your reply or Sign up for a free account.

Similar topics

2
3182
by: Eshrath | last post by:
Hi, What I am trying to do: ======================= I need to form a table in html using the xsl but the table that is formed is quite long and cannot be viewed in our application. So we are...
2
10532
by: Donald Firesmith | last post by:
I am having trouble having Google Adsense code stored in XSL converted properly into HTML. The <> unfortunately become &lt; and &gt; and then no longer work. XSL code is: <script...
2
1673
by: tmb | last post by:
I'm trying to use the Microsoft Search to search for a text string in a folder full of a bunch of ASP files. Seems like the normal "Search for text in files" program in XP Pro won't search...
1
5420
by: RJN | last post by:
Hi I'm using XMLTextReader to parse the contents of XML. I have issues when the xml content itself has some special characters like & ,> etc. <CompanyName>Johnson & Jhonson</CompanyName>...
1
1643
by: JezB | last post by:
I'm binding a DataGrid web-control to data fetched from a database. However some of my data fields contain text that is within <...> characters - I notice that everything between the <> is...
1
1225
by: Al | last post by:
Hi! I try to use custom download page (download.aspx) wich writes file (about 700Mb) to response. But I can download only one file from one IP at the same time. I think that this is IIS or...
0
1265
by: John Lafrowda | last post by:
Dear all, here is a simple problem that I cannot overcome: I'm trying to write a client/server application in Visual Basic .net. The server is an executable (.exe) project, the clients are class...
1
2675
by: RJN | last post by:
Hi I'm using XMLTextReader to parse the contents of XML. I have issues when the xml content itself has some special characters like & ,> etc. <CompanyName>Johnson & Jhonson</CompanyName>...
1
2286
by: mike | last post by:
I've got some code like this: gametype_id = Request.Form("gametype_id") response.write "<br>gametype_id from form>" & gametype_id & "<" response.write "<br>gametype_id from database>" &...
4
2063
by: MooseManDan | last post by:
I have a linked table DOWNLOAD (MS excel spreadsheet) that I copied all the information over to in MAIN DATA table, but added more fields to MAIN DATA. How do I create the relationship to...
0
7124
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
6998
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
7200
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
1
6884
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
5460
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
1
4904
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...
0
4586
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and...
0
3090
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The...
0
287
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.