...

View Full Version : Logging downloads



david.ginn524
07-24-2012, 06:36 PM
Greetings,
I have created a very very basic website to distribute my pictures to family and friends. while this is normally easy to do; I have made it a little more complicated because I wanted to log the downloads in a database. I have gotten everything working except there is a problem. When I click the download link (which is actually a form submit button) it will start downloading the file. The file is a zip of all the photos I have taken of that day /activity. I have one zip that is 2.1 GB.

The problem I am having is that; the download will never finish. The download connection just times out and cuts the connection then you have to restart it.
I have had my friends try to download it and me and it still cuts the connection. Currently I thought it was my crappy internet which is 170kb download which takes about 4 hrs to download the 2.14GB file. But I had other friends dl it. One was dling at 2.2 MB/s ETA completion 10 min. It will cut the connection still. I haven't seen a pattern in time when it disconnects or at a certain size it disconnects. I am guessing it is my code.

Below is the page that displays the "links" (a form submit button) which redirects it to a page; calls a InsertDB function to log the DL then serves the file from the log.php page. I know this is not the most efficient coding but its super simple website so i don't need to iterate through things or make it complicated.


<?php
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<meta name="description" content="" />

<meta name="author" content="David Ginn" />
<?php
include ('includes/title.php');
?>
</head>

<body><div id="wrap">

<div id="header">
<p class="hide">skip to: <a href="#content">content</a> |
<a href="#sitemenu">navigation</a><br /></p>
<?php
include ('includes/titlepage.php');
?>
</div>
<?php
/**
cut down code to include links
*/
include ('includes/links.php');
?>





<div id="content">

<h2>Links to download the Connect Photos</h2>
<h3>Each link downloads <b>ALL</b> photos I have taken for this activity. </h3> <br />
Click the titles to download all the pictures. <br /><br />
<form name="sns" action="/picturelinks/log.php" method="post">
<input type="hidden" name="download" value="2">
<input type="submit" value="Slip N Slide 7-21-12" /> 231 photos; 2.14 GB
</form>
<form name="sns" action="/picturelinks/log.php" method="post">
<input type="hidden" name="download" value="1">
<input type="submit" value="4th of July" /> 137 photos; 538 MB
</form>



</div>

<div id="footer">
<?php
include ('includes/copyright.php');
?>

</div>

</div></body>
</html>




here is the code for the log page. Currently I am implementing 2 types to try and download the file. the content octet-stream for zips and just a regular header call. the content stream doesn't work and I am not sure why. the regular head; does work; but after a while it stops the download.
is there a better way to serve these files than calling a header function?

any suggestions would be awesome :) thanks


<?php
$download = $_POST['download'];

$date = date("Y-m-d H:i:s");
function getRealIpAddr()
{
if (!empty($_SERVER['HTTP_CLIENT_IP'])) //check ip from share internet
{
$ip=$_SERVER['HTTP_CLIENT_IP'];
}
elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) //to check ip is pass from proxy
{
$ip=$_SERVER['HTTP_X_FORWARDED_FOR'];
}
else
{
$ip=$_SERVER['REMOTE_ADDR'];
}
return $ip;

}


function InsertDB()
{
include ('includes/db_connect.php');
mysql_select_db($db, $con);
getRealIpAddr();
$iplog = getRealIpAddr();
$download = $_POST['download'];
$sql="INSERT INTO Log (IP,Download)
VALUES
('$iplog','$download')";
if (!mysql_query($sql,$con))
{
die('Error: ' . mysql_error());
}
mysql_close($con);


}


if ($download == "1")
{
$file = "4thofJuly2012.zip";
header("Content-type: application/octet-stream");
header("Content-disposition: attachment; filename=".$file."");
readfile('$file');
InsertDB();
}
elseif ($download == "2")
{
$file = "/picturelinks/Slip n Slide 7-21-12.zip";
$cm = "Location: $file";
header ($cm);
InsertDB();
}
elseif ($download == "3")
{
//$file = "/picturelinks/Slip n Slide 7-21-12.zip";
$cm = "Location: $file";
header ($cm);
InsertDB();
}
else
header( 'Location: /picturearchive.php' ) ;
?>

tangoforce
07-25-2012, 01:59 AM
Your download is being cut short by the scripts maximum execution time (typically 30 - 60 seconds on most php based systems).

You can use set_time_limit(0) in the code (assuming that function isn't disabled) or adjust your php.ini file (assuming your host allows this).

Some servers simply don't allow you to workaround the timeouts so in that case you'd be better off issuing a header redirect to the actual file so that the webserver serves it instead of php.

david.ginn524
07-25-2012, 01:58 PM
thank you for that, where do i put that in the code? next to the header?

Also, even with this I may or may not have figured it out. Not entirely sure about it though. All the times I have been downloading / friends have been; I have been editing and updating the code via my PHP program. When I save it, it uploads the newest version to the server. This seems to reset all active connections for some reason. I downloaded my zip yesterday without modifying any code what so ever and it worked find. To me this doesn't seem that logical. Since I am uploading newer versions; why would it close the existing connections ?

tangoforce
07-25-2012, 06:04 PM
thank you for that, where do i put that in the code? next to the header?



<?php
set_time_limit(0); //May not work if disabled by host





All the times I have been downloading / friends have been; I have been editing and updating the code via my PHP program. When I save it, it uploads the newest version to the server. This seems to reset all active connections for some reason. .. why would it close the existing connections ?

I doubt it is. I suspect its conincidental timing to be honest as the replacement of the file shouldn't mean that the running instance of it is halted HOWEVER on some linux systems deleting / renaming a file DOES cause the running versions to be terminated.

david.ginn524
07-25-2012, 06:56 PM
Thanks very much I shall do that. One other item that I literally just thought of. Since I am logging the download of the IP, initial time stamp and a few other details.. Is there anyway to add a 2nd time stamp to the download of when it finished or the "connection closed"?
I dont think that would be possible in the website code; would it? I am thinking the server would have to know when the connection is closed to add a log to a database or something similar to that?

tangoforce
07-25-2012, 07:23 PM
Thanks very much I shall do that. One other item that I literally just thought of. Since I am logging the download of the IP, initial time stamp and a few other details.. Is there anyway to add a 2nd time stamp to the download of when it finished or the "connection closed"?

Yes, you need to look at a function called register_shutdown_function() :thumbsup:


I dont think that would be possible in the website code; would it? I am thinking the server would have to know when the connection is closed to add a log to a database or something similar to that?

No it just needs to know when the script has finished and log that time. Using the above function will allow you to do that.

DrDOS
07-25-2012, 08:27 PM
<?php
// We'll be outputting a PDF
header('Content-type: application/pdf');

// It will be called downloaded.pdf
header('Content-Disposition: attachment; filename="downloaded.pdf"');

// The PDF source is in original.pdf
readfile('original.pdf');
?>

Have you tried using a download.php file? They're really simple to write, you can even do stuff in the file, like compress a folder or convert a filetype. They have to be alone on a page with no spaces before or after the php tags, and you just call them with a simple href link. The server may be more forgiving if you use one, or you may be able to use it with a download manager.

david.ginn524
07-25-2012, 08:40 PM
<?php
// We'll be outputting a PDF
header('Content-type: application/pdf');

// It will be called downloaded.pdf
header('Content-Disposition: attachment; filename="downloaded.pdf"');

// The PDF source is in original.pdf
readfile('original.pdf');
?>

Have you tried using a download.php file? They're really simple to write, you can even do stuff in the file, like compress a folder or convert a filetype. They have to be alone on a page with no spaces before or after the php tags, and you just call them with a simple href link. The server may be more forgiving if you use one, or you may be able to use it with a download manager.

OMG I have been trying to compress stuff for a couple months automatically. How do I do that? I finally gave up. Mind you this was in ASP and I sort of tried in PHP but how would I go about compressing stuff. This is totally off subject from my original problem. This was a separate project that got put on the back burner

david.ginn524
07-25-2012, 09:21 PM
one other item pertaining to download logging. I know lots of websites track what type of browser you use and other information like that. How do i gather that? Im guessing its a function of some sort or a call to a variable stored in the browser

tangoforce
07-25-2012, 11:57 PM
<?php
// We'll be outputting a PDF
header('Content-type: application/pdf');

// It will be called downloaded.pdf
header('Content-Disposition: attachment; filename="downloaded.pdf"');

// The PDF source is in original.pdf
readfile('original.pdf');
?>

Have you tried using a download.php file? They're really simple to write, you can even do stuff in the file, like compress a folder or convert a filetype. The server may be more forgiving if you use one

You do realise that thats pretty much what the op is doing don't you? :rolleyes: Look above, they have download management code that they are seeking help with. Suggesting that they write an even simpler version such has yours will not actually help them fix their max_execution_time problem which I am helping them work through and that you don't appear to understand. While I appreciate you think you're helping, you've in effect just suggested that the op actually rolls back their code to something far less useful to them.



or you may be able to use it with a download manager.

That really serves no purpose other than to derail this topic. Yes it is possible to use code that works with download managers - I have this myself (along with throttling and connection management) however you've just done the opposite with that line of text than your previous paragraphs - tried to make it even more complex :eek:

@david: I've just spotted a few errors in your code too - adjustments suggested below:



<?php
$download = mysql_real_escape_string($_POST['download']); //Protect the database against injection

$date = date("Y-m-d H:i:s");
function getRealIpAddr()
{
if (!empty($_SERVER['HTTP_CLIENT_IP'])) //check ip from share internet
{
$ip=$_SERVER['HTTP_CLIENT_IP'];
}
elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) //to check ip is pass from proxy
{
$ip=$_SERVER['HTTP_X_FORWARDED_FOR'];
}
else
{
$ip=$_SERVER['REMOTE_ADDR'];
}
return $ip;

}


function InsertDB()
{
global $download; //Use main variable

include ('includes/db_connect.php');
mysql_select_db($db, $con);
getRealIpAddr();
$iplog = mysql_real_escape_string(getRealIpAddr()); // Protect DB
//$download = $_POST['download'];
$sql="INSERT INTO Log (IP,Download)
VALUES
('$iplog','$download')";
if (!mysql_query($sql,$con))
{
die('Error: ' . mysql_error());
}
mysql_close($con);


}


if ($download == "1") //Use single quotes for '1' as you're not using a $Variable
{
$file = "4thofJuly2012.zip"; // Single quotes
header("Content-type: application/octet-stream");
header("Content-disposition: attachment; filename=".$file."");
readfile('$file'); //Double quotes should be here OR no quotes at all
InsertDB();
}
elseif ($download == "2") //Single quotes for '2' as above
{
$file = "/picturelinks/Slip n Slide 7-21-12.zip"; // More single quotes
$cm = "Location: $file"; //Correct
header ($cm); // As readfile() above
InsertDB();
}
elseif ($download == "3")
{
//$file = "/picturelinks/Slip n Slide 7-21-12.zip";
$cm = "Location: $file";
header ($cm);
InsertDB();
}
else
header( 'Location: /picturearchive.php' ) ;
?>

david.ginn524
07-26-2012, 01:03 AM
honestly , i have barley any clue in coding. I do this as a hobby and i am no expert. I barley know functions / just started using them. So I appreciate you all helping me and shall review this. Also thanks tangoforce for the corrections

david.ginn524
07-26-2012, 01:12 AM
also dumb question, for the "global $download;" why did you change it from the the post. is it calling the one from above that i already did the post?

DrDOS
07-26-2012, 01:33 AM
You do realise that thats pretty much what the op is doing don't you? :rolleyes: Look above, they have download management code that they are seeking help with. Suggesting that they write an even simpler version such has yours will not actually help them fix their max_execution_time problem which I am helping them work through and that you don't appear to understand. While I appreciate you think you're helping, you've in effect just suggested that the op actually rolls back their code to something far less useful to them.

That really serves no purpose other than to derail this topic. Yes it is possible to use code that works with download managers - I have this myself (along with throttling and connection management) however you've just done the opposite with that line of text than your previous paragraphs - tried to make it even more complex :eek:


Sorry, I didn't see the header content-type line in the code. Just hope he manages to solve his problem someway.

tangoforce
07-26-2012, 01:37 AM
also dumb question, for the "global $download;" why did you change it from the the post. is it calling the one from above that i already did the post?

Yes, thats correct. Using the keyword global inside a function and then declaring the variable name next to it tells PHP that you are using a variable in the main scope of the script - in other words outside of the function.

tangoforce
07-26-2012, 01:43 AM
Sorry, I didn't see the header content-type line in the code.

Thats not really important, the important thing is that its a script that outputs a file. The second point is that it terminates prematurely - usually this is down to the maximum execution time of the script as defined in the configuration.


Just hope he manages to solve his problem someway.

Well thats what I was working towards.. :thumbsup:

david.ginn524
07-26-2012, 02:41 AM
Sorry, I didn't see the header content-type line in the code. Just hope he manages to solve his problem someway.

that is A ok , its a good suggestion and normally i would take it but i cant really tell my elderly family to use a download manager when they barley know how to use a computer / click buttons.
We shall try this and see
thanks



EZ Archive Ads Plugin for vBulletin Copyright 2006 Computer Help Forum