mirror of
https://github.com/Ne-Lexa/php-zip.git
synced 2025-08-17 20:52:59 +02:00
Compare commits
11 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
ca068fa78f | ||
|
a84d2f9eff | ||
|
97db60a52d | ||
|
4134ca8daa | ||
|
e7528b2974 | ||
|
19e17fb730 | ||
|
d8f913ac67 | ||
|
1d1c8559cd | ||
|
e1108f9a24 | ||
|
96d269b4ca | ||
|
4aa9711e00 |
6
.gitattributes
vendored
Normal file
6
.gitattributes
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
.gitattributes export-ignore
|
||||
.github export-ignore
|
||||
.gitignore export-ignore
|
||||
.travis.yml export-ignore
|
||||
phpunit.xml export-ignore
|
||||
tests export-ignore
|
@@ -5,7 +5,7 @@ php:
|
||||
- '7.0'
|
||||
- '7.1'
|
||||
- '7.2'
|
||||
- nightly
|
||||
- '7.3'
|
||||
|
||||
# cache vendor dirs
|
||||
cache:
|
||||
@@ -15,7 +15,7 @@ cache:
|
||||
|
||||
install:
|
||||
- travis_retry composer self-update && composer --version
|
||||
- travis_retry composer install --prefer-dist --no-interaction
|
||||
- travis_retry composer install --no-interaction
|
||||
|
||||
before_script:
|
||||
- sudo apt-get install p7zip-full
|
||||
|
@@ -567,7 +567,7 @@ $zipFile->rename($oldName, $newName);
|
||||
```
|
||||
<a name="Documentation-ZipFile-setCompressionLevel"></a> **ZipFile::setCompressionLevel** - set the compression level for all files in the archive.
|
||||
|
||||
> _Note that this method does not apply to entries that were added after this method was run._
|
||||
> _Note that this method does not apply to entries that are added after this method is run._
|
||||
|
||||
By default, the compression level is -1 (`\PhpZip\ZipFile::LEVEL_DEFAULT_COMPRESSION`) or the compression level specified in the archive for Deflate compression.
|
||||
|
||||
@@ -671,7 +671,7 @@ $zipFile->setReadPasswordEntry($entryName, $password);
|
||||
```
|
||||
<a name="Documentation-ZipFile-setPassword"></a> **ZipFile::setPassword** - sets a new password for all files in the archive.
|
||||
|
||||
> _Note that this method does not apply to entries that were added after this method was run._
|
||||
> _Note that this method does not apply to entries that are added after this method is run._
|
||||
```php
|
||||
$zipFile->setPassword($password);
|
||||
```
|
||||
@@ -691,7 +691,7 @@ $zipFile->setPasswordEntry($entryName, $password, $encryptionMethod);
|
||||
```
|
||||
<a name="Documentation-ZipFile-disableEncryption"></a> **ZipFile::disableEncryption** - disable encryption for all entries that are already in the archive.
|
||||
|
||||
> _Note that this method does not apply to entries that were added after this method was run._
|
||||
> _Note that this method does not apply to entries that are added after this method is run._
|
||||
```php
|
||||
$zipFile->disableEncryption();
|
||||
```
|
||||
|
@@ -225,4 +225,23 @@ class FilesUtil
|
||||
}
|
||||
return number_format($size) . " bytes";
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes zip path.
|
||||
*
|
||||
* @param string $path Zip path
|
||||
* @return string
|
||||
*/
|
||||
public static function normalizeZipPath($path)
|
||||
{
|
||||
return implode(
|
||||
'/',
|
||||
array_filter(
|
||||
explode('/', (string)$path),
|
||||
static function ($part) {
|
||||
return $part !== '.' && $part !== '..';
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -297,13 +297,13 @@ class ZipFile implements ZipFileInterface
|
||||
public function extractTo($destination, $entries = null)
|
||||
{
|
||||
if (!file_exists($destination)) {
|
||||
throw new ZipException("Destination " . $destination . " not found");
|
||||
throw new ZipException(sprintf('Destination %s not found', $destination));
|
||||
}
|
||||
if (!is_dir($destination)) {
|
||||
throw new ZipException("Destination is not directory");
|
||||
throw new ZipException('Destination is not directory');
|
||||
}
|
||||
if (!is_writable($destination)) {
|
||||
throw new ZipException("Destination is not writable directory");
|
||||
throw new ZipException('Destination is not writable directory');
|
||||
}
|
||||
|
||||
$zipEntries = $this->zipModel->getEntries();
|
||||
@@ -315,18 +315,19 @@ class ZipFile implements ZipFileInterface
|
||||
if (is_array($entries)) {
|
||||
$entries = array_unique($entries);
|
||||
$flipEntries = array_flip($entries);
|
||||
$zipEntries = array_filter($zipEntries, function (ZipEntry $zipEntry) use ($flipEntries) {
|
||||
$zipEntries = array_filter($zipEntries, static function (ZipEntry $zipEntry) use ($flipEntries) {
|
||||
return isset($flipEntries[$zipEntry->getName()]);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($zipEntries as $entry) {
|
||||
$file = $destination . DIRECTORY_SEPARATOR . $entry->getName();
|
||||
$entryName = FilesUtil::normalizeZipPath($entry->getName());
|
||||
$file = $destination . DIRECTORY_SEPARATOR . $entryName;
|
||||
if ($entry->isDirectory()) {
|
||||
if (!is_dir($file)) {
|
||||
if (!mkdir($file, 0755, true)) {
|
||||
throw new ZipException("Can not create dir " . $file);
|
||||
if (!mkdir($file, 0755, true) && !is_dir($file)) {
|
||||
throw new ZipException('Can not create dir ' . $file);
|
||||
}
|
||||
chmod($file, 0755);
|
||||
touch($file, $entry->getTime());
|
||||
@@ -335,8 +336,8 @@ class ZipFile implements ZipFileInterface
|
||||
}
|
||||
$dir = dirname($file);
|
||||
if (!is_dir($dir)) {
|
||||
if (!mkdir($dir, 0755, true)) {
|
||||
throw new ZipException("Can not create dir " . $dir);
|
||||
if (!mkdir($dir, 0755, true) && !is_dir($dir)) {
|
||||
throw new ZipException('Can not create dir ' . $dir);
|
||||
}
|
||||
chmod($dir, 0755);
|
||||
touch($dir, $entry->getTime());
|
||||
@@ -1210,7 +1211,7 @@ class ZipFile implements ZipFileInterface
|
||||
{
|
||||
$filename = (string)$filename;
|
||||
|
||||
$tempFilename = $filename . '.temp' . uniqid();
|
||||
$tempFilename = $filename . '.temp' . uniqid('', true);
|
||||
if (!($handle = @fopen($tempFilename, 'w+b'))) {
|
||||
throw new InvalidArgumentException("File " . $tempFilename . ' can not open from write.');
|
||||
}
|
||||
@@ -1256,7 +1257,7 @@ class ZipFile implements ZipFileInterface
|
||||
{
|
||||
$outputFilename = (string)$outputFilename;
|
||||
|
||||
if (empty($mimeType) || !is_string($mimeType) && !empty($outputFilename)) {
|
||||
if (empty($mimeType) || (!is_string($mimeType) && !empty($outputFilename))) {
|
||||
$ext = strtolower(pathinfo($outputFilename, PATHINFO_EXTENSION));
|
||||
|
||||
if (!empty($ext) && isset(self::$defaultMimeTypes[$ext])) {
|
||||
@@ -1295,7 +1296,7 @@ class ZipFile implements ZipFileInterface
|
||||
{
|
||||
$outputFilename = (string)$outputFilename;
|
||||
|
||||
if (empty($mimeType) || !is_string($mimeType) && !empty($outputFilename)) {
|
||||
if (empty($mimeType) || (!is_string($mimeType) && !empty($outputFilename))) {
|
||||
$ext = strtolower(pathinfo($outputFilename, PATHINFO_EXTENSION));
|
||||
|
||||
if (!empty($ext) && isset(self::$defaultMimeTypes[$ext])) {
|
||||
|
41
tests/PhpZip/ZipSlipVulnerabilityTest.php
Normal file
41
tests/PhpZip/ZipSlipVulnerabilityTest.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace PhpZip;
|
||||
|
||||
/**
|
||||
* Class ZipSlipVulnerabilityTest
|
||||
*
|
||||
* @package PhpZip
|
||||
* @see https://github.com/Ne-Lexa/php-zip/issues/39 Issue#31
|
||||
* @see https://snyk.io/research/zip-slip-vulnerability Zip Slip Vulnerability
|
||||
*/
|
||||
class ZipSlipVulnerabilityTest extends ZipTestCase
|
||||
{
|
||||
/**
|
||||
* @throws Exception\ZipException
|
||||
*/
|
||||
public function testCreateSlipVulnerabilityFile()
|
||||
{
|
||||
$localFile = '../dir/./../../file.txt';
|
||||
$zipFile = new ZipFile();
|
||||
$zipFile->addFromString($localFile, 'contents');
|
||||
self::assertContains($localFile, $zipFile->getListFiles());
|
||||
$zipFile->close();
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception\ZipException
|
||||
*/
|
||||
public function testUnpack()
|
||||
{
|
||||
$this->assertTrue(mkdir($this->outputDirname, 0755, true));
|
||||
|
||||
$zipFile = new ZipFile();
|
||||
$zipFile->addFromString('../dir/./../../file.txt', 'contents');
|
||||
$zipFile->extractTo($this->outputDirname);
|
||||
$zipFile->close();
|
||||
|
||||
$expectedExtractedFile = $this->outputDirname . '/dir/file.txt';
|
||||
self::assertTrue(is_file($expectedExtractedFile));
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user