Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chris Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

execute code upon download completion 1

Status
Not open for further replies.

danno74

IS-IT--Management
Nov 13, 2002
295
US
Greetings,

Currently, I have a page that once a user selects a file they want to download, it moves and renames the file from another folder to the download folder, then executes the file download.

What I want to accomplish is to delete the file after the download of it has completed. I tried to execute a simple sleep command within the page, but seems to execute the sleep command prior to the header command to download the page:

Code:
<?php

        $rdmint=rand(10000, 99999);
        $hiddenpath='/hiddenpath/';
        $downloadpath='/download/';
        $filename='bigfile';
        $destnewfile="$filename$rdmint.zip";
        $file="$hiddenpath$filename.zip";
        $newfile="$downloadpath$destnewfile";


        if(copy($file, $newfile))
        {
        echo "File copied successfully.";
        }
        else
        {
        echo "Failed to copy $file, please contact the Helpdesk.";
        }

        header("Location: [URL unfurl="true"]https://download/$destnewfile");[/URL]
        

        sleep(60);


        if (unlink($newfile))
        {
        echo "File moved from server successfully.";
        }

?>

Any ideas on how I can accomplish this? Will putting the sleep and unlink cmds in another file alleviate the problem possibly?

Thank you for your time.

- Dan
 
Unfortunately, once the user's browser has received the "Location" header, it immediately severs the current connection and establishes a new one with the specified URL. So anything after the header('Location: ...') invocation will not run.

Instead, you can make PHP stream the file to the browser. In the online manual entry for header() ( Example #1 shows how to do this by sending the browser Content-type and Content-Disposition headers. The example code reads:

Code:
<?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');
?>


Want to ask the best questions? Read Eric S. Raymond's essay "How To Ask Questions The Smart Way". TANSTAAFL!
 
Thanks sleipnir.

Actually, that is what my page currently does, but the files are too large to pass through readfile, after I get past 80MB, I get errors or empty files downloaded. I now have 300-400MB+ files that I cannot split up. Thus my attempts at this current workaround.

 
Then you might try a housekeeping function.

Create a PHP include file, which you include in other scripts where appropriate. Have that included script-code scan your download directory and delete any file that is older than a certain amount of time.

Of course, the fun part about this way is the definitions of "where appropriate" and "a certain amount of time". If you run this script too often in your site, you can have processing overhead you don't want, so be circumspect where in your site you run it. And you want, I'm sure, to give your users a reasonable amount of time to finish their downloads before deleting the file, but not to leave it there long enough to be found.

If you have sufficient control over the server where this runs, you could even set up a cron job (or whatever is equivalent on non-Unix-like OSes) to do this deletion on its own.


Want to ask the best questions? Read Eric S. Raymond's essay "How To Ask Questions The Smart Way". TANSTAAFL!
 
something is probably wrong at your end or perhaps in your browser that you are using for testing.

however, there is a workaround for your original query

1. when the user clicks the download link on the first page, instead of loading a new page in the main window, open up an iframe with javascript and download the file through that.
2. using (for example) jquery on the main page, and assuming that the iframe is called myIFrame, use this function to test when the content is downloaded
Code:
jQuery('#myIFrame').load(function(){
 //
});
3. in the anonymous function pass a variable back to the server via ajax that will cause the server to delete the file.

alternatively, set a time out on the file after which it will be deleted (do this via a db entry or a flat file or something that you check with a cron job, or just check the file creation time in the file system).
 
Thanks for your suggestions. I'm interested in hearing what solutions you may have for the problems I was having with the original code. I have posted this questions on many forums with this original code and never found a solution - maybe I was asking it in a way people couldn't understand...


Here code I'm currently using:

Code:
 //Location of file, must be out of web root
      $file_location='/download/software.exe';
	  
      //supply the right file format      
      header('Content-type: application/exe');
	  header('Expires: 0');
	  header('Pragma: public');
      
      //force browser to prompt to download file
      
      header('Content-Disposition: attachment; filename="software.exe"');
	
      
      //finally echo content
      readfile($file_location);

I get a server error, problem has nothing to do with browser -

[Fri Aug 12 14:58:53 2011] [error] [client ] PHP Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 358830081 bytes) in /file.php on line 24, referer:
Help is immensely appreciated.... I'm only asking because I know very little about javascript and jquery.

- Dan
 
try this

Code:
//Location of file, must be out of web root
$file_location='/download/software.exe';

if(!file_exists($file_location) || is_readable($file_location)):
	echo 'problem';
	exit;
endif;
//supply the right file format      
header('Content-type: application/octet-stream');
header('Expires: 0');
header('Pragma: public');

//force browser to prompt to download file
header('Content-Disposition: attachment; filename="software.exe"');
$size  = filesize($file_location);
header('Content-Length: ' .$size ); //explicitly provide the file size

//*** EITHER *** ///
ini_set('memory_limit', ($size * 1.5));
readfile($file_location);
exit; //always explicitly exit

//** OR **//
$fh = fopen ($file_location, "rb");
while (!feof($fh)):
	echo fread($fh, 100000);
endwhile;
fclose($fh);
 
You know jpadie, I was about to reply with the error I normally get when I do this, and it run without a hitch. I also had to set
Code:
ini_set("max_execution_time", "900");

It works now! We're going to do some testing - do you know if we get say 5 users doing this at once, will the memory limit be exceeded, or is it on a per execution basis?
 
memory_limit sets the maximum amount of time that the relevant script is allowed to use. so per connection (essentially).

add this to the start or expressly make sure that output buffering is turned off.
Code:
@ob_end_clean();

i had thought that readfile() did not buffer the content but your experience suggests either that it does buffer or that output buffering was turned on and set to quite a high value. I had meant to add the line into the code I posted above.

i am surprised that max_execution_time was also needed as normally things that happen externally to the script (i.e. database operations, file reads/writes, buffer outputs) are not counted in the time that the script itself takes to run.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top