Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1284
  • Last Modified:

PHP download script not working with large zip file

Hi Experts;
I have a php script with allows for a one-time, secure download of a zip file (about 36 MB large).  However when I download the zip file using the script, I sometimes get an error when trying to extract the file.  The error is "Windows cannot open the folder.  The Compressed (zipped) Folder: 'C:\Downloads\cd.zip' is invalid."  This error only seems to occurs over slow connections.  When I have a fast connection the file download completes and there is no error.  The following is the script I am using, I changed the mysql database connection for security but in my code the connection is valid.

<?php

set_time_limit(0);
//The directory where the download files are kept - keep outside of the web document root
$strDownloadFolder = "sec_dl/";

//If you can download a file more than once
$boolAllowMultipleDownload = 0;

//connect to the DB
$resDB = mysql_connect("localhost", "user", "password");
mysql_select_db("database", $resDB);

if(!empty($_GET['key'])){
	//check the DB for the key
	$resCheck = mysql_query("SELECT * FROM downloads WHERE downloadkey = '".mysql_real_escape_string($_GET['key'])."' LIMIT 1");
	$arrCheck = mysql_fetch_assoc($resCheck);
	if(!empty($arrCheck['file'])){
		//check that the download time hasnt expired
		if($arrCheck['expires']>=time()){
			if(!$arrCheck['downloads'] OR $boolAllowMultipleDownload){
				//everything is ok - check the file exists and then let the user download it
				$strDownload = $strDownloadFolder.$arrCheck['file'];
				
				if(file_exists($strDownload)){
					
					//get the file content
					$strFile = file_get_contents($strDownload);
										
					//set the headers to force a download
					header("Content-Transfer-Encoding: binary");
					header("Content-Type: application/octet-stream");
					header("Content-Disposition: attachment; filename=\"".str_replace(" ", "_", $arrCheck['file'])."\"");					
					readfile($strFile);					
					//echo the file to the user
					echo $strFile;
										
					//update the DB to say this file has been downloaded
					mysql_query("UPDATE downloads SET downloads = downloads + 1 WHERE downloadkey = '".mysql_real_escape_string($_GET['key'])."' LIMIT 1");
					
					exit;
					
				}else{
					echo "We couldn't find the file to download.";
				}
			}else{
				//this file has already been downloaded and multiple downloads are not allowed
				echo "This file has already been downloaded.";
			}
		}else{
			//this download has passed its expiry date
			echo "This download has expired.";
		}
	}else{
		//the download key given didnt match anything in the DB
		echo "No file was found to download.";
	}
}else{
	//No download key was provided to this script
	echo "No download key was provided. Please return to the previous page and try again.";
}

?>

Open in new window


Any help is much appreciated.  Thanks!
0
cm89284
Asked:
cm89284
  • 7
  • 7
1 Solution
 
Dave BaldwinFixer of ProblemsCommented:
If it only fails on slow connections, then the PHP script may be timing out and not finishing sending the file.  See the notes on this page about IIS timing out: http://us2.php.net/manual/en/function.set-time-limit.php
0
 
cm89284Author Commented:
Can you be more specific.  I already have
set_time_limit(0);
as the first line in the code.

Thanks
0
 
Dave BaldwinFixer of ProblemsCommented:
You specifically need to read the notes on that page about the IIS time out that occurs independent of any PHP settings.  set_time_limit(0); has no effect on the IIS timeout.
0
 [eBook] Windows Nano Server

Download this FREE eBook and learn all you need to get started with Windows Nano Server, including deployment options, remote management
and troubleshooting tips and tricks

 
cm89284Author Commented:
Ok but to my understanding I can only change the CGI timeout of my own server and my website is hosted on a remote server.  I am not very proficient in IIS so I may be wrong but I added the CGI feature and it only shows up when I select my machine from IIS.  Is there another way to change this timeout setting?
0
 
Dave BaldwinFixer of ProblemsCommented:
This page talks about the different versions:  http://blogs.iis.net/donraman/archive/2010/02/08/troubleshoot-my-php-script-is-timing-out.aspx   If you're on shared hosting, you may have to call your web host to see if they will change it for you.
0
 
cm89284Author Commented:
I appreciate all your help on this.  I sent an email to support and my web hosting provider said they don't allow for changing of these settings.  Is there any way I could approach this problem a different way through modification of the script?  I am looking for a script that generates a single-use link to the file, also I don't want the user to know the location of the downloaded file.  Is this possible to accomplish with a script so it won't timeout?  Obviously something like a redirect would work because then the file is not downloaded through the script and the timeout won't be an issue, but the location of the file would be revealed so it won't be secure.  If you could help me with coming up with a solution that addresses all these issues it would be extremely helpful.  I appreciate all your help and expertise on this matter.

Thanks
0
 
Dave BaldwinFixer of ProblemsCommented:
As long as a script is reading the file and doing the downloading, you will be subject to the time-out limits.  You could copy the file to a unique file name and make it available for download for a limited time.  All it takes is a clean-up routine that deletes file after they have been available for the specified time.
0
 
Ray PaseurCommented:
Not sure if this is part of the problem but it looks to me like the script is sending the file contents twice.  See lines 34 and 36.
http://php.net/manual/en/function.readfile.php
0
 
cm89284Author Commented:
I took out the readfile line but this didn't solve the issue.  After talking with my web hosting provider they said I could change the CGI timeout value by adding a user.ini file to the directory and editing the max_exectution time.  I set the max_execution time to 3600 but I still get the same error.  Is it possible that this error is occurring because of a reason other than an IIS timeout?
0
 
Dave BaldwinFixer of ProblemsCommented:
I don't think so.  Do you get any error messages?
0
 
cm89284Author Commented:
No but the download stops short and then it says Windows cannot open the folder "Windows cannot open the folder.  The Compressed (zipped) Folder: 'C:\Downloads\cd.zip' is invalid."
0
 
Dave BaldwinFixer of ProblemsCommented:
The easy test is to see if the file can be downloaded on one of the slow connections from a regular link instead of thru PHP.  If it succeeds, then the script timeout is the problem.
0
 
cm89284Author Commented:
Yes it can be downloaded through a direct link but if U specified the max execution time as 3600 how can it be a script timeout issue?
0
 
Dave BaldwinFixer of ProblemsCommented:
It doesn't do any good to keep asking the same question.  There are two timeout restrictions when you use PHP on IIS.  One is from PHP and one is from IIS.  The shortest value will set the limit.  Your 'ini' file only affects PHP.

I believe that your only solution would be to move to hosting that allows a longer timeout.
0
 
cm89284Author Commented:
I see thanks for all your help
0

Featured Post

Get free NFR key for Veeam Availability Suite 9.5

Veeam is happy to provide a free NFR license (1 year, 2 sockets) to all certified IT Pros. The license allows for the non-production use of Veeam Availability Suite v9.5 in your home lab, without any feature limitations. It works for both VMware and Hyper-V environments

  • 7
  • 7
Tackle projects and never again get stuck behind a technical roadblock.
Join Now