Welcome Guest, Not a member yet? Register   Sign In
Problem with download helper and AJAX calls. Expertise needed.
#1

[eluser]luismartin[/eluser]
I'm stuck with this issue. I'm not sure if this is something about CI or it is simply a general PHP error. I think it is more of PHP but perhaps someone could help:

I'm trying to implement an images downloader with which the users can download a series of selected images which are previously zipped in a cached file.

The downloader uses a fixed box which is persistent through pages until cancelled or download the images.

The process is like follows:

Quote:1- Once the user has chosen the images to download, he/she clicks on the download button in the download box.
2- Javascript (jQuery more specifically) manages the AJAX request. It sends the list of images to download through POST.
3- PHP gets the request.
4- A hash name is generated with the files list so that any request of the same files will have the same name (this will be useful to cache the requested files).
5- PHP checks whether the cached file already exists.
6a - If it exists, it directly calls the download helper function force_download()
6b - If not, the zip class does its job, archiving the images, and it finally calls $this->zip->download() which in turn gets the zipped file and calls force_download()
7- Javascript gets the response.

All the process seems to work, except that there's no prompt to download any file. The cached zip file is in fact generated and it stores the requested images correctly. The path for the force_download is exactly the same as the one used for the creation of the zip, so I'm not fetching from a wrong path.

The response headers are like follows:

Code:
Connection:Keep-Alive
Content-Disposition:attachment; filename="cache/5cc47c128fc1b6dfa4e433f9e64ca719.zip"
Content-Length:2795303
Content-Transfer-Encoding:binary
Content-Type:"application/x-zip"
Date:Thu, 17 May 2012 15:05:45 GMT
Expires:0
Keep-Alive:timeout=5, max=98
Pragma:no-cache
Server:Apache.......
....

Despite getting Content-Disposition:attachment, I get no file. Is it because of the asynchronous call? What could I do to fix this without giving up using ajax? I want ajax because I'd like to track the request in the same download box.
#2

[eluser]Aken[/eluser]
You can't force a file download through Ajax. Just a limitation of the technology. You can display a link to the user to download the file.
#3

[eluser]luismartin[/eluser]
[quote author="Aken" date="1337290988"]You can't force a file download through Ajax. Just a limitation of the technology. You can display a link to the user to download the file.[/quote]

Aha, it's ok. Thanks for the tip.

I found some workarounds for this limitation:
http://stackoverflow.com/questions/67969...javascript

Apache can force the files from a directory to be downloaded. I haven't tried it yet though.

What I've actually tried is not asynchronous and is not the best way but it does work. It's a jQuery plugin with a function which receives the data to send, creates a form on the fly with hidden fields and sends it.

http://www.filamentgroup.com/lab/jquery_...downloads/

Regards.
#4

[eluser]gRoberts[/eluser]
Could you not either:

1) Simply use [removed].href to redirect to the path of the zip file that has been created?

2) Create a 1x1 iframe and set the src to the path of the zip file.

Both of which would display the download prompt. #1 "should" simply show the download prompt without changing the current page, #2 will simply show the download prompt without changing the page.
#5

[eluser]luismartin[/eluser]
[quote author="gRoberts" date="1337317705"]Could you not either:

1) Simply use [removed].href to redirect to the path of the zip file that has been created?

2) Create a 1x1 iframe and set the src to the path of the zip file.

Both of which would display the download prompt. #1 "should" simply show the download prompt without changing the current page, #2 will simply show the download prompt without changing the page.[/quote]

Hello gRoberts,

I'm not sure what you mean in #1. Looks like part of the text has been removed automatically.
As for #2, you mean creating the 1x1 iframe after the server response? The iframe should be created at first? or should it work in both cases?

Regards.
#6

[eluser]gRoberts[/eluser]
Hi there,

Sorry, the forum removed part of my response.

#1 was "window dot location dot href" but replace the " dot " with a full stop.

#2 Could work in both situations. if you are using Ajax, then really, the iframe doesn't "have" to already exist. You could create it when you get a response back from the server.

i.e.

Code:
(function()
{
  $('#download').click(function(e)
  {
   e.preventDefault();
   $.ajax(
   {
    url : 'controller/action',
    dataType : 'json',
    type : 'POST',
    data :
    {
     Image1 : 'friend.jpg',
     Image2 : 'dog.jpg'
    },
    success : function(resp)
    {
     // using the iframe method
     if($('.download-frame').length == 0)
     {
      $('body').append($('<iframe class="download-frame" src="about:blank" />').css({ width : 1, height : 1 }));
      $('.download-frame').attr('src', resp.DownloadPath);
     }

     // using the [removed].href method
     [removed].href = resp.DownloadPath;
    },
    error : function()
    {
     alert('There was a problem generating the ZIP');
    }
   });
  });
});

Note: The above sample includes BOTH #1 and #2 methods, you will need to remove one or the other, otherwise it may result in two downloads appearing.

This would mean you have to change your PHP code slightly to, instead of "force_downloading" the file, you simply use json_encode to return the filename.

i.e.

Code:
$Filename = md5(time()) . '.zip';
if(!file_exists($Filename))
{
  //create zip
}
header('content-type: application/json');
die(json_encode(array('DownloadPath' => base_url() . 'cache/' . $Filename)));

Obviously, the part where you generate the filename and do all the checking is relevant, but instead of using force_download, you simply return the DownloadPath as a response in which the Ajax call (in javascript) will receive and change the iFrame to.
#7

[eluser]luismartin[/eluser]
Great answer! I will try that.

Thanks a lot for your help!
#8

[eluser]gRoberts[/eluser]
Sorry, just noticed a little error in my code above:

Code:
(function()
{
  $('#download').click(function(e)
  {
   e.preventDefault();
   $.ajax(
   {
    url : 'controller/action',
    dataType : 'json',
    type : 'POST',
    data :
    {
     Image1 : 'friend.jpg',
     Image2 : 'dog.jpg'
    },
    success : function(resp)
    {
     // using the iframe method
     if($('.download-frame').length == 0)
     {
      $('body').append($('<iframe class="download-frame" src="about:blank" />').css({ width : 1, height : 1 }));
     }
     $('.download-frame').attr('src', resp.DownloadPath);

     // using the [removed].href method
     [removed].href = resp.DownloadPath;
    },
    error : function()
    {
     alert('There was a problem generating the ZIP');
    }
   });
  });
});

With the #1 Iframe method, it would only work if the iframe did not exist due to an incorrectly place line of code.

I have moved the `$('.download-frame').attr('src', resp.DownloadPath);` outside of the if statement.
#9

[eluser]luismartin[/eluser]
It's ok, the background was perfectly undesrtood. Smile Only let me say one thing which has nothing to do with the topic either, just in case someone takes your code. The zip file should be created like this (this is an option):

Code:
md5($filename1 . $filename2 . ....); // preferably with a loop.

Otherwise the zip would have a semi-random name and the cached zip wouldn't probably be recoverable.




Theme © iAndrew 2016 - Forum software by © MyBB