Skip to content

Commit ef00efc

Browse files
committed
Fix ZipArchiveWriter potentially writing central directory more than once
1 parent 0681beb commit ef00efc

File tree

5 files changed

+33
-9
lines changed

5 files changed

+33
-9
lines changed

ChangeLog.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ ZIP File support for the XP Framework ChangeLog
33

44
## ?.?.? / ????-??-??
55

6+
* Fixed `ZipArchiveWriter` potentially appending the ZIP central directory
7+
to the end of the file more than once.
8+
(@thekid)
9+
610
## 11.2.1 / 2025-11-20
711

812
* Fixed issue #4: *Undefined property: [...]ZipFileOutputStream::$data*

src/main/php/io/archive/zip/AbstractZipReaderImpl.class.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,8 @@ public function streamPosition($offset) {
104104

105105
/**
106106
* Closes underlying stream
107+
*
108+
* @return void
107109
*/
108110
public function close() {
109111
$this->stream->close();

src/main/php/io/archive/zip/ZipArchiveReader.class.php

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<?php namespace io\archive\zip;
22

33
use io\streams\{InputStream, Seekable};
4+
use lang\Closeable;
45

56
/**
67
* Read from a zip file
@@ -25,13 +26,13 @@
2526
* }
2627
* ```
2728
*
29+
* @see io.archive.zip.ZipArchive#open
2830
* @test io.archive.zip.unittest.ZipArchiveReaderTest
2931
* @test io.archive.zip.unittest.ZipFileEntriesTest
3032
* @test io.archive.zip.unittest.ZipFileIteratorTest
31-
* @see io.archive.zip.ZipArchive#open
3233
*/
33-
class ZipArchiveReader {
34-
protected $impl= NULL;
34+
class ZipArchiveReader implements Closeable {
35+
protected $impl;
3536

3637
/**
3738
* Creation constructor

src/main/php/io/archive/zip/ZipArchiveWriter.class.php

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
<?php namespace io\archive\zip;
22

33
use io\streams\OutputStream;
4-
use lang\IllegalArgumentException;
4+
use lang\{Closeable, IllegalArgumentException};
55
use util\Date;
66

77
/**
88
* Writes to a ZIP archive
99
*
10-
* @see xp://io.archive.zip.ZipArchive#create
11-
* @test xp://io.archive.zip.unittest.ZipArchiveWriterTest
10+
* @see io.archive.zip.ZipArchive#create
11+
* @test io.archive.zip.unittest.ZipArchiveWriterTest
1212
*/
13-
class ZipArchiveWriter {
13+
class ZipArchiveWriter implements Closeable {
1414
protected
1515
$stream = null,
1616
$dir = [],
@@ -237,13 +237,16 @@ public function writeFile($file, $name, $size, $compressed, $crc32, $flags) {
237237
/**
238238
* Closes this zip archive
239239
*
240+
* @return void
240241
*/
241242
public function close() {
243+
if (null === $this->dir) return;
244+
245+
// Close any open streams
242246
$this->out && $this->out->close();
243247

244-
$comment= '';
245-
246248
// Build central directory
249+
$comment= '';
247250
$l= 0;
248251
foreach ($this->dir as $name => $entry) {
249252
$s= (
@@ -272,6 +275,8 @@ public function close() {
272275
strlen($comment)
273276
));
274277
$this->stream->write($comment);
278+
$this->stream->close();
279+
$this->dir= null;
275280
}
276281

277282
/**

src/test/php/io/archive/zip/unittest/ZipArchiveWriterTest.class.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,4 +131,16 @@ public function transferring_a_file() {
131131

132132
Assert::equals(['test.txt' => 'File contents'], $this->entriesWithContentIn($out));
133133
}
134+
135+
#[Test]
136+
public function central_directory_added_only_once() {
137+
$out= new MemoryOutputStream();
138+
139+
$fixture= new ZipArchiveWriter($out);
140+
$fixture->close();
141+
$size= $out->size();
142+
$fixture->close();
143+
144+
Assert::equals($size, $out->size());
145+
}
134146
}

0 commit comments

Comments
 (0)