Clean up Zip Util to be more strict about what is a valid package archive, fixes #8931
parent
37b1e0fffd
commit
942562c382
|
@ -71,37 +71,41 @@ class Zip
|
|||
*/
|
||||
private static function locateFile(\ZipArchive $zip, $filename)
|
||||
{
|
||||
$indexOfShortestMatch = false;
|
||||
$lengthOfShortestMatch = -1;
|
||||
|
||||
for ($i = 0; $i < $zip->numFiles; $i++) {
|
||||
$stat = $zip->statIndex($i);
|
||||
if (strcmp(basename($stat['name']), $filename) === 0) {
|
||||
$directoryName = dirname($stat['name']);
|
||||
if ($directoryName === '.') {
|
||||
//if composer.json is in root directory
|
||||
//it has to be the one to use.
|
||||
return $i;
|
||||
// return root composer.json if it is there and is a file
|
||||
if (false !== ($index = $zip->locateName($filename)) && $zip->getFromIndex($index) !== false) {
|
||||
return $index;
|
||||
}
|
||||
|
||||
if (strpos($directoryName, '\\') !== false ||
|
||||
strpos($directoryName, '/') !== false) {
|
||||
//composer.json files below first directory are rejected
|
||||
$topLevelPaths = array();
|
||||
for ($i = 0; $i < $zip->numFiles; $i++) {
|
||||
$name = $zip->getNameIndex($i);
|
||||
$dirname = dirname($name);
|
||||
|
||||
// handle archives with proper TOC
|
||||
if ($dirname === '.') {
|
||||
$topLevelPaths[$name] = true;
|
||||
if (\count($topLevelPaths) > 1) {
|
||||
// archive can only contain one top level directory
|
||||
return false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
$length = strlen($stat['name']);
|
||||
if ($indexOfShortestMatch === false || $length < $lengthOfShortestMatch) {
|
||||
//Check it's not a directory.
|
||||
$contents = $zip->getFromIndex($i);
|
||||
if ($contents !== false) {
|
||||
$indexOfShortestMatch = $i;
|
||||
$lengthOfShortestMatch = $length;
|
||||
}
|
||||
// handle archives which do not have a TOC record for the directory itself
|
||||
if (false === strpos('\\', $dirname) && false === strpos('/', $dirname)) {
|
||||
$topLevelPaths[$dirname.'/'] = true;
|
||||
if (\count($topLevelPaths) > 1) {
|
||||
// archive can only contain one top level directory
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $indexOfShortestMatch;
|
||||
if ($topLevelPaths && false !== ($index = $zip->locateName(key($topLevelPaths).$filename)) && $zip->getFromIndex($index) !== false) {
|
||||
return $index;
|
||||
}
|
||||
|
||||
// no composer.json found either at the top level or within the topmost directory
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -20,7 +20,7 @@ use Composer\Test\TestCase;
|
|||
*/
|
||||
class ZipTest extends TestCase
|
||||
{
|
||||
public function testThrowsExceptionIfZipExcentionIsNotLoaded()
|
||||
public function testThrowsExceptionIfZipExtensionIsNotLoaded()
|
||||
{
|
||||
if (extension_loaded('zip')) {
|
||||
$this->markTestSkipped('The PHP zip extension is loaded.');
|
||||
|
@ -74,7 +74,7 @@ class ZipTest extends TestCase
|
|||
return;
|
||||
}
|
||||
|
||||
$result = Zip::getComposerJson(__DIR__.'/Fixtures/Zip/subfolder.zip');
|
||||
$result = Zip::getComposerJson(__DIR__.'/Fixtures/Zip/subfolders.zip');
|
||||
|
||||
$this->assertNull($result);
|
||||
}
|
||||
|
@ -103,7 +103,7 @@ class ZipTest extends TestCase
|
|||
$this->assertEquals("{\n \"name\": \"foo/bar\"\n}\n", $result);
|
||||
}
|
||||
|
||||
public function testReturnsRootComposerJsonAndSkipsSubfolders()
|
||||
public function testMultipleTopLevelDirsIsInvalid()
|
||||
{
|
||||
if (!extension_loaded('zip')) {
|
||||
$this->markTestSkipped('The PHP zip extension is not loaded.');
|
||||
|
@ -112,6 +112,18 @@ class ZipTest extends TestCase
|
|||
|
||||
$result = Zip::getComposerJson(__DIR__.'/Fixtures/Zip/multiple.zip');
|
||||
|
||||
$this->assertNull($result);
|
||||
}
|
||||
|
||||
public function testReturnsComposerJsonFromFirstSubfolder()
|
||||
{
|
||||
if (!extension_loaded('zip')) {
|
||||
$this->markTestSkipped('The PHP zip extension is not loaded.');
|
||||
return;
|
||||
}
|
||||
|
||||
$result = Zip::getComposerJson(__DIR__.'/Fixtures/Zip/single-sub.zip');
|
||||
|
||||
$this->assertEquals("{\n \"name\": \"foo/bar\"\n}\n", $result);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue