PHPFixing
  • Privacy Policy
  • TOS
  • Ask Question
  • Contact Us
  • Home
  • PHP
  • Programming
  • SQL Injection
  • Web3.0
Showing posts with label zip. Show all posts
Showing posts with label zip. Show all posts

Thursday, November 3, 2022

[FIXED] How to unzip a zip with multiple files into my lambda node.js function tmp directory preserving the original filenames

 November 03, 2022     lambda, node.js, zip     No comments   

Issue

I have a zip file in S3 that contains several txt files and an image.

I am needing to grab that file from S3 and then unzip all of the files with their original filenames into the tmp directory in lambda using node.js

I am not super familiar with node and while the S3 part of getting the file works fine, I frankensteined the zip part together from the interwebs and was wondering if someone could help me get it right.

const zlib = require('zlib');
const fs = require('fs');
    
try { 
  const s3Object = await s3
    .getObject({
      Bucket: 'mybucket',
      Key: `zip/${myzipfilename}`
    })
    .promise();

  console.log("s3 zip fetched");
                
  // write file to tmp          
  writeFileSync(`/tmp/${myzipfilename}`, s3Object.Body);
        
  //unzip files
  const fileContents = fs.createReadStream(`/tmp/${myzipfilename}`);

  //I am quite sure this part is incorrect and is currently giving me an error
  const writeStream = fs.createWriteStream(`./tmp/${filename.slice(0, -3)}`);

  const unzip = zlib.createGunzip();
  fileContents.pipe(unzip).pipe(writeStream);            
}

End result within the lambda tmp directory would be something like:

/tmp/myoriginaltxtfilename.txt
/tmp/myoriginaltxtfilename2.txt
/tmp/myoriginaltxtfilename3.txt
/tmp/myoriginalimagefilename.png

I don't need to rezip anything.


Solution

You have a couple of issues in your code. First of all, at this line:

const writeStream = fs.createWriteStream(`./tmp/${filename.slice(0, -3)}`);

filename is not defined.

Second, you're using nodejs zlib to extract a .zip file which contains multiple files which won't work. zlib module is only for streams and buffers that represent singular resources not zip archives. You could use node-stream-zip instead.

Let's say you've successfully downloaded the zip file from S3 and saved in /tmp directory. Using node-stream-zip extracting the files from the zip file without unzipping it would look something like this:

const StreamZip = require('node-stream-zip');
const zip = new StreamZip({
    file: `/tmp/${myzipfilename}`,
    storeEntries: true
});

zip.on('ready', () => {
  console.log('All entries read: ' + zip.entriesCount);
});

zip.on('entry', (entry) => {
  if ('/' === entry.name[entry.name.length - 1]) {
    console.log('[DIR]', entry.name);
    return;
  }

  console.log('[FILE]', entry.name);

  zip.stream(entry.name, (err, stream) => {
    if (err) {
      console.log('Error: ', err.toString());
      return;
    }

    stream.on('error', (err) => {
      console.log('[ERROR]', err);
      return;
    });

    stream.pipe(fs.createWriteStream(`/tmp/${entry.name}`));
  });
});


Answered By - Rahul Sharma
Answer Checked By - Robin (PHPFixing Admin)
Read More
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg

Sunday, August 28, 2022

[FIXED] How to write a table encoded as a list of dictionaries directly to a zipped archive containing a CSV?

 August 28, 2022     csv, python, sparse-matrix, zip     No comments   

Issue

Suppose you have data in the form of a list of dictionaries like d here:

d = [{'a' : 1, 'b' : 2}, {'a' : 3, 'c' : 5}]

and you want to save it as a comma-separated table to a zipped (not gzipped, I mean a .zip archive) CSV without going via, e.g., a pandas.DataFrame.from_dict().

Why not via pandas? Because d in real practice may correspond to a very large, but especially sparse, DataFrame, i.e. a table with many more columns than non-NA data per row, which for some reason occupies a huge amount of memory (BTW this is not a theory: it made our scripts crash several times, hence our need to work around it).

d is a sort of unpivoted-in-disguise version of the data, because each dictionary only contains the relevant data, not a useless sequence of NA's.

From the csv module's documentation I learned how to write d directly to a CSV:

with open('test.csv', 'w') as csvfile :
    writer = csv.DictWriter(csvfile, fieldnames = ['a','b','c'])
    writer.writeheader()
    writer.writerows(d)

but I don't see any option to write to a zipped CSV.

I consulted the documentation of zipfile, but I could not make it work, due to the usual problem between text and bytes.

if os.path.exists('test.csv.zip') :
    os.remove('test.csv.zip')
with zipfile.ZipFile('test.csv.zip', mode = 'a') as zip :
    with zip.open('test.csv', 'w') as csvfile :
        writer = csv.DictWriter(csvfile, fieldnames = ['a','b','c'])
        writer.writeheader()
        writer.writerows(d)

# TypeError: a bytes-like object is required, not 'str'

Can anyone think of a workaround, or maybe a radically different approach that I am not seeing?

The fundamental constraints are:

  1. d is always going to be generated: this we cannot decide or change
  2. avoid generating very large objects that consume as much memory or disk space as the dense pandas.DataFrame.from_dict()
  3. the data must be written to a csv.zip archive.

Otherwise we would write to a CSV, hoping that it is not too huge (but yeah, that was the initial issue, so...), and zip it afterwards.


EDIT posting the implementation from Daweo's answer, for completeness.

import os
import zipfile
import csv
import codecs
utf8 = codecs.getwriter('utf_8') # or other encoding dictated by requirements

output_zip_file = 'test.csv.zip'

if os.path.exists(output_zip_file) :
    os.remove(output_zip_file)
with zipfile.ZipFile(output_zip_file, mode = 'a') as zip :
    with zip.open('out.csv', 'w') as csvfile :
        writer = csv.DictWriter(utf8(csvfile), fieldnames = ['a','b','c'])
        writer.writeheader()
        writer.writerows(d)

Solution

You might use codecs.StreamWriter if you want to use csv.DictWriter with binary file-handle, consider following simple example

import csv
import codecs
utf8 = codecs.getwriter('utf_8') # or other encoding dictated by requirements
with open("file.csv","wb") as f:
    writer = csv.DictWriter(utf8(f), fieldnames = ['a','b','c'])
    writer.writeheader()
    writer.writerows([{'a':1},{'b':2},{'c':3}])

creates file.csv holding

a,b,c
1,,
,2,
,,3


Answered By - Daweo
Answer Checked By - Candace Johnson (PHPFixing Volunteer)
Read More
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg

[FIXED] How to access multiple CSV files that share the same name from multiple folders from a zip file

 August 28, 2022     csv, dataframe, pandas, python, zip     No comments   

Issue

I have a zip file (stored locally) with multiple folders in it. In each folder are a few CSV files. I need to only access 1 particular CSV from each folder. The CSV's I am trying to access from each folder all share the same name, but I cannot figure out how to access a particular file from each folder, then concatenate them into a pandas df.

I have tried the below (initially trying to read all CSV's):

path = r"C:\Users\...\Downloads\folder.zip"
all_files = glob.glob(os.path.join(path , "/*.csv"))

li = []

for filename in all_files:
    df = pd.read_csv(filename, index_col=None)
    li.append(df)

frame = pd.concat(li, axis=0, ignore_index=True)

But I get: ValueError: No objects to concatenate. The CSV's are definitely present and not empty.

I am currently trying to do this in a sagemaker notebook, not sure if that is also causing me problems. Any help would be great.


Solution

After some digging and advice from Umar.H and mad, I figured out a solution to my original question and to the code example I was originally working with.

The code I was originally working with wasn't working with accessing the zip file directly, so I unzipped the file and tried it on just a regular folder. Amending the empty list of df's li to not return an empty list was solved by changing "/*file.csv" in all_files to "*/*file.csv.

To solve the main issue I had, which was to avoid unzipping the zip file and access all required CSV's I managed to get the following to work

PATH = "C:/Users/.../Downloads/folder.zip"

li = []
with zipfile.ZipFile(PATH, "r") as f:
    for name in f.namelist():
        if name.endswith("file.csv"):
            data = f.open(name)
            df = pd.read_csv(data, header=None, low_memory = False)
            li.append(df)

frame = pd.concat(li, axis=0, ignore_index=True)

Hope this can be helpful for anyone else with large zip files.



Answered By - Jasper_97
Answer Checked By - Mary Flores (PHPFixing Volunteer)
Read More
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg

Thursday, May 19, 2022

[FIXED] How to post (HTTP POST) zipfile and parameters in ObjectiveC?

 May 19, 2022     file-upload, http-post, iphone, web-services, zip     No comments   

Issue

I have tried to Post a Zipfile and some parameters to web service, but i get the response "missing ebook file", so how to Post zip file and parameters in Objectivec please help me

Thanks in Advance

I have tried this:

      NSString *urlString1 = [NSString stringWithFormat:@"http://www.EbookFile.com/index.php?q=api/upload&APPkey=dfsfwerwe324342323432"];



    NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] init] autorelease];
                [request setURL:[NSURL URLWithString:urlString1]];
                [request setHTTPMethod:@"POST"];

                    NSString *boundary = [NSString stringWithString:@"---------------------------14737809831466499882746641449"];
                    NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@",boundary];
                    [request addValue:contentType forHTTPHeaderField: @"Content-Type"];
                    NSMutableData *body = [NSMutableData data];

                // Parameter 1

                [body appendData:[[NSString stringWithFormat:@"--%@\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]];
                [body appendData:[[NSString stringWithString:@"Content-Disposition: form-data; name=\"uid\"\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
                [body appendData:[uid dataUsingEncoding:NSUTF8StringEncoding]];
                [body appendData:[[NSString stringWithString:@"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];


                        // Parameter 2

                [body appendData:[[NSString stringWithFormat:@"--%@\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]];
                [body appendData:[[NSString stringWithString:@"Content-Disposition: form-data; name=\"title\"\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
                [body appendData:[titleText.text dataUsingEncoding:NSUTF8StringEncoding]];
                [body appendData:[[NSString stringWithString:@"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];

                // Parameter 3


                [body appendData:[[NSString stringWithFormat:@"--%@\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]];
                [body appendData:[[NSString stringWithString:@"Content-Disposition: form-data; name=\"token\"\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
                [body appendData:[token dataUsingEncoding:NSUTF8StringEncoding]];
                [body appendData:[[NSString stringWithString:@"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];

                // Parameter 4


                [body appendData:[[NSString stringWithFormat:@"--%@\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]];
                [body appendData:[[NSString stringWithString:@"Content-Disposition: form-data; name=\"desc\"\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
                [body appendData:[descText.text dataUsingEncoding:NSUTF8StringEncoding]];
                [body appendData:[[NSString stringWithString:@"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];

                // Parameter 5


                [body appendData:[[NSString stringWithFormat:@"--%@\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]];
                [body appendData:[[NSString stringWithString:@"Content-Disposition: form-data; name=\"cat\"\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
                [body appendData:[CatId dataUsingEncoding:NSUTF8StringEncoding]];
                [body appendData:[[NSString stringWithString:@"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];


        // ZIP File Post here

                int r = arc4random() % 8000000;
                NSString *RandomNumber = [NSString stringWithFormat:@"%d",r];
                NSString *file = [RandomNumber stringByAppendingString:@".zip"];

                NSData *Filedata = [NSData dataWithContentsOfURL:[NSURL fileURLWithPath:archivePath]]; // ZIP file convert to NAData here

                [body appendData:[[NSString stringWithFormat:@"Content-Disposition: attachment; name=\"file\"; filename=\"%@\"\r\n",file] dataUsingEncoding:NSUTF8StringEncoding]];
                [body appendData:[[NSString stringWithString:@"Content-Type: application/octet-stream\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
                [body appendData:Filedata];
                [body appendData:[[NSString stringWithFormat:@"\r\n--%@--\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]];
                [request setHTTPBody:body];

                // pointers to some necessary objects
                NSHTTPURLResponse* response =[[NSHTTPURLResponse alloc] init];
                NSError* error = [[NSError alloc] init] ;

                // synchronous filling of data from HTTP POST response
                NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];

                if (error)
                {
                }

 NSString *responseString = [[[NSString alloc] initWithBytes:[responseData bytes]
                                                                     length:[responseData length]
                                                                   encoding:NSUTF8StringEncoding] autorelease];

Solution

 NSString *urlString1 = [NSString stringWithFormat:@"http://www.efferwrwre.com/index.php?q=api/upload&key=f5746442fb9067b3fba83c3da0351f1f"];
    NSLog(@"URLSTribg : %@", urlString1);
    NSString *ww = [urlString1 stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    
    NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] init] autorelease];
    [request setURL:[NSURL URLWithString:ww]];
    [request setHTTPMethod:@"POST"];
    
    NSString *boundary = [NSString stringWithString:@"---------------------------14737809831466499882746641449"];
    NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@",boundary];
    [request addValue:contentType forHTTPHeaderField: @"Content-Type"];
    NSMutableData *body = [NSMutableData data];
        
    [body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithString:@"Content-Disposition: form-data; name=\"uid\"\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[uid dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]];
    
    
    [body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithString:@"Content-Disposition: form-data; name=\"title\"\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[titleText.text dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]];
    
    
    [body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithString:@"Content-Disposition: form-data; name=\"token\"\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[token dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]];
    
    
    [body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithString:@"Content-Disposition: form-data; name=\"desc\"\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[descText.text dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]];

    
    [body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithString:@"Content-Disposition: form-data; name=\"cat\"\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[CatId dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]];
    
    int r = arc4random() % 8000000;
    NSString *RandomNumber = [NSString stringWithFormat:@"%d",r];
    NSString *file = [RandomNumber stringByAppendingString:@".zip"];
    
    NSData *Filedata = [NSData dataWithContentsOfURL:[NSURL fileURLWithPath:archivePath]];
    NSLog(@"file:%@",Filedata);
    
    [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"file\"; filename=\"%@\"\r\n",file] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithString:@"Content-Type: application/octet-stream\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:Filedata];
    [body appendData:[[NSString stringWithFormat:@"\r\n--%@--\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [request setHTTPBody:body];

 NSHTTPURLResponse* response =[[NSHTTPURLResponse alloc] init];
    NSError* error = [[NSError alloc] init] ;
    
    NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
    if (error)
    {
        
    }
    
    NSString *responseString = [[[NSString alloc] initWithBytes:[responseData bytes]
                                                         length:[responseData length]
                                                       encoding:NSUTF8StringEncoding] autorelease];
    NSLog(@"%@", responseString);


Answered By - SampathKumar
Answer Checked By - Marilyn (PHPFixing Volunteer)
Read More
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg

Thursday, May 5, 2022

[FIXED] how can I export multiple images using zipfile and urllib2

 May 05, 2022     django, image, python, python-zipfile, zip     No comments   

Issue

I am trying to add multiple image files into my zip. I have searched around and knows how to add a single one. I tried to loop through multiple images then write into it but it didn't work.

I kind of did the same thing with txt format and it works that I can compress a few files into the zip but somehow not when with image.

# get all photos in db which will be a queryset as result
photos = Photo.objects.all()

# loop through the queryset
for photo in photos:
    # open the image url
    url = urllib2.urlopen(photo.image.url)
    # get the image filename including extension
    filename = str(photo.image).split('/')[-1]
    f = StringIO()
    zip = ZipFile(f, 'w')
    zip.write(filename, url.read())
zip.close()
response = HttpResponse(f.getvalue(), content_type="application/zip")
response['Content-Disposition'] = 'attachment; filename=image-test.zip'
return response

This would give me the last image which in a way I can see why.


Solution

Don't create a new zip file in every iteration. Instead, write all the files to the same archive (which you instantiate before the loop):

f = StringIO()
zip = ZipFile(f, 'w')

for photo in photos:
    url = urllib2.urlopen(photo.image.url)
    filename = str(photo.image).split('/')[-1]
    zip.write(filename, url.read())
zip.close()


Answered By - user2390182
Answer Checked By - David Goodson (PHPFixing Volunteer)
Read More
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg

Thursday, December 30, 2021

[FIXED] LAMP: How to create .Zip of large files for the user on the fly, without disk/CPU thrashing

 December 30, 2021     bash, lamp, php, pipe, zip     No comments   

Issue

Often a web service needs to zip up several large files for download by the client. The most obvious way to do this is to create a temporary zip file, then either echo it to the user or save it to disk and redirect (deleting it some time in the future).

However, doing things that way has drawbacks:

  • a initial phase of intensive CPU and disk thrashing, resulting in...
  • a considerable initial delay to the user while the archive is prepared
  • very high memory footprint per request
  • use of substantial temporary disk space
  • if the user cancels the download half way through, all resources used in the initial phase (CPU, memory, disk) will have been wasted

Solutions like ZipStream-PHP improve on this by shovelling the data into Apache file by file. However, the result is still high memory usage (files are loaded entirely into memory), and large, thrashy spikes in disk and CPU usage.

In contrast, consider the following bash snippet:

ls -1 | zip -@ - | cat > file.zip
  # Note -@ is not supported on MacOS

Here, zip operates in streaming mode, resulting in a low memory footprint. A pipe has an integral buffer – when the buffer is full, the OS suspends the writing program (program on the left of the pipe). This here ensures that zip works only as fast as its output can be written by cat.

The optimal way, then, would be to do the same: replace cat with a web server process, streaming the zip file to the user with it created on the fly. This would create little overhead compared to just streaming the files, and would have an unproblematic, non-spiky resource profile.

How can you achieve this on a LAMP stack?


Solution

You can use popen() (docs) or proc_open() (docs) to execute a unix command (eg. zip or gzip), and get back stdout as a php stream. flush() (docs) will do its very best to push the contents of php's output buffer to the browser.

Combining all of this will give you what you want (provided that nothing else gets in the way -- see esp. the caveats on the docs page for flush()).

(Note: don't use flush(). See the update below for details.)

Something like the following can do the trick:

<?php
// make sure to send all headers first
// Content-Type is the most important one (probably)
//
header('Content-Type: application/x-gzip');

// use popen to execute a unix command pipeline
// and grab the stdout as a php stream
// (you can use proc_open instead if you need to 
// control the input of the pipeline too)
//
$fp = popen('tar cf - file1 file2 file3 | gzip -c', 'r');

// pick a bufsize that makes you happy (64k may be a bit too big).
$bufsize = 65535;
$buff = '';
while( !feof($fp) ) {
   $buff = fread($fp, $bufsize);
   echo $buff;
}
pclose($fp);

You asked about "other technologies": to which I'll say, "anything that supports non-blocking i/o for the entire lifecycle of the request". You could build such a component as a stand-alone server in Java or C/C++ (or any of many other available languages), if you were willing to get into the "down and dirty" of non-blocking file access and whatnot.

If you want a non-blocking implementation, but you would rather avoid the "down and dirty", the easiest path (IMHO) would be to use nodeJS. There is plenty of support for all the features you need in the existing release of nodejs: use the http module (of course) for the http server; and use child_process module to spawn the tar/zip/whatever pipeline.

Finally, if (and only if) you're running a multi-processor (or multi-core) server, and you want the most from nodejs, you can use Spark2 to run multiple instances on the same port. Don't run more than one nodejs instance per-processor-core.


Update (from Benji's excellent feedback in the comments section on this answer)

1. The docs for fread() indicate that the function will read only up to 8192 bytes of data at a time from anything that is not a regular file. Therefore, 8192 may be a good choice of buffer size.

[editorial note] 8192 is almost certainly a platform dependent value -- on most platforms, fread() will read data until the operating system's internal buffer is empty, at which point it will return, allowing the os to fill the buffer again asynchronously. 8192 is the size of the default buffer on many popular operating systems.

There are other circumstances that can cause fread to return even less than 8192 bytes -- for example, the "remote" client (or process) is slow to fill the buffer - in most cases, fread() will return the contents of the input buffer as-is without waiting for it to get full. This could mean anywhere from 0..os_buffer_size bytes get returned.

The moral is: the value you pass to fread() as buffsize should be considered a "maximum" size -- never assume that you've received the number of bytes you asked for (or any other number for that matter).

2. According to comments on fread docs, a few caveats: magic quotes may interfere and must be turned off.

3. Setting mb_http_output('pass') (docs) may be a good idea. Though 'pass' is already the default setting, you may need to specify it explicitly if your code or config has previously changed it to something else.

4. If you're creating a zip (as opposed to gzip), you'd want to use the content type header:

Content-type: application/zip

or... 'application/octet-stream' can be used instead. (it's a generic content type used for binary downloads of all different kinds):

Content-type: application/octet-stream

and if you want the user to be prompted to download and save the file to disk (rather than potentially having the browser try to display the file as text), then you'll need the content-disposition header. (where filename indicates the name that should be suggested in the save dialog):

Content-disposition: attachment; filename="file.zip"

One should also send the Content-length header, but this is hard with this technique as you don’t know the zip’s exact size in advance. Is there a header that can be set to indicate that the content is "streaming" or is of unknown length? Does anybody know?


Finally, here's a revised example that uses all of @Benji's suggestions (and that creates a ZIP file instead of a TAR.GZIP file):

<?php
// make sure to send all headers first
// Content-Type is the most important one (probably)
//
header('Content-Type: application/octet-stream');
header('Content-disposition: attachment; filename="file.zip"');

// use popen to execute a unix command pipeline
// and grab the stdout as a php stream
// (you can use proc_open instead if you need to 
// control the input of the pipeline too)
//
$fp = popen('zip -r - file1 file2 file3', 'r');

// pick a bufsize that makes you happy (8192 has been suggested).
$bufsize = 8192;
$buff = '';
while( !feof($fp) ) {
   $buff = fread($fp, $bufsize);
   echo $buff;
}
pclose($fp);

Update: (2012-11-23) I have discovered that calling flush() within the read/echo loop can cause problems when working with very large files and/or very slow networks. At least, this is true when running PHP as cgi/fastcgi behind Apache, and it seems likely that the same problem would occur when running in other configurations too. The problem appears to result when PHP flushes output to Apache faster than Apache can actually send it over the socket. For very large files (or slow connections), this eventually causes in an overrun of Apache's internal output buffer. This causes Apache to kill the PHP process, which of course causes the download to hang, or complete prematurely, with only a partial transfer having taken place.

The solution is not to call flush() at all. I have updated the code examples above to reflect this, and I placed a note in the text at the top of the answer.



Answered By - Lee
Read More
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg
Older Posts Home

Total Pageviews

Featured Post

Why Learn PHP Programming

Why Learn PHP Programming A widely-used open source scripting language PHP is one of the most popular programming languages in the world. It...

Subscribe To

Posts
Atom
Posts
All Comments
Atom
All Comments

Copyright © PHPFixing