2

Can skip About and Goal if necessary. They provide context/background about program.

The Problem:
When I download a zip archive that is supposed to have a csv file in it, I get an empty archive or invalid archive. Now, I can make the zip archive with the csv in it, on the server and download via FileZilla. This is not the desired use case. User wants to download automatically after clicking a button.

About program:
Agents sign up for event (i.e. RSVP to it) and provide a set of photos. For every agent, there are +1 photos. User wants to download a list of all RSVPs for each event (i.e. the sign up data). For each RSVP, User also wants to see the photos they uploaded to the server.

Goal of program:

  1. Create csv file on server of mysql query (each row is an RSVP)
  2. For each row, create zip archive for that row's/RSVP's photos.
  3. Wanted: 1 csv file and multiple zip archives all in one big archive
  4. End result: Add all files into one zip archive and download to User.
  5. Addendum: This big zip file needs to be freshly generated every time it is requested.

Current Status of Program:
CSV file created. Below it is added to ZipArchive object. Downloaded zip file and found it empty.

//store the result of the query. Included to show process
$result = mysqli_query($dbh, $sql);
//open the file to write the information to.
$file = fopen('event-report.csv', 'w');
$txt .= 'Title Company,' .'Event ID,' . 'Event Time,' . 'First Name,' . 'Last Name,' . 'Email,' . 'Agent Company,' . 'Phone Number,' . 'Listing ID,' . 'URL,' . 'Address,' . 'ZIP,' . "\n";
while ($row = mysqli_fetch_row($result)){
    for ($i=0; $i<12; $i++){
        $txt .= $row[$i] . ',';             //About the agent attending
    }
    $txt .= "\n";
    $listings[$listing_count] = $row[8];    
}
fputs($file, $txt); //store into csv file
fclose($file);        //verified on server; contains desired output

$zip = new ZipArchive();
$dir = 'tmp';                  //create temporary directory with write access
if ( !file_exists($dir) ) {
    mkdir ($dir, 0755);        //Everything for owner, read/execute for others
}
if($zip->open('test.zip', ZIPARCHIVE::CREATE) === TRUE ){

    $zip->addFile('event-report.csv');
    if (file_exists($zip->getFromName('event-report.csv'))){
        echo "Exists";
    }
    else{
        echo "Does Not Exist";
        echo $_SERVER['DOCUMENT_ROOT'];
    }
}
else {
    echo "Failed code";
}
$zip->close();
if(!$return){
    echo " You do not have write access to current folder.";
}
else{
    echo "You do have access.";  //without headers, the zip containing csv successfully created on server.
}

header('Content-disposition: attachment; filename=download.zip');
header('Content-type: application/zip');
readfile($dir.'/test.zip');     //When downloaded: still empty/invalid.

Possible Problem(s)

  1. Zip is not finding the file because it is being created at the same time.
    1a. Solved:. Files created can be put into zip archive right after closing.
  2. addFile parameter(s) are incorrect or lacking.
    2a. Man page says for this parameter: "path to the file to add"
    2b. Tried putting the path after the domain name but no success:
    $zip->addFile('/f1/f2/f3/f.csv');
    2c. PHP Manual > ZipArchive::addFile
      i. Solved: The parameter is just the name of the file. No path is needed in this case.

Questions

  1. How do I add a csv file, a zip archive, or any file in general to another zip archive so that it will not be empty when I download it?
  2. Is this implementation incorrect because I am trying to add a file to a zip archive right after creating it? See Possible Problem(s) 1.
  3. If this question can be solved by a little reading, then what resources can you link that can guide me along? I have spent an entire day reading in regards to this issue and do not feel like I understand what I am missing here.
    3a. file permissions
Community
  • 1
  • 1
Aaron Ko
  • 54
  • 7
  • I have not created the other zip archives yet. I am only testing right now with the 1 csv file that I do currently have. Theoretically, it is added to the zip archive and downloaded in my code snippet above. Debugging is a little confusing because the browser tab that opens to download closes right away. Cannot see any echo data. – Aaron Ko Jul 28 '14 at 06:12
  • Set path as full path: e.g. `$zip->addFile($_SERVER['DOCUMENT_ROOT'] . '/path/to/my/file.csv');` Next error is `readfile($file);` What do you expect to read here? – u_mulder Jul 28 '14 at 06:21
  • Not sure why `readfile($file)` is there. I do not expect to read anything. Removed it. Also, edited post to include some error checking. I tried to use `$_SERVER['DOCUMENT_ROOT']` but it returned folder names in the path that I could not access (i.e. `home/showsell/restofpath` where home and showsell were folders I could not see on the server). So I only used what was after that + `/path/to/my/file.csv` (replacing with correct dir). No success there. – Aaron Ko Jul 28 '14 at 07:02
  • I also tried with the unknown folder names and no success as well. – Aaron Ko Jul 28 '14 at 07:10
  • `readfile()` is required! This function call sends the file contents to `stdout` (i.e. the HTTP response)! Make sure that "test.zip" exists at the end of the process. Check the return value of `ZipArchive::close()`. If `false`, then you probably do not have write access to the *current* folder. Try writing your Zip file to an absolute location you know you have write access to. – RandomSeed Jul 28 '14 at 14:00
  • @RandomSeed Thank you for the explanation! I checked the return and found that I did not have write access. I made directory on the server with proper permissions and can save a zip on the server with csv inside it. However, when I download it, the zip is still empty. See updated code snippet for error checking and use of mkdir. – Aaron Ko Jul 28 '14 at 16:52
  • The only issue that remains seems not to be related to Zip pr CSV at all. You may want to open a new question for that, after checking existing questions [like this one](http://stackoverflow.com/a/2882523/1446005). I would not recommend editing this current question, as it would drastically change subject. – RandomSeed Jul 29 '14 at 07:45
  • I thought I was going crazy so I researched under the assumption that the code was fine. Which brought me [here](http://stackoverflow.com/a/8041597/1921702). See my answer below as I appear to have solved my issue. – Aaron Ko Jul 29 '14 at 18:24

2 Answers2

0

You need to be explicit with absolute paths when adding to the archive.

$zip->addFile($abs_path, $relative_path); 
Valentin Mercier
  • 5,256
  • 3
  • 26
  • 50
Zombiesplat
  • 943
  • 8
  • 19
  • Thanks! I modified the addFile params but still had the original issue. I submitted my own answer as I seem to have it working now. – Aaron Ko Jul 29 '14 at 20:01
0

Solution: flush headers before calling readfile(). I learned that I do not need flush() but I left it in there anyways. See SO post that helped me include these two statements here

header('Content-type: application/zip');
header('Content-disposition: attachment; filename=test.zip');
ob_clean();   // discard any data in the output buffer (if possible)
flush();      // flush headers (if possible)
readfile('tmp/test.zip');
exit();

I also changed some minor things with the error checking that I thought I would mention below:
I made a directory with certain permissions that will hold the files I want to put into the archive. This is done at the beginning before the csv and zip are created.

$dir = 'tmp/';
if ( !file_exists($dir) ) {
    mkdir ($dir, 0777);
}

Opening the file has changed too. It now involves the new directory I make:

$zip = new ZipArchive;
if($zip->open($dir.'test.zip', ZIPARCHIVE::CREATE) === TRUE ){

    $res = $zip->addFile('tmp/event-report.csv', 'event-report.csv');                           //add the report csv file.
    if ($res){
        echo "Exists ";
    }
    else{
        echo "Does Not Exist ";
        //echo $_SERVER['DOCUMENT_ROOT'];
    }
}

Thanks to everyone that contributed or just viewed this question.

Community
  • 1
  • 1
Aaron Ko
  • 54
  • 7