|
php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login |
[2018-11-28 16:21 UTC] nystrom dot lars dot egon at gmail dot com
Description: ------------ This is closely related to bug #69477, but I'm experiencing a different behavior. When you have a zip archive that contains a directory with a name that ends with . (a dot) ZipArchive errors out with the message: ZipArchive::extractTo(/path/to/extract/to/): failed to open stream: Is a directory Test script: --------------- $extractPath = "/path/to/extract/to"; $zip = new ZipArchive; $zip->open("/path/to/zipfile"); // Next line causes the error if the zip file contains a directory named 'myfolder.' $zip->extractTo($extractPath, ['myfolder.']); PatchesPull RequestsHistoryAllCommentsChangesGit/SVN commits
|
|||||||||||||||||||||||||||||||||||||
Copyright © 2001-2025 The PHP GroupAll rights reserved. |
Last updated: Tue Nov 04 21:00:01 2025 UTC |
I get this error message if the archive contains an *empty* directory entry with a trailing dot. Test script: <?php $zip = new ZipArchive; $zip->open(__DIR__ . '/77214.zip', ZipArchive::CREATE | ZipArchive::OVERWRITE); $zip->addEmptyDir('foo.'); $zip->close(); $zip->open(__DIR__ . '/77214.zip'); $zip->extractTo(__DIR__ . '/77214'); $zip->close(); The culprit is php_zip_make_relative_path()[1], which mistakenly returns an empty string instead of "foo." [1] <https://github.com/php/php-src/blob/php-7.3.0RC6/ext/zip/php_zip.c#L115-L130>I was experiencing this problem as well and I was able to debug it to what I believe causes the bug. Let us have a simple ZIP archive to reproduce the problem, having a single file with the path dot./sub/file.txt When using ZipArchive::extractTo() to extract this file, the file was actually extracted into sub/file.txt Looking at the function source code at https://github.com/php/php-src/blob/533af1eb14dbeb10c83f291b07da62b70d0df8ae/ext/zip/php_zip.c#L2714 I saw that it calls `php_zip_extract_file()` from the same file to do the job. The function in turn calls `php_zip_make_relative_path()` to clean the file paths and avoid path traversal attack - see https://github.com/php/php-src/blob/533af1eb14dbeb10c83f291b07da62b70d0df8ae/ext/zip/php_zip.c#L146-L150 From the implementation of `php_zip_make_relative_path()` at https://github.com/php/php-src/blob/533af1eb14dbeb10c83f291b07da62b70d0df8ae/ext/zip/php_zip.c#L83-L117 I understood that it iterates through the file path from the end to the start and when it finds a slash character with a dot before it, it trims that whole part and starts from the position after the slash. I believe that is wrong. To avoid traversal attack, it should check for two dots before the slash (like ../something). Also it seems there seems to be off-by-one mistake as the comment there reads "i is the position of ." but I think that i is the position of the slash.