php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #80863 ZipArchive::extractTo() ignores references
Submitted: 2021-03-14 13:45 UTC Modified: 2021-05-07 15:54 UTC
From: lars at larsegon dot se Assigned: cmb (profile)
Status: Closed Package: Zip Related
PHP Version: 7.4 OS: Linux
Private report: No CVE-ID: None
View Add Comment Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
You can add a comment by following this link or if you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: lars at larsegon dot se
New email:
PHP Version: OS:

 

 [2021-03-14 13:45 UTC] lars at larsegon dot se
Description:
------------
Two strictly equal arrays are treated differently by ZipArchive::extractTo().

In the attached script I'm creating a zip archive, and then extracting the files in the zip file again.

To extract the files, I'm calling ZipArchive::extractTo(targetPath, files), where files is a hard-coded array of paths to the files in the zip archive.

The script also has a couple of functions, one which turns a list of paths into a tree (list2tree) and one which turns the tree back into a list of paths (tree2list). If output = tree2list(list2tree(input)), output will be strictly equal to input, as can be seen in the asserting if-clause in the script.

Even though output === input, ZipArchive::extractTo(targetPath, output) extracts nothing, and ZipArchive::extractTo(targetPath, input) extracts everything.

Test script:
---------------
<?php

function list2tree(array $paths): array
{
    $tree = [];
    foreach ($paths as $path) {
        $parts = explode("/", $path);
        $node  = &$tree;
        foreach ($parts as $pathSegment) {
            if (empty($pathSegment) && $node !== $tree) {
                continue;
            }

            if (is_string($node)) {
                throw new \RuntimeException("Name collision");
            }

            $node = &$node[$pathSegment];
        }
        $node = '';
    }
    return $tree;
}

function tree2list(array $tree): array
{
    $list = [];
    foreach ($tree as $name => $content) {
        if (is_array($content)) {
            $subList = tree2list($content);
            foreach ($subList as &$node) {
                $node = "$name/$node";
            }
            $list = array_merge($list, $subList);
        } else {
            $list[] = $name;
        }
    }

    return $list;
}

function createArchive()
{
    $archive = tempnam(sys_get_temp_dir(), "phpzip");

    $zip = new ZipArchive;
    $zip->open($archive, ZipArchive::CREATE | ZipArchive::OVERWRITE);
    $zip->addFromString("dir/file.txt", "contents");
    $zip->addFromString("dir/file2.txt", "contents");
    $zip->close();

    return $archive;
}

$files = [
    "dir/file.txt",
    "dir/file2.txt",
];

$archive = createArchive();

// Calling these functions is what corrupts the file list.
$tree    = list2tree($files);
$extract = tree2list($tree);

// But we can assert that $extract and $files are strictly equal
if ($extract !== $files) {
    throw new \LogicException();
}

$target = tempnam(sys_get_temp_dir(), "phpzip");
unlink($target);
mkdir($target);

$e = new ZipArchive;
$e->open($archive);

// Even though $extract and $files are strictly equal,
// the following line extracts nothing:
$e->extractTo($target, $extract);

// But the following line extracts all files (if you uncomment it):
// $e->extractTo($target, $files);

var_dump($extract);

echo `ls -lah "$target"`;


Expected result:
----------------
I expect two strictly equal arrays of zip-entries to extract the same set of files from the zip archive.

Actual result:
--------------
ZipArchive::extractTo() extracts none of the files in the second argument, despite them being a list of files in the archive.

Patches

Add a Patch

Pull Requests

Pull requests:

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2021-05-07 14:13 UTC] cmb@php.net
-Status: Open +Status: Verified -PHP Version: 8.0.3 +PHP Version: 7.4 -Assigned To: +Assigned To: cmb
 [2021-05-07 14:13 UTC] cmb@php.net
That's an issue with references.  Thanks for reporting!
 [2021-05-07 15:54 UTC] cmb@php.net
-Summary: extractTo sometimes does not extract anything +Summary: ZipArchive::extractTo() ignores references
 [2021-05-07 15:55 UTC] cmb@php.net
The following pull request has been associated:

Patch Name: Fix #80863: ZipArchive::extractTo() ignores references
On GitHub:  https://github.com/php/php-src/pull/6959
Patch:      https://github.com/php/php-src/pull/6959.patch
 [2021-05-07 17:23 UTC] git@php.net
Automatic comment on behalf of cmb69
Revision: https://github.com/php/php-src/commit/57918b1a1bd0d74a1224e630bae25644ddb89234
Log: Fix #80863: ZipArchive::extractTo() ignores references
 [2021-05-07 17:23 UTC] git@php.net
-Status: Verified +Status: Closed
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Apr 18 15:01:28 2024 UTC