6

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.

1
  • 1
    Each instruction in a PHP script executes till it has completed, and only then does it move on to executing the next instruction Commented Mar 10, 2015 at 11:49

2 Answers 2

8

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

Sign up to request clarification or add additional context in comments.

3 Comments

You could also (mostly, if not entirely) eliminate the concurrency issues by using temporary names. so file_put_contents(tempnam(sys_get_temp_dir(), ''), $url) to download the zip file at $url into a temporary file in the system temp dir. This also means, if you develop on Windez and deploy to *nix, that you shouldn't need to change your code between environments.
@Felype The code works great however how could I return the file/data after successfully unzipping it? The file inside zip is a .xml file and I need to output it.
You can use basic "send file as a download" code like header("Content-Type: application/xml"); header("Content-Length:".filesize($filePath)); header("Content-Disposition: attachment; filename=".$filename); readfile($filePath);
2

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; } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.