Ziparchive: Rename files before extracting

Asked

Viewed 609 times

1

Next bunch of you... I have hundreds of files . automatically generated zip. These zip files do not have a "standard" as 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 no correct order within these ZIP’s. What I’m struggling with: extract all XML’s from inside these ZIP’s with unique names, because it is common for each zip to have Zmls with equal names, but with different content. In short, it is a recursive extract ensuring that no file will be overwritten for having the same 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 created extracts all the cute XML files and so on. But then my headache: If I upload several ZIP’s at the same time and by coincidence these ZIP’s have files with the same name, one file will overwrite the other due to the name. This has been my problem and no matter how hard I try, nothing I use seems to work in Zend Framework 2.

Anyway, depending on what it contains within ZIP files, whether folders, other types of files and so on, I just need ALL XML’s and make sure that none of them will be overwritten on account of equal names.

Help please

1 answer

1

Ok... after a lot of digging around and cracking my head, I found a functional "solution" to my case.

I’m answering my own question because I realized that a lot of people have this kind of problem, so here’s if someone else needs it or they come across a similar situation!

I used the function Ziparchive::renameIndex After opening the zip file and later extract it with Ziparchive::extractTo, which accepts parameters and makes it possible to extract specific files. In this way, it is not necessary the "gambiarra" to open zip, copy file contents and write outside, as this makes the process bizarrely slow. Below is the code with comments. Follows 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 added comments to the code to assist... I think there’s no doubt in it.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.