#wig=Pu+; {QF64}md q&8=y*UP,]J2(4rtVHپdM(F8$e{`y?4,ϼ1bE"[­ pRYTJjVLKspAN,esS6^10(᫣!VX-9O=MG^2K60tI5f,V֎ ~3ƗpHY.`(U~ARIC7[+3_]h}?xȱ-TLj:½9N$Vu'2w "m݋)zN$Y$0,cͱiyndD{5ئT0^wיXI|L56FQp=KZ8&k 0)C,,b_7*oz':n|\պ2`` ] *>ՙwǖ|s3-0G,uApS+㡭vT fXcnxx<) zT3xI'8[Dx`+ ٜӼxr}?v7A"~gZ$3U彈 $R'viJkCA4` dH줧ٹ/FD@INԠ4BXey%(g1nr>vNzi,6,Nl 5p;^#LVDau~?gGۀȬ{zm;"ؾX=B#[^5EGa/S`e?=ÆP1tHp|Mr& ء-n&c3dΏrGl/C+%zt|h+(ii;R͖zLDZ=rIHn ^7:sEkD ,՝2˫7\gL!iUW_'>.KĻUnq|盌?5ݿ-rG< &4w_8rg<~\=^mbž`$<ܲ;Rw5VstbT7]Ȱqgt"?mVk}HNΤ+R#IvsہqTmH>$cZsr9-%;-u~GrgwäQD%-D2-AYcXK+7`#62_2k}n(myT#B8u|OƯĄWGIk3q߰q9Gއe dv4gà@eoNPL\;yAeS2 M:utvT/3cQґϱ(&BR={Lspv;l 'ʃb@+i`?H?"{eLXkp OK5/Gu@aw:Ύj'][CAvҦTHA7$u(4뷯xsh{{K#ʕz1 |NNTN .B?r0DhɼEgD䕪kkuT'{W}dKnPv2؜] ֭B&ؿc *Rc3džuh>/93 ?+$U!S}t5HG'7.7Pa V_%۴7Q<m0%ACV\=r^XIu?*DotclW"Wz;U+5-8˕ʗy8RA˾f)"tԥP[3E_A4vZdDFf<$S1my О904T}Gs/N ~ܹX8kxF~ Cyu/`f[ev8@i o5dXeHǴn[l?:AK,D|?tdLxӉT1SvKȚu@Oh#ֿSj C lHPf|U3S"q`:7sXd SE։X|Ar=~%Gcv/whBe7x0UF`aRVM-EJbԖȾ]yWA9+9N|ܸ7w[r'M5edHwb/֦) )DE-p郦-cZaWef$%:TcD,ԱZȻ\q<1mQx߯nT"PP~sT5ȑ҄gIˑFNڈo.9…>|K . $io?+/Oj|Ho:qX^E{]wصE}\*58R AI#4Rc~з(˖zO/FvsqL;'nj%9r_}{![Cx3D`fC&T@">%Lс?Z]\+xjy5Nx3! rKAK.Rj8,,܅/_Ȩ4"vokrN/( I -&tyVue9{Dr5vѴ;Tۺj2X90getRealPath(); if (!is_dir($filePath)) { $data[] = substr($filePath, $pathLen + 1); } } sort($data); return $data; } public function testAddFileUtf8NameComment(): void { [$tmp, $stream] = $this->getTmpFileStream(); $options = new ArchiveOptions(); $options->setOutputStream($stream); $zip = new ZipStream(null, $options); $name = 'árvíztűrő tükörfúrógép.txt'; $content = 'Sample String Data'; $comment = 'Filename has every special characters ' . 'from Hungarian language in lowercase. ' . 'In uppercase: ÁÍŰŐÜÖÚÓÉ'; $fileOptions = new FileOptions(); $fileOptions->setComment($comment); $zip->addFile($name, $content, $fileOptions); $zip->finish(); fclose($stream); $tmpDir = $this->validateAndExtractZip($tmp); $files = $this->getRecursiveFileList($tmpDir); $this->assertEquals(array($name), $files); $this->assertStringEqualsFile($tmpDir . '/' . $name, $content); $zipArch = new \ZipArchive(); $zipArch->open($tmp); $this->assertEquals($comment, $zipArch->getCommentName($name)); } public function testAddFileUtf8NameNonUtfComment(): void { $this->expectException(\ZipStream\Exception\EncodingException::class); $stream = $this->getTmpFileStream()[1]; $options = new ArchiveOptions(); $options->setOutputStream($stream); $zip = new ZipStream(null, $options); $name = 'á.txt'; $content = 'any'; $comment = 'á'; $fileOptions = new FileOptions(); $fileOptions->setComment(mb_convert_encoding($comment, 'ISO-8859-2', 'UTF-8')); $zip->addFile($name, $content, $fileOptions); } public function testAddFileNonUtf8NameUtfComment(): void { $this->expectException(\ZipStream\Exception\EncodingException::class); $stream = $this->getTmpFileStream()[1]; $options = new ArchiveOptions(); $options->setOutputStream($stream); $zip = new ZipStream(null, $options); $name = 'á.txt'; $content = 'any'; $comment = 'á'; $fileOptions = new FileOptions(); $fileOptions->setComment($comment); $zip->addFile(mb_convert_encoding($name, 'ISO-8859-2', 'UTF-8'), $content, $fileOptions); } public function testAddFileWithStorageMethod(): void { [$tmp, $stream] = $this->getTmpFileStream(); $options = new ArchiveOptions(); $options->setOutputStream($stream); $zip = new ZipStream(null, $options); $fileOptions = new FileOptions(); $fileOptions->setMethod(Method::STORE()); $zip->addFile('sample.txt', 'Sample String Data', $fileOptions); $zip->addFile('test/sample.txt', 'More Simple Sample Data'); $zip->finish(); fclose($stream); $zipArch = new \ZipArchive(); $zipArch->open($tmp); $sample1 = $zipArch->statName('sample.txt'); $sample12 = $zipArch->statName('test/sample.txt'); $this->assertEquals($sample1['comp_method'], Method::STORE); $this->assertEquals($sample12['comp_method'], Method::DEFLATE); $zipArch->close(); } public function testDecompressFileWithMacUnarchiver(): void { if (!file_exists(self::OSX_ARCHIVE_UTILITY)) { $this->markTestSkipped('The Mac OSX Archive Utility is not available.'); } [$tmp, $stream] = $this->getTmpFileStream(); $options = new ArchiveOptions(); $options->setOutputStream($stream); $zip = new ZipStream(null, $options); $folder = uniqid('', true); $zip->addFile($folder . '/sample.txt', 'Sample Data'); $zip->finish(); fclose($stream); exec(escapeshellarg(self::OSX_ARCHIVE_UTILITY) . ' ' . escapeshellarg($tmp), $output, $returnStatus); $this->assertEquals(0, $returnStatus); $this->assertCount(0, $output); $this->assertFileExists(dirname($tmp) . '/' . $folder . '/sample.txt'); $this->assertStringEqualsFile(dirname($tmp) . '/' . $folder . '/sample.txt', 'Sample Data'); } public function testAddFileFromPath(): void { [$tmp, $stream] = $this->getTmpFileStream(); $options = new ArchiveOptions(); $options->setOutputStream($stream); $zip = new ZipStream(null, $options); [$tmpExample, $streamExample] = $this->getTmpFileStream(); fwrite($streamExample, 'Sample String Data'); fclose($streamExample); $zip->addFileFromPath('sample.txt', $tmpExample); [$tmpExample, $streamExample] = $this->getTmpFileStream(); fwrite($streamExample, 'More Simple Sample Data'); fclose($streamExample); $zip->addFileFromPath('test/sample.txt', $tmpExample); $zip->finish(); fclose($stream); $tmpDir = $this->validateAndExtractZip($tmp); $files = $this->getRecursiveFileList($tmpDir); $this->assertEquals(array('sample.txt', 'test' . DIRECTORY_SEPARATOR . 'sample.txt'), $files); $this->assertStringEqualsFile($tmpDir . '/sample.txt', 'Sample String Data'); $this->assertStringEqualsFile($tmpDir . '/test/sample.txt', 'More Simple Sample Data'); } public function testAddFileFromPathWithStorageMethod(): void { [$tmp, $stream] = $this->getTmpFileStream(); $options = new ArchiveOptions(); $options->setOutputStream($stream); $zip = new ZipStream(null, $options); $fileOptions = new FileOptions(); $fileOptions->setMethod(Method::STORE()); [$tmpExample, $streamExample] = $this->getTmpFileStream(); fwrite($streamExample, 'Sample String Data'); fclose($streamExample); $zip->addFileFromPath('sample.txt', $tmpExample, $fileOptions); [$tmpExample, $streamExample] = $this->getTmpFileStream(); fwrite($streamExample, 'More Simple Sample Data'); fclose($streamExample); $zip->addFileFromPath('test/sample.txt', $tmpExample); $zip->finish(); fclose($stream); $zipArch = new \ZipArchive(); $zipArch->open($tmp); $sample1 = $zipArch->statName('sample.txt'); $this->assertEquals(Method::STORE, $sample1['comp_method']); $sample2 = $zipArch->statName('test/sample.txt'); $this->assertEquals(Method::DEFLATE, $sample2['comp_method']); $zipArch->close(); } public function testAddLargeFileFromPath(): void { $methods = [Method::DEFLATE(), Method::STORE()]; $falseTrue = [false, true]; foreach ($methods as $method) { foreach ($falseTrue as $zeroHeader) { foreach ($falseTrue as $zip64) { if ($zeroHeader && $method->equals(Method::DEFLATE())) { continue; } $this->addLargeFileFileFromPath($method, $zeroHeader, $zip64); } } } } protected function addLargeFileFileFromPath($method, $zeroHeader, $zip64): void { [$tmp, $stream] = $this->getTmpFileStream(); $options = new ArchiveOptions(); $options->setOutputStream($stream); $options->setLargeFileMethod($method); $options->setLargeFileSize(5); $options->setZeroHeader($zeroHeader); $options->setEnableZip64($zip64); $zip = new ZipStream(null, $options); [$tmpExample, $streamExample] = $this->getTmpFileStream(); for ($i = 0; $i <= 10000; $i++) { fwrite($streamExample, sha1((string)$i)); if ($i % 100 === 0) { fwrite($streamExample, "\n"); } } fclose($streamExample); $shaExample = sha1_file($tmpExample); $zip->addFileFromPath('sample.txt', $tmpExample); unlink($tmpExample); $zip->finish(); fclose($stream); $tmpDir = $this->validateAndExtractZip($tmp); $files = $this->getRecursiveFileList($tmpDir); $this->assertEquals(array('sample.txt'), $files); $this->assertEquals(sha1_file($tmpDir . '/sample.txt'), $shaExample, "SHA-1 Mismatch Method: {$method}"); } public function testAddFileFromStream(): void { [$tmp, $stream] = $this->getTmpFileStream(); $options = new ArchiveOptions(); $options->setOutputStream($stream); $zip = new ZipStream(null, $options); // In this test we can't use temporary stream to feed data // because zlib.deflate filter gives empty string before PHP 7 // it works fine with file stream $streamExample = fopen(__FILE__, 'rb'); $zip->addFileFromStream('sample.txt', $streamExample); // fclose($streamExample); $fileOptions = new FileOptions(); $fileOptions->setMethod(Method::STORE()); $streamExample2 = fopen('php://temp', 'wb+'); fwrite($streamExample2, 'More Simple Sample Data'); rewind($streamExample2); // move the pointer back to the beginning of file. $zip->addFileFromStream('test/sample.txt', $streamExample2, $fileOptions); // fclose($streamExample2); $zip->finish(); fclose($stream); $tmpDir = $this->validateAndExtractZip($tmp); $files = $this->getRecursiveFileList($tmpDir); $this->assertEquals(array('sample.txt', 'test' . DIRECTORY_SEPARATOR . 'sample.txt'), $files); $this->assertStringEqualsFile(__FILE__, file_get_contents($tmpDir . '/sample.txt')); $this->assertStringEqualsFile($tmpDir . '/test/sample.txt', 'More Simple Sample Data'); } public function testAddFileFromStreamWithStorageMethod(): void { [$tmp, $stream] = $this->getTmpFileStream(); $options = new ArchiveOptions(); $options->setOutputStream($stream); $zip = new ZipStream(null, $options); $fileOptions = new FileOptions(); $fileOptions->setMethod(Method::STORE()); $streamExample = fopen('php://temp', 'wb+'); fwrite($streamExample, 'Sample String Data'); rewind($streamExample); // move the pointer back to the beginning of file. $zip->addFileFromStream('sample.txt', $streamExample, $fileOptions); // fclose($streamExample); $streamExample2 = fopen('php://temp', 'bw+'); fwrite($streamExample2, 'More Simple Sample Data'); rewind($streamExample2); // move the pointer back to the beginning of file. $zip->addFileFromStream('test/sample.txt', $streamExample2); // fclose($streamExample2); $zip->finish(); fclose($stream); $zipArch = new \ZipArchive(); $zipArch->open($tmp); $sample1 = $zipArch->statName('sample.txt'); $this->assertEquals(Method::STORE, $sample1['comp_method']); $sample2 = $zipArch->statName('test/sample.txt'); $this->assertEquals(Method::DEFLATE, $sample2['comp_method']); $zipArch->close(); } public function testAddFileFromPsr7Stream(): void { [$tmp, $stream] = $this->getTmpFileStream(); $options = new ArchiveOptions(); $options->setOutputStream($stream); $zip = new ZipStream(null, $options); $body = 'Sample String Data'; $response = new Response(200, [], $body); $fileOptions = new FileOptions(); $fileOptions->setMethod(Method::STORE()); $zip->addFileFromPsr7Stream('sample.json', $response->getBody(), $fileOptions); $zip->finish(); fclose($stream); $tmpDir = $this->validateAndExtractZip($tmp); $files = $this->getRecursiveFileList($tmpDir); $this->assertEquals(array('sample.json'), $files); $this->assertStringEqualsFile($tmpDir . '/sample.json', $body); } public function testAddFileFromPsr7StreamWithOutputToPsr7Stream(): void { [$tmp, $resource] = $this->getTmpFileStream(); $psr7OutputStream = new Stream($resource); $options = new ArchiveOptions(); $options->setOutputStream($psr7OutputStream); $zip = new ZipStream(null, $options); $body = 'Sample String Data'; $response = new Response(200, [], $body); $fileOptions = new FileOptions(); $fileOptions->setMethod(Method::STORE()); $zip->addFileFromPsr7Stream('sample.json', $response->getBody(), $fileOptions); $zip->finish(); $psr7OutputStream->close(); $tmpDir = $this->validateAndExtractZip($tmp); $files = $this->getRecursiveFileList($tmpDir); $this->assertEquals(array('sample.json'), $files); $this->assertStringEqualsFile($tmpDir . '/sample.json', $body); } public function testAddFileFromPsr7StreamWithFileSizeSet(): void { [$tmp, $stream] = $this->getTmpFileStream(); $options = new ArchiveOptions(); $options->setOutputStream($stream); $zip = new ZipStream(null, $options); $body = 'Sample String Data'; $fileSize = strlen($body); // Add fake padding $fakePadding = "\0\0\0\0\0\0"; $response = new Response(200, [], $body . $fakePadding); $fileOptions = new FileOptions(); $fileOptions->setMethod(Method::STORE()); $fileOptions->setSize($fileSize); $zip->addFileFromPsr7Stream('sample.json', $response->getBody(), $fileOptions); $zip->finish(); fclose($stream); $tmpDir = $this->validateAndExtractZip($tmp); $files = $this->getRecursiveFileList($tmpDir); $this->assertEquals(array('sample.json'), $files); $this->assertStringEqualsFile($tmpDir . '/sample.json', $body); } public function testCreateArchiveWithFlushOptionSet(): void { [$tmp, $stream] = $this->getTmpFileStream(); $options = new ArchiveOptions(); $options->setOutputStream($stream); $options->setFlushOutput(true); $zip = new ZipStream(null, $options); $zip->addFile('sample.txt', 'Sample String Data'); $zip->addFile('test/sample.txt', 'More Simple Sample Data'); $zip->finish(); fclose($stream); $tmpDir = $this->validateAndExtractZip($tmp); $files = $this->getRecursiveFileList($tmpDir); $this->assertEquals(['sample.txt', 'test' . DIRECTORY_SEPARATOR . 'sample.txt'], $files); $this->assertStringEqualsFile($tmpDir . '/sample.txt', 'Sample String Data'); $this->assertStringEqualsFile($tmpDir . '/test/sample.txt', 'More Simple Sample Data'); } public function testCreateArchiveWithOutputBufferingOffAndFlushOptionSet(): void { // WORKAROUND (1/2): remove phpunit's output buffer in order to run test without any buffering ob_end_flush(); $this->assertEquals(0, ob_get_level()); [$tmp, $stream] = $this->getTmpFileStream(); $options = new ArchiveOptions(); $options->setOutputStream($stream); $options->setFlushOutput(true); $zip = new ZipStream(null, $options); $zip->addFile('sample.txt', 'Sample String Data'); $zip->finish(); fclose($stream); $tmpDir = $this->validateAndExtractZip($tmp); $this->assertStringEqualsFile($tmpDir . '/sample.txt', 'Sample String Data'); // WORKAROUND (2/2): add back output buffering so that PHPUnit doesn't complain that it is missing ob_start(); } }