ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
ZipStreamTest.php
Go to the documentation of this file.
1<?php
2declare(strict_types=1);
3
4namespace ZipStreamTest;
5
6use org\bovigo\vfs\vfsStream;
8use PHPUnit\Framework\TestCase;
10use ZipStream\Option\Archive as ArchiveOptions;
11use ZipStream\Option\File as FileOptions;
14
18class ZipStreamTest extends TestCase
19{
20 const OSX_ARCHIVE_UTILITY =
21 '/System/Library/CoreServices/Applications/Archive Utility.app/Contents/MacOS/Archive Utility';
22
23 public function testFileNotFoundException(): void
24 {
25 $this->expectException(\ZipStream\Exception\FileNotFoundException::class);
26 // Get ZipStream Object
27 $zip = new ZipStream();
28
29 // Trigger error by adding a file which doesn't exist
30 $zip->addFileFromPath('foobar.php', '/foo/bar/foobar.php');
31 }
32
33 public function testFileNotReadableException(): void
34 {
35 // create new virtual filesystem
36 $root = vfsStream::setup('vfs');
37 // create a virtual file with no permissions
38 $file = vfsStream::newFile('foo.txt', 0000)->at($root)->setContent('bar');
39 $zip = new ZipStream();
40 $this->expectException(\ZipStream\Exception\FileNotReadableException::class);
41 $zip->addFileFromPath('foo.txt', $file->url());
42 }
43
44 public function testDostime(): void
45 {
46 // Allows testing of protected method
47 $class = new \ReflectionClass(File::class);
48 $method = $class->getMethod('dostime');
49 $method->setAccessible(true);
50
51 $this->assertSame($method->invoke(null, 1416246368), 1165069764);
52
53 // January 1 1980 - DOS Epoch.
54 $this->assertSame($method->invoke(null, 315532800), 2162688);
55
56 // January 1 1970 -> January 1 1980 due to minimum DOS Epoch. @todo Throw Exception?
57 $this->assertSame($method->invoke(null, 0), 2162688);
58 }
59
60 public function testAddFile(): void
61 {
62 [$tmp, $stream] = $this->getTmpFileStream();
63
64 $options = new ArchiveOptions();
65 $options->setOutputStream($stream);
66
67 $zip = new ZipStream(null, $options);
68
69 $zip->addFile('sample.txt', 'Sample String Data');
70 $zip->addFile('test/sample.txt', 'More Simple Sample Data');
71
72 $zip->finish();
73 fclose($stream);
74
75 $tmpDir = $this->validateAndExtractZip($tmp);
76
77 $files = $this->getRecursiveFileList($tmpDir);
78 $this->assertEquals(['sample.txt', 'test/sample.txt'], $files);
79
80 $this->assertStringEqualsFile($tmpDir . '/sample.txt', 'Sample String Data');
81 $this->assertStringEqualsFile($tmpDir . '/test/sample.txt', 'More Simple Sample Data');
82 }
83
87 protected function getTmpFileStream(): array
88 {
89 $tmp = tempnam(sys_get_temp_dir(), 'zipstreamtest');
90 $stream = fopen($tmp, 'wb+');
91
92 return array($tmp, $stream);
93 }
94
99 protected function validateAndExtractZip($tmp): string
100 {
101 $tmpDir = $this->getTmpDir();
102
103 $zipArch = new \ZipArchive;
104 $res = $zipArch->open($tmp);
105
106 if ($res !== true) {
107 $this->fail("Failed to open {$tmp}. Code: $res");
108
109 return $tmpDir;
110 }
111
112 $this->assertEquals(0, $zipArch->status);
113 $this->assertEquals(0, $zipArch->statusSys);
114
115 $zipArch->extractTo($tmpDir);
116 $zipArch->close();
117
118 return $tmpDir;
119 }
120
121 protected function getTmpDir(): string
122 {
123 $tmp = tempnam(sys_get_temp_dir(), 'zipstreamtest');
124 unlink($tmp);
125 mkdir($tmp) or $this->fail('Failed to make directory');
126
127 return $tmp;
128 }
129
134 protected function getRecursiveFileList(string $path): array
135 {
136 $data = array();
137 $path = (string)realpath($path);
138 $files = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($path));
139
140 $pathLen = strlen($path);
141 foreach ($files as $file) {
142 $filePath = $file->getRealPath();
143 if (!is_dir($filePath)) {
144 $data[] = substr($filePath, $pathLen + 1);
145 }
146 }
147
148 sort($data);
149
150 return $data;
151 }
152
153 public function testAddFileUtf8NameComment(): void
154 {
155 [$tmp, $stream] = $this->getTmpFileStream();
156
157 $options = new ArchiveOptions();
158 $options->setOutputStream($stream);
159
160 $zip = new ZipStream(null, $options);
161
162 $name = 'árvíztűrő tükörfúrógép.txt';
163 $content = 'Sample String Data';
164 $comment =
165 'Filename has every special characters ' .
166 'from Hungarian language in lowercase. ' .
167 'In uppercase: ÁÍŰŐÜÖÚÓÉ';
168
169 $fileOptions = new FileOptions();
170 $fileOptions->setComment($comment);
171
172 $zip->addFile($name, $content, $fileOptions);
173 $zip->finish();
174 fclose($stream);
175
176 $tmpDir = $this->validateAndExtractZip($tmp);
177
178 $files = $this->getRecursiveFileList($tmpDir);
179 $this->assertEquals(array($name), $files);
180 $this->assertStringEqualsFile($tmpDir . '/' . $name, $content);
181
182 $zipArch = new \ZipArchive();
183 $zipArch->open($tmp);
184 $this->assertEquals($comment, $zipArch->getCommentName($name));
185 }
186
187 public function testAddFileUtf8NameNonUtfComment(): void
188 {
189 $this->expectException(\ZipStream\Exception\EncodingException::class);
190
191 $stream = $this->getTmpFileStream()[1];
192
193 $options = new ArchiveOptions();
194 $options->setOutputStream($stream);
195
196 $zip = new ZipStream(null, $options);
197
198 $name = 'á.txt';
199 $content = 'any';
200 $comment = 'á';
201
202 $fileOptions = new FileOptions();
203 $fileOptions->setComment(mb_convert_encoding($comment, 'ISO-8859-2', 'UTF-8'));
204
205 $zip->addFile($name, $content, $fileOptions);
206 }
207
208 public function testAddFileNonUtf8NameUtfComment(): void
209 {
210 $this->expectException(\ZipStream\Exception\EncodingException::class);
211
212 $stream = $this->getTmpFileStream()[1];
213
214 $options = new ArchiveOptions();
215 $options->setOutputStream($stream);
216
217 $zip = new ZipStream(null, $options);
218
219 $name = 'á.txt';
220 $content = 'any';
221 $comment = 'á';
222
223 $fileOptions = new FileOptions();
224 $fileOptions->setComment($comment);
225
226 $zip->addFile(mb_convert_encoding($name, 'ISO-8859-2', 'UTF-8'), $content, $fileOptions);
227 }
228
229 public function testAddFileWithStorageMethod(): void
230 {
231 [$tmp, $stream] = $this->getTmpFileStream();
232
233 $options = new ArchiveOptions();
234 $options->setOutputStream($stream);
235
236 $zip = new ZipStream(null, $options);
237
238 $fileOptions = new FileOptions();
239 $fileOptions->setMethod(Method::STORE());
240
241 $zip->addFile('sample.txt', 'Sample String Data', $fileOptions);
242 $zip->addFile('test/sample.txt', 'More Simple Sample Data');
243 $zip->finish();
244 fclose($stream);
245
246 $zipArch = new \ZipArchive();
247 $zipArch->open($tmp);
248
249 $sample1 = $zipArch->statName('sample.txt');
250 $sample12 = $zipArch->statName('test/sample.txt');
251 $this->assertEquals($sample1['comp_method'], Method::STORE);
252 $this->assertEquals($sample12['comp_method'], Method::DEFLATE);
253
254 $zipArch->close();
255 }
256
258 {
259 if (!file_exists(self::OSX_ARCHIVE_UTILITY)) {
260 $this->markTestSkipped('The Mac OSX Archive Utility is not available.');
261 }
262
263 [$tmp, $stream] = $this->getTmpFileStream();
264
265 $options = new ArchiveOptions();
266 $options->setOutputStream($stream);
267
268 $zip = new ZipStream(null, $options);
269
270 $folder = uniqid('', true);
271
272 $zip->addFile($folder . '/sample.txt', 'Sample Data');
273 $zip->finish();
274 fclose($stream);
275
276 exec(escapeshellarg(self::OSX_ARCHIVE_UTILITY) . ' ' . escapeshellarg($tmp), $output, $returnStatus);
277
278 $this->assertEquals(0, $returnStatus);
279 $this->assertCount(0, $output);
280
281 $this->assertFileExists(dirname($tmp) . '/' . $folder . '/sample.txt');
282 $this->assertStringEqualsFile(dirname($tmp) . '/' . $folder . '/sample.txt', 'Sample Data');
283 }
284
285 public function testAddFileFromPath(): void
286 {
287 [$tmp, $stream] = $this->getTmpFileStream();
288
289 $options = new ArchiveOptions();
290 $options->setOutputStream($stream);
291
292 $zip = new ZipStream(null, $options);
293
294 [$tmpExample, $streamExample] = $this->getTmpFileStream();
295 fwrite($streamExample, 'Sample String Data');
296 fclose($streamExample);
297 $zip->addFileFromPath('sample.txt', $tmpExample);
298
299 [$tmpExample, $streamExample] = $this->getTmpFileStream();
300 fwrite($streamExample, 'More Simple Sample Data');
301 fclose($streamExample);
302 $zip->addFileFromPath('test/sample.txt', $tmpExample);
303
304 $zip->finish();
305 fclose($stream);
306
307 $tmpDir = $this->validateAndExtractZip($tmp);
308
309 $files = $this->getRecursiveFileList($tmpDir);
310 $this->assertEquals(array('sample.txt', 'test/sample.txt'), $files);
311
312 $this->assertStringEqualsFile($tmpDir . '/sample.txt', 'Sample String Data');
313 $this->assertStringEqualsFile($tmpDir . '/test/sample.txt', 'More Simple Sample Data');
314 }
315
317 {
318 [$tmp, $stream] = $this->getTmpFileStream();
319
320 $options = new ArchiveOptions();
321 $options->setOutputStream($stream);
322
323 $zip = new ZipStream(null, $options);
324
325 $fileOptions = new FileOptions();
326 $fileOptions->setMethod(Method::STORE());
327
328 [$tmpExample, $streamExample] = $this->getTmpFileStream();
329 fwrite($streamExample, 'Sample String Data');
330 fclose($streamExample);
331 $zip->addFileFromPath('sample.txt', $tmpExample, $fileOptions);
332
333 [$tmpExample, $streamExample] = $this->getTmpFileStream();
334 fwrite($streamExample, 'More Simple Sample Data');
335 fclose($streamExample);
336 $zip->addFileFromPath('test/sample.txt', $tmpExample);
337
338 $zip->finish();
339 fclose($stream);
340
341 $zipArch = new \ZipArchive();
342 $zipArch->open($tmp);
343
344 $sample1 = $zipArch->statName('sample.txt');
345 $this->assertEquals(Method::STORE, $sample1['comp_method']);
346
347 $sample2 = $zipArch->statName('test/sample.txt');
348 $this->assertEquals(Method::DEFLATE, $sample2['comp_method']);
349
350 $zipArch->close();
351 }
352
353 public function testAddLargeFileFromPath(): void
354 {
355 $methods = [Method::DEFLATE(), Method::STORE()];
356 $falseTrue = [false, true];
357 foreach ($methods as $method) {
358 foreach ($falseTrue as $zeroHeader) {
359 foreach ($falseTrue as $zip64) {
360 if ($zeroHeader && $method->equals(Method::DEFLATE())) {
361 continue;
362 }
363 $this->addLargeFileFileFromPath($method, $zeroHeader, $zip64);
364 }
365 }
366 }
367 }
368
369 protected function addLargeFileFileFromPath($method, $zeroHeader, $zip64): void
370 {
371 [$tmp, $stream] = $this->getTmpFileStream();
372
373 $options = new ArchiveOptions();
374 $options->setOutputStream($stream);
375 $options->setLargeFileMethod($method);
376 $options->setLargeFileSize(5);
377 $options->setZeroHeader($zeroHeader);
378 $options->setEnableZip64($zip64);
379
380 $zip = new ZipStream(null, $options);
381
382 [$tmpExample, $streamExample] = $this->getTmpFileStream();
383 for ($i = 0; $i <= 10000; $i++) {
384 fwrite($streamExample, sha1((string)$i));
385 if ($i % 100 === 0) {
386 fwrite($streamExample, "\n");
387 }
388 }
389 fclose($streamExample);
390 $shaExample = sha1_file($tmpExample);
391 $zip->addFileFromPath('sample.txt', $tmpExample);
392 unlink($tmpExample);
393
394 $zip->finish();
395 fclose($stream);
396
397 $tmpDir = $this->validateAndExtractZip($tmp);
398
399 $files = $this->getRecursiveFileList($tmpDir);
400 $this->assertEquals(array('sample.txt'), $files);
401
402 $this->assertEquals(sha1_file($tmpDir . '/sample.txt'), $shaExample, "SHA-1 Mismatch Method: {$method}");
403 }
404
405 public function testAddFileFromStream(): void
406 {
407 [$tmp, $stream] = $this->getTmpFileStream();
408
409 $options = new ArchiveOptions();
410 $options->setOutputStream($stream);
411
412 $zip = new ZipStream(null, $options);
413
414 // In this test we can't use temporary stream to feed data
415 // because zlib.deflate filter gives empty string before PHP 7
416 // it works fine with file stream
417 $streamExample = fopen(__FILE__, 'rb');
418 $zip->addFileFromStream('sample.txt', $streamExample);
419// fclose($streamExample);
420
421 $fileOptions = new FileOptions();
422 $fileOptions->setMethod(Method::STORE());
423
424 $streamExample2 = fopen('php://temp', 'wb+');
425 fwrite($streamExample2, 'More Simple Sample Data');
426 rewind($streamExample2); // move the pointer back to the beginning of file.
427 $zip->addFileFromStream('test/sample.txt', $streamExample2, $fileOptions);
428// fclose($streamExample2);
429
430 $zip->finish();
431 fclose($stream);
432
433 $tmpDir = $this->validateAndExtractZip($tmp);
434
435 $files = $this->getRecursiveFileList($tmpDir);
436 $this->assertEquals(array('sample.txt', 'test/sample.txt'), $files);
437
438 $this->assertStringEqualsFile(__FILE__, file_get_contents($tmpDir . '/sample.txt'));
439 $this->assertStringEqualsFile($tmpDir . '/test/sample.txt', 'More Simple Sample Data');
440 }
441
443 {
444 [$tmp, $stream] = $this->getTmpFileStream();
445
446 $options = new ArchiveOptions();
447 $options->setOutputStream($stream);
448
449 $zip = new ZipStream(null, $options);
450
451 $fileOptions = new FileOptions();
452 $fileOptions->setMethod(Method::STORE());
453
454 $streamExample = fopen('php://temp', 'wb+');
455 fwrite($streamExample, 'Sample String Data');
456 rewind($streamExample); // move the pointer back to the beginning of file.
457 $zip->addFileFromStream('sample.txt', $streamExample, $fileOptions);
458// fclose($streamExample);
459
460 $streamExample2 = fopen('php://temp', 'bw+');
461 fwrite($streamExample2, 'More Simple Sample Data');
462 rewind($streamExample2); // move the pointer back to the beginning of file.
463 $zip->addFileFromStream('test/sample.txt', $streamExample2);
464// fclose($streamExample2);
465
466 $zip->finish();
467 fclose($stream);
468
469 $zipArch = new \ZipArchive();
470 $zipArch->open($tmp);
471
472 $sample1 = $zipArch->statName('sample.txt');
473 $this->assertEquals(Method::STORE, $sample1['comp_method']);
474
475 $sample2 = $zipArch->statName('test/sample.txt');
476 $this->assertEquals(Method::DEFLATE, $sample2['comp_method']);
477
478 $zipArch->close();
479 }
480
481 public function testAddFileFromPsr7Stream(): void
482 {
483 [$tmp, $stream] = $this->getTmpFileStream();
484
485 $options = new ArchiveOptions();
486 $options->setOutputStream($stream);
487
488 $zip = new ZipStream(null, $options);
489
490 $body = 'Sample String Data';
491 $response = new Response(200, [], $body);
492
493 $fileOptions = new FileOptions();
494 $fileOptions->setMethod(Method::STORE());
495
496 $zip->addFileFromPsr7Stream('sample.json', $response->getBody(), $fileOptions);
497 $zip->finish();
498 fclose($stream);
499
500 $tmpDir = $this->validateAndExtractZip($tmp);
501
502 $files = $this->getRecursiveFileList($tmpDir);
503 $this->assertEquals(array('sample.json'), $files);
504 $this->assertStringEqualsFile($tmpDir . '/sample.json', $body);
505 }
506
508 {
509 [$tmp, $stream] = $this->getTmpFileStream();
510
511 $options = new ArchiveOptions();
512 $options->setOutputStream($stream);
513
514 $zip = new ZipStream(null, $options);
515
516 $body = 'Sample String Data';
517 $fileSize = strlen($body);
518 // Add fake padding
519 $fakePadding = "\0\0\0\0\0\0";
520 $response = new Response(200, [], $body . $fakePadding);
521
522 $fileOptions = new FileOptions();
523 $fileOptions->setMethod(Method::STORE());
524 $fileOptions->setSize($fileSize);
525 $zip->addFileFromPsr7Stream('sample.json', $response->getBody(), $fileOptions);
526 $zip->finish();
527 fclose($stream);
528
529 $tmpDir = $this->validateAndExtractZip($tmp);
530
531 $files = $this->getRecursiveFileList($tmpDir);
532 $this->assertEquals(array('sample.json'), $files);
533 $this->assertStringEqualsFile($tmpDir . '/sample.json', $body);
534 }
535
537 {
538 [$tmp, $stream] = $this->getTmpFileStream();
539
540 $options = new ArchiveOptions();
541 $options->setOutputStream($stream);
542 $options->setFlushOutput(true);
543
544 $zip = new ZipStream(null, $options);
545
546 $zip->addFile('sample.txt', 'Sample String Data');
547 $zip->addFile('test/sample.txt', 'More Simple Sample Data');
548
549 $zip->finish();
550 fclose($stream);
551
552 $tmpDir = $this->validateAndExtractZip($tmp);
553
554 $files = $this->getRecursiveFileList($tmpDir);
555 $this->assertEquals(['sample.txt', 'test/sample.txt'], $files);
556
557 $this->assertStringEqualsFile($tmpDir . '/sample.txt', 'Sample String Data');
558 $this->assertStringEqualsFile($tmpDir . '/test/sample.txt', 'More Simple Sample Data');
559 }
560
562 {
563 // WORKAROUND (1/2): remove phpunit's output buffer in order to run test without any buffering
564 ob_end_flush();
565 $this->assertEquals(0, ob_get_level());
566
567 [$tmp, $stream] = $this->getTmpFileStream();
568
569 $options = new ArchiveOptions();
570 $options->setOutputStream($stream);
571 $options->setFlushOutput(true);
572
573 $zip = new ZipStream(null, $options);
574
575 $zip->addFile('sample.txt', 'Sample String Data');
576
577 $zip->finish();
578 fclose($stream);
579
580 $tmpDir = $this->validateAndExtractZip($tmp);
581 $this->assertStringEqualsFile($tmpDir . '/sample.txt', 'Sample String Data');
582
583 // WORKAROUND (2/2): add back output buffering so that PHPUnit doesn't complain that it is missing
584 ob_start();
585 }
586}
$path
Definition: aliased.php:25
$sc Method
$comment
Definition: buildRTE.php:83
An exception for terminatinating execution or to throw for unit testing.
PSR-7 response implementation.
Definition: Response.php:11
testCreateArchiveWithOutputBufferingOffAndFlushOptionSet()
getRecursiveFileList(string $path)
addLargeFileFileFromPath($method, $zeroHeader, $zip64)
$i
Definition: disco.tpl.php:19
$tmpDir
Definition: fileserver.php:15
$files
Definition: metarefresh.php:49
$stream
PHP stream implementation.
Class Version \Option.
Definition: Bigint.php:4
$response
$root
Definition: sabredav.php:45
foreach($_POST as $key=> $value) $res
$data
Definition: bench.php:6