ZipArchive: Rename files before extracting

0

Next Galley ... I have hundreds of automatically generated .zip files. These zips files do not have a "default" because they are generated from several different systems. Therefore, some have only XML files, others have other ZIP's inside with other XML's and even folders, so there is not a correct order inside those ZIP's. What I'm fighting: extract all XML's from within these ZIP's with unique names, since it's common for every zip to have ZMLs with the same names, but with different content. In short, it is a recursive extraction ensuring that no file will be replaced with an equal name.

I created the following code:

public function TrataZip($dir)
{
    $tmpupload = './data/tmpuploads/' . session_id() . '/';
    $files = scandir($dir);
    foreach ($files as $key => $value) {
        $path = realpath($dir . DIRECTORY_SEPARATOR . $value);
        if (!is_dir($path)) {
            $extensao = pathinfo($path);
            if ($extensao['extension'] == 'zip') {
                $zip = new \ZipArchive();
                $zip->open($path);
                $zip->extractTo($dir);
                $zip->close();
                unlink($path);
                return $this->TrataZip($dir);
            } elseif ($extensao['extension'] == 'xml') {
                $stamp = new \DateTime();
                rename($path, $tmpupload . $stamp->format('d-m-Y-H-i-s-') . rand() . "-nfe.xml");
            }
        } else if ($value != "." && $value != "..") {
            return $this->TrataZip($path);
        }
    }
    return $this;
}

The code I've created extracts all the cute little XML files and so on. But then my headache: If I upload multiple ZIP's at the same time and coincidentally these ZIP's have files with the same name, one file will overwrite the other because of the name. This has been my problem and as hard as I try, nothing I use seems to work in Zend Framework 2.

Anyway, regardless of what's inside the ZIP files, whether it's folders, other types of files, etc., I just need ALL XML's and make sure none of them are overwritten by equal names.

Help please

    
asked by anonymous 01.06.2016 / 19:23

1 answer

0

Okay ... after a lot of tweaking and breaking my head, I found a functional "solution" for my case.

I am answering the question itself because I realized that a lot of people have this kind of problem, so here it is if someone also needs or faces a similar situation!

I used the Ziparchive :: renameIndex function after opening the zip file and later extracting it with Ziparchive :: extractTo , which accepts parameters and enables extraction of specific files. That way, it is not necessary to "open-zip" gambiarra, copy file content and write from the outside, as this makes the process bizarrely slow. Below is the code with comments. Here is the code:

public function TrataZip($dir)
{
    $files = scandir($dir);
    $stamp = new \DateTime();
    foreach ($files as $key => $value) {
        $path = realpath($dir . DIRECTORY_SEPARATOR . $value);
        if (!is_dir($path)) {
            $extensao = pathinfo($path);
            if ($extensao['extension'] == 'zip') {
                $zip = new \ZipArchive();
                $zip->open($path);
                for ($i = 0; $i < $zip->numFiles; $i++) {
                    $stat = $zip->statIndex($i);
                    $nome = $zip->getNameIndex($i);
                    $nome_xml = explode('.', $nome);
                    /*
                    *Isso aqui é má prática, o ideal é encontrar a extensão do arquivo pelo mime type, mas funciona bem também...
                    *Aqui localizo arquivos com a extensão de meu interesse, no caso, XML...
                    */
                    if (@$nome_xml[1] == "xml") {
                        //Renomeio primeiro, para garantir que nenhum terá nome semelhante e extraio após isso
                        $zip->renameIndex($i,$stamp->format('d-m-Y-H-i-s-') . rand() . "-nfe.xml");
                        $zip->extractTo($dir, array($zip->getNameIndex($i)));
                    }
                    elseif(@$nome_xml[1] == "zip"){
                        //Se for zip, renomeio também e extraio logo em seguida
                        $zip->renameIndex($i,$stamp->format('d-m-Y-H-i-s-') . rand() . "-nfe.zip");
                        $zip->extractTo($dir, array($zip->getNameIndex($i)));
                    }
                }
                $zip->close();
                unlink($path); //Removo o zip antigo...
                //Chamo novamente e própria função em caso de haver outros zips dentro do diretório
                return $this->TrataZip($dir);
            }
            //Se o upload for um arquivo XML e não ZIP, renomeio também
            elseif ($extensao['extension'] == 'xml') {
                $stamp = new \DateTime();
                rename($path, $dir . $stamp->format('d-m-Y-H-i-s-') . rand() . "-nfe.xml");
            }
        } elseif ($value != "." && $value != "..") {
            //Se contiver pastas, repito até não sobrar mais nada...
            return $this->TrataZip($path);
        }
    }
    return $this;
}

I've added comments in the code to help ... I think there's no doubt about it.

    
02.06.2016 / 16:54