7

Fellow coders:

Hate to ask this question, as it was, I belive correctly answered two times:

  1. Here

  2. And here

So the problem is: when unzipping the downloaded 'file.zip', after unzipping, it contains all the folders from the path, even tough I specified the local file in the addFile function. I'd like the zip file not to contain any subfolder, just files.

$zipname = str_replace(' ', '_', $obj['Name']) . '.zip';

$zip = new ZipArchive();

$zip->open($zipname, ZipArchive::CREATE);
foreach ($files as $file) {
    // $file looks like this: webroot/uploadify/files/file.jpg
    $zip->addFile($file, pathinfo($file, PATHINFO_BASENAME));
}

$zip->close();

header('Content-Description: File Transfer');
header('Content-Transfer-Encoding: binary');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header("Content-type: application/zip");
header("Content-Disposition: attachment; filename=" . $zipname);
header("Pragma: no-cache");
header("Expires: 0");
header('Content-Length: ' . filesize($zipname));

readfile($zipname);

Can anyone see what's the problem with this code?

Additional info:

I, ofc, use paths relative to the webroot, but the folder hierarchy in the extracted folder after: extract to file -> 'my_file.zip' is C->xampp->htdocs->my_cakephp_web_app->app->webroot->files which is not exactly what I wanted to achieve :)

PHP 5.4.4

Windows XP, XAMPP

EDIT

Tried using the http://www.phpconcept.net/pclzip/ library and had the same problem. Also on my home PC ( win7 ) this code worked well.

This brings up a question: Are there any settings I should meet that I'm not aware of?

Community
  • 1
  • 1
Igor L.
  • 3,159
  • 7
  • 40
  • 61

4 Answers4

4

I have run your code and it works as expected. So there are 3 things that could be going wrong from what I can see.

Try using these flags in case an old file still exists and it is not being overwritten (it is not clear what $obj['Name'] is set to ) If you read the comments in the php manual, there are varying degrees of success using ZIPARCHIVE::CREATE vs ZIPARCHIVE::OVERWRITE, so perhaps using both will work.

$zip->open( $zipname, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE );

Pathinfo could be failing and returning the whole path or null for some reason

Is it possible to do a var_dump on the pathinfo output, just to confirm it is what you expect it to be?

foreach ( $files as $file )
{
     var_dump(pathinfo( $file, PATHINFO_BASENAME ));

    // $file looks like this: webroot/uploadify/files/file.jpg
    // $zip->addFile( $file, pathinfo( $file, PATHINFO_BASENAME ) );
}

Maybe there is a bug with your os/php version with addFile function (unlikely, grasping at straws here as i can't see any other explanation)

bumperbox
  • 10,166
  • 6
  • 43
  • 66
3

In PHP 5.3 this should do it:

$phar = new PharData('file.zip');

// add all files in the folder, only include files with extensions
$phar->buildFromDirectory('/directory', '~[.][0-9a-z]+$~i');

You could also use PharData::buildFromIterator with the LEAVES_ONLY flag.

Alix Axel
  • 151,645
  • 95
  • 393
  • 500
  • Hi, I tried your code like this: `$phar = new PharData( 'tmp_zips/file.zip' ); $phar->buildFromDirectory( '/uploadify/files/test1', '~[.][0-9a-z]+$~i' );` I got this error: `RecursiveDirectoryIterator::__construct(/uploadify/files/test1,/uploadify/files/test1): The system cannot find the path specified. (code: 3)` – Igor L. Sep 02 '13 at 09:20
  • @IgorLacik: Seems to suggest that you mistyped your path. – Alix Axel Sep 02 '13 at 14:15
2

You need to test each file to see if it's a file (rather than a directory, symlink, etc):

foreach ( $files as $file )
{
    if(filetype($file) == 'file') {
        $zip->addFile( $file, pathinfo( $file, PATHINFO_BASENAME ) );
    }
}

This is using filetype, but you could also use is_file.

Adam Hopkinson
  • 28,281
  • 7
  • 65
  • 99
1

I have absolutely no idea why this is working :)

I'd actually believe, that my PC entered a Skynet mode and got the addFile method to work somehow :)

Anyone who can plausibly explain what happened will get the +50 bonus :)

    $zipname = str_replace( ' ', '_', $obj['Name'] ) . '.zip';

    $zip = new ZipArchive;

    $zip->open( $zipname, ZipArchive::CREATE );

    foreach ( $files as $file )
    {
        // the str_replace made it work???
        $zip->addFile( str_replace( '/webroot', '', getcwd() . '/' . $file ), pathinfo( $file, PATHINFO_BASENAME ) );
    }

    $zip->close();

    header("Content-type: application/zip");
    header("Content-Disposition: attachment; filename=" . $zipname);
    header('Content-Length: ' . filesize( $zipname ));

    readfile( $zipname );

EDIT:

Also, after having some more trouble with temporary files not deleteing themselves, I switched to http://www.phpconcept.net/pclzip/, which works well.

Also, Alix Axel mentioned PharData below, given the amount of score he's earned here, I'm considering his approach as well..

Igor L.
  • 3,159
  • 7
  • 40
  • 61
  • Just curious as to what the value of getcwd() is. It looks like you are translating a relative path to an absolute path. – bumperbox Aug 26 '13 at 17:50
  • This is from the 1st comment on the php manual for $zip->addFile. Beware: calling $zip->addFile() on a file that doesn't exist will succeed and return TRUE, delaying the failure until you make the final $zip->close() call, which will return FALSE and potentially leave you scratching your head. If you're adding multiple files to a zip and your $zip->close() call is returning FALSE, ensure that all the files you added actually exist. It's also a good idea to check each file with file_exists() or is_readable() before calling $zip->addFile() on it. – bumperbox Aug 26 '13 at 17:50
  • getcwd() returns "C:\xampp\htdocs\test_tool\app\webroot". Also read that comment and figured that since the zip archive is being created, it works ( should've printed the $zip->close() out, will know next time when having trouble ). – Igor L. Aug 27 '13 at 07:24