SitePoint Sponsor

User Tag List

Results 1 to 10 of 10
  1. #1
    SitePoint Addict whydna's Avatar
    Join Date
    Jun 2006
    Posts
    258
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Downloading remote file, progress bar?

    hey guys,

    I am downloading a file from another server to my server and trying to show a progress bar using ajax.

    The easiest way I can think of right now, is by calling file_get_contents with a limit and offset to get the file in chunks, using fwrite to write to a file, and then updating the progress bar and repeat until the file is done.

    This doesn't seem very efficient to me, and was wondering if anyone else had a better idea?

  2. #2
    SitePoint Wizard bronze trophy
    Join Date
    Jul 2008
    Posts
    5,757
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    The other server will need to send a content-length header so you know how many bytes the response will contain, otherwise you won't be able to calc a percentage.

    You want to use a php cli script to do the actual downloading so you don't have such long running processes in your webserver. They can communicate with a script in the webserver through a database.

    Assuming you want to save the file to the filesystem, I think the easiest way is to simply store the anticipated filesize in the database, along with a download_id or whatever else will uniquiely identify a specific downloading event, and the filename it will be saved as.

    cli script
    PHP Code:
    $source fopen($url'r');
    print_r(stream_get_meta_data($source)); // parse content-length out
    $dest fopen($new_filename'w');
    //update database with size and filename
    stream_copy_to_stream($sourcedest); 
    The other script which runs in the webserver, that ajax will poll, just looks up the filename and size via the database, and calcs by using filesize()

  3. #3
    SitePoint Wizard bronze trophy
    Join Date
    Jul 2008
    Posts
    5,757
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    You could also forgo stream_copy_to_stream and just use a loop to copy small chunks at a time, periodically updating a bytes_received column in the database. Then you don't need to stat the file each time. Be mindful of max database connections either way, as you could end up with many open if you have a lot of downloads going and you don't close them until the script is finished.

  4. #4
    SitePoint Addict whydna's Avatar
    Join Date
    Jun 2006
    Posts
    258
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Instead of updating a db, couldn't the ajax script just check the size of the file that has been written to so far?

  5. #5
    SitePoint Wizard bronze trophy
    Join Date
    Jul 2008
    Posts
    5,757
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Yeah, you could just send a head request.

  6. #6
    SitePoint Addict whydna's Avatar
    Join Date
    Jun 2006
    Posts
    258
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Im actually having a lot of problems with this. My code is as follows:

    HTML Code:
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    <html>
    	<head>
    		<title></title>
    		<script type="text/javascript">
    			window.addEvent('domready', function() {
    				
    				startDownload(src, dest);
    				while(1) {
    					getDownloadProgress(dest);
    					sleep(2);
    				}	
    			});
    					
    			function startDownload()
    			{
                    var request = new Request(
                            {
                                url: reqUrl,
                                onSuccess: function(response) 
                                    {
    									alert('download done');
                                    }
                            }
                        );
                    request.send();
    			}
    
    			function getDownloadProgress()
    			{
                    var request = new Request(
                            {
                                url: reqUrl,
                                onSuccess: function(response) 
                                    {
    									$('percent_complete').innerHTML=response;
                                    }
                            }
                        );
                    request.send();
    			}
    		</script>
    	</head>
    	<body>
    		<div id="percent_complete"></div>&#37;
    	</body>
    </html>
    
    The problem seems to be that mootools is having trouble running simultaneous ajax calls. It starts the download, but never updates the progress until the actual download is done. I thought ajax was suppose to be asynchronous?? Any ideas?

  7. #7
    SitePoint Addict whydna's Avatar
    Join Date
    Jun 2006
    Posts
    258
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Here is the code better formatted:

    HTML Code:
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    <html>
         <head>
              <title></title>
                   <script type="text/javascript">
                        window.addEvent('domready', function() {
                             startDownload(src, dest);
                                  while(1) {
                                       getDownloadProgress(dest);
                                       sleep(2);
                                  }	
                        });
    					
                        function startDownload()
                        {
                             var request = new Request(
                                  {
                                       url: reqUrl,
                                       onSuccess: function(response) 
                                            {
                                                 alert('download done');
                                            }
                                  }
                             );
                             request.send();
                        }
    
                        function getDownloadProgress()
                        {
                             var request = new Request(
                                  {
                                       url: reqUrl,
                                       onSuccess: function(response) 
                                            {
                                                 $('percent_complete').innerHTML=response;
                                            }
                                  }
                             );
                             request.send();
                        }
                   </script>
              </head>
              <body>
                   <div id="percent_complete"></div>&#37;
              </body>
    </html>

  8. #8
    SitePoint Wizard bronze trophy
    Join Date
    Jul 2008
    Posts
    5,757
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I don't think I wanna know the definition of that sleep() function is Ajax is asynchronous, but userland javascript code is still single threaded. You can block a lot of stuff from happening if you put a big loop in there.

    Anyway, you should just have your success callback update the dom like you are, but also have it initiate another request if not done. eg
    Code:
                                       onSuccess: function(response) 
                                            {
                                                 $('percent_complete').innerHTML=response;
                                                 if (response !== '100') getDownloadProgress();
                                            }
    and do away with that while(1)

    Optionally, you might want to introduce some timers into this. For example, enforcing a minimum time between polling to keep your server from getting hammered with potentially rapid requests.
    Code:
                                       onSuccess: function(response) 
                                            {
                                                 $('percent_complete').innerHTML=response;
                                                 if (response !== '100') setTimeout(function() {getDownloadProgress()}, 2000);
                                            }
    And, also checking for failure(staled download progress, failed download etc...)

  9. #9
    SitePoint Addict whydna's Avatar
    Join Date
    Jun 2006
    Posts
    258
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Ah ok. I will try that.

    But I still have the problem of not being able to download and poll for progress at the same time.

  10. #10
    SitePoint Wizard bronze trophy
    Join Date
    Jul 2008
    Posts
    5,757
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I wouldn't have the first request that initiates the download wait for it to complete. Are these scripts using php sessions?


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •