/** * Extract the source archive into $this->getPath(). * While extracting, we remove the top folder from the filename inside the archive. * For example, a file 'SugarPro-Full-7.2.1/soap.php' will get extracted to * <install_path>/soap.php . */ public function extract() { $this->getLogger()->info("Extracting {$this->source} into " . $this->getPath() . '...'); if (!is_dir($this->getPath()) || !$this->fs->isEmpty($this->getPath())) { throw new InstallerException("The target path {$this->getPath()} is not a directory or is not empty when extracting the archive."); } if (!is_file($this->source)) { throw new InstallerException("{$this->source} doesn't exists or is not a file."); } $zip = new \ZipArchive(); if ($zip->open($this->source) !== true) { throw new InstallerException("Unable to open zip {$this->source}."); } $zip_paths = array(); for ($i = 0; $i < $zip->numFiles; $i++) { $zip_paths[$i] = $zip->getNameIndex($i); } $target_paths = Installer::junkParent($zip_paths); foreach ($target_paths as $i => $name) { if (empty($name)) { continue; } $target_path = $this->getPath() . '/' . $name; // Check is name ends with '/' (directory name) if (strpos($name, '/', strlen($name) - 1) === false) { // We have a file name // We load each zipped file in memory. // It is much faster than getting the Stream handle. // For Sugar 7 archive we peak at 24MB so it shouldn't be an issue. $content = $zip->getFromIndex($i); if ($content === false) { throw new InstallerException("Error while extracting {$name} from the archive."); } if (file_put_contents($target_path, $content) === false) { throw new InstallerException("Error while writting to file {$target_path}."); } } else { // We have a dir name $this->fs->mkdir($target_path); } } if (!$zip->close()) { throw new InstallerException("Unable to close zip {$this->source}."); } $this->getLogger()->info('Extraction OK.'); }
/** * @dataProvider junkParentProvider */ public function testJunkParent($expected, $path) { $this->assertEquals($expected, Installer::junkParent($path)); }