Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP download and extract zip file

Tags:

php

I have the following code that downloads a zip file from an external source and then extracts it:

file_put_contents("my-zip.zip", fopen("http://www.externalsite.com/zipfile.zip", 'r'));

$zip = new ZipArchive;
$res = $zip->open('my-zip.zip');
if ($res === TRUE) {
  $zip->extractTo('/extract-here');
  $zip->close();
  //
} else {
  //
}

This works fine, however my question is, does the unzipping procedure wait until the file_put_contents function is complete? Or will it try and run half way through?

It seems to work fine right now but I'm thinking that if the zip file download is delayed or slow for whatever reason that it may crash why trying to unzip a file that doesn't exist.

If that makes sense.

like image 407
Lee Avatar asked Mar 10 '15 11:03

Lee


2 Answers

file_put_contents can work differently depending on the host machine, but as far as I can tell its format doesn't lock concurrent threads as one should expect (unless strictly specified). Also good to remember PHP behaves differently on windows than it does in linux (and many people, not telling you do, develop in windows to then deploy on a linux server)

You can try something like this to guarantee that the file was successfully downloaded. (And that no concurrent thread same time);

$file = fopen("my-zip.zip", "w+");
if (flock($file, LOCK_EX)) {
    fwrite($file, fopen("http://www.externalsite.com/zipfile.zip", 'r'));
    $zip = new ZipArchive;
    $res = $zip->open('my-zip.zip');
    if ($res === TRUE) {
      $zip->extractTo('/extract-here');
      $zip->close();
      //
    } else {
      //
    }
    flock($file, LOCK_UN);
} else {
    // die("Couldn't download the zip file.");
}
fclose($file);

This might also work.

$f = file_put_contents("my-zip.zip", fopen("http://www.externalsite.com/zipfile.zip", 'r'), LOCK_EX);
if(FALSE === $f)
    die("Couldn't write to file.");
$zip = new ZipArchive;
$res = $zip->open('my-zip.zip');
if ($res === TRUE) {
  $zip->extractTo('/extract-here');
  $zip->close();
  //
} else {
  //
}

This will prevent in case you call this page twice and both pages try to access the same file. This is what could happen: Page 1 downloads zip. Page 1 starts extracting zip. Page 2 downloads zip replacing the old one Page 1 will be like: What happened to my zip? O.O

like image 168
Felype Avatar answered Sep 22 '22 12:09

Felype


Try something like this

function downloadUnzipGetContents($url) {
    $data = file_get_contents($url);

    $path = tempnam(sys_get_temp_dir(), 'prefix');

    $temp = fopen($path, 'w');
    fwrite($temp, $data);
    fseek($temp, 0);
    fclose($temp);

    $pathExtracted = tempnam(sys_get_temp_dir(), 'prefix');

    $filenameInsideZip = 'test.csv';
    copy("zip://".$path."#".$filenameInsideZip, $pathExtracted);

    $data = file_get_contents($pathExtracted);

    unlink($path);
    unlink($pathExtracted);

    return $data;
}
like image 39
nacholibre Avatar answered Sep 21 '22 12:09

nacholibre