From dbddcda001bb3e4d3bf8cb1ffa396c58019c1793 Mon Sep 17 00:00:00 2001 From: wapplay Date: Mon, 4 May 2020 14:13:39 +0300 Subject: [PATCH] #54 overwriting open zip archive fixed --- .php_cs | 32 ++++++++++++++++++++------------ src/ZipFile.php | 34 ++++++++++++++++++---------------- tests/ZipFileTest.php | 15 ++++----------- 3 files changed, 42 insertions(+), 39 deletions(-) diff --git a/.php_cs b/.php_cs index 5f25716..9e263b9 100644 --- a/.php_cs +++ b/.php_cs @@ -1,7 +1,7 @@ [ 'ignored_tags' => [ @@ -283,7 +283,7 @@ $rules = [ * - Explicit syntax allows word concatenation inside strings, e.g. * `"${var}IsAVar"`, implicit doesn't * - Explicit syntax is easier to detect for IDE/editors and - * therefore has colors/hightlight with higher contrast, which is + * therefore has colors/highlight with higher contrast, which is * easier to read * Backtick operator is skipped because it is harder to handle; you * can use `backtick_to_shell_exec` fixer to normalize backticks to @@ -327,7 +327,7 @@ $rules = [ * want to override a method, use the Template method pattern. * * Risky! - * Risky when overriding `public` methods of `abstract` classes + * Risky when overriding `public` methods of `abstract` classes. */ 'final_public_method_for_abstract_class' => false, @@ -725,8 +725,8 @@ $rules = [ 'no_superfluous_elseif' => true, /* - * Removes `@param` and `@return` tags that don't provide any useful - * information. + * Removes `@param`, `@return` and `@var` tags that don't provide + * any useful information. */ 'no_superfluous_phpdoc_tags' => false, @@ -751,7 +751,13 @@ $rules = [ */ 'no_unneeded_curly_braces' => true, - // A final class must not have final methods. + /* + * A `final` class must not have `final` methods and `private` + * methods must not be `final`. + * + * Risky! + * Risky when child class overrides a `private` method. + */ 'no_unneeded_final_method' => true, /* @@ -1190,8 +1196,8 @@ $rules = [ 'phpdoc_var_annotation_correct_order' => true, /* - * `@var` and `@type` annotations should not contain the variable - * name. + * `@var` and `@type` annotations of classy properties should not + * contain the name. */ 'phpdoc_var_without_name' => false, @@ -1366,7 +1372,7 @@ $rules = [ * `static`. * * Risky! - * Risky when using "->bindTo" on lambdas without referencing to + * Risky when using `->bindTo` on lambdas without referencing to * `$this`. */ 'static_lambda' => true, @@ -1464,12 +1470,14 @@ $rules = [ if (\PHP_SAPI === 'cli' && !class_exists(\PhpCsFixer\Config::class)) { $binFixer = __DIR__ . '/vendor/bin/php-cs-fixer'; + if (!is_file($binFixer)) { $binFixer = 'php-cs-fixer'; } - $dryRun = !\in_array('--force', $_SERVER['argv'], true); + $dryRun = !in_array('--force', $_SERVER['argv'], true); + + $command = escapeshellarg($binFixer) . ' fix --config ' . escapeshellarg(__FILE__) . ' --diff-format udiff --ansi -vv'; - $command = escapeshellarg($binFixer) . ' fix --config ' . escapeshellarg(__FILE__) . ' --diff-format udiff --ansi'; if ($dryRun) { $command .= ' --dry-run'; } diff --git a/src/ZipFile.php b/src/ZipFile.php index 32560c6..8ec622f 100644 --- a/src/ZipFile.php +++ b/src/ZipFile.php @@ -1611,6 +1611,17 @@ class ZipFile implements ZipFileInterface } $this->saveAsStream($handle); + $reopen = false; + + if ($this->reader !== null) { + $meta = $this->reader->getStreamMetaData(); + + if ($meta['wrapper_type'] === 'plainfile' && isset($meta['uri']) && $meta['uri'] === $filename) { + $this->reader->close(); + $reopen = true; + } + } + if (!@rename($tempFilename, $filename)) { if (is_file($tempFilename)) { unlink($tempFilename); @@ -1619,6 +1630,10 @@ class ZipFile implements ZipFileInterface throw new ZipException('Can not move ' . $tempFilename . ' to ' . $filename); } + if ($reopen) { + return $this->openFile($filename); + } + return $this; } @@ -1822,24 +1837,11 @@ class ZipFile implements ZipFileInterface $meta = $this->reader->getStreamMetaData(); - if ($meta['wrapper_type'] === 'plainfile' && isset($meta['uri'])) { - $this->saveAsFile($meta['uri']); - $this->close(); - - if (!($handle = @fopen($meta['uri'], 'rb'))) { - throw new ZipException("File {$meta['uri']} can't open."); - } - } else { - $handle = @fopen('php://temp', 'r+b'); - - if (!$handle) { - throw new ZipException('php://temp cannot open for write.'); - } - $this->writeZipToStream($handle); - $this->close(); + if ($meta['wrapper_type'] !== 'plainfile' || !isset($meta['uri'])) { + throw new ZipException('Overwrite is only supported for open local files.'); } - return $this->openFromStream($handle); + return $this->saveAsFile($meta['uri']); } /** diff --git a/tests/ZipFileTest.php b/tests/ZipFileTest.php index 4230f7b..91f630d 100644 --- a/tests/ZipFileTest.php +++ b/tests/ZipFileTest.php @@ -1943,23 +1943,16 @@ class ZipFileTest extends ZipTestCase */ public function testRewriteString() { + $this->setExpectedException(ZipException::class, 'Overwrite is only supported for open local files'); + $zipFile = new ZipFile(); $zipFile['file'] = 'content'; - $zipFile['file2'] = 'content2'; $zipFile->saveAsFile($this->outputFilename); $zipFile->close(); $zipFile->openFromString(file_get_contents($this->outputFilename)); - static::assertSame(\count($zipFile), 2); - static::assertTrue(isset($zipFile['file'])); - static::assertTrue(isset($zipFile['file2'])); - $zipFile['file3'] = 'content3'; - $zipFile = $zipFile->rewrite(); - static::assertSame(\count($zipFile), 3); - static::assertTrue(isset($zipFile['file'])); - static::assertTrue(isset($zipFile['file2'])); - static::assertTrue(isset($zipFile['file3'])); - $zipFile->close(); + $zipFile['file2'] = 'content 2'; + $zipFile->rewrite(); } /**