Coder Social home page Coder Social logo

cubiclesoft / php-zipstreamwriter Goto Github PK

View Code? Open in Web Editor NEW
6.0 3.0 2.0 41 KB

A fast, efficient streaming library for creating ZIP files on the fly in pure userland PHP without any external tools, PHP extensions, or physical disk storage requirements.

PHP 100.00%
streaming-zip zip stream stream-http pkzip

php-zipstreamwriter's Introduction

ZipStreamWriter for PHP

A fast, efficient streaming library for creating ZIP files on the fly in pure userland PHP without any external tools, PHP extensions, or physical disk storage requirements. Follows version 6.3.7 of the PKWARE Zip specification. Choose from a MIT or LGPL license.

Donate Discord

If you use this project, don't forget to donate to support its development!

Features

  • Instantly start streaming a ZIP file from a PHP application to a user.
  • Extremely low memory footprint.
  • No external tools, PHP extensions (zlib is recommended though), or disk storage requirements.
  • Easily add empty directories just like ZipArchive.
  • Add files in their entirety or in chunks.
  • Automatic, intelligent Deflate compression. For whole files, if the uncompressed version is smaller than the compressed version, the uncompressed version is used.
  • Support for NTFS timestamps and UNIX timestamps + uid/gid.
  • Support for UNIX file attributes (e.g. 0644) + MS-DOS attributes.
  • Automatic Zip64 large file support.
  • Built using the PKWARE specification, a nice ZIP artifact library, a hex editor, and sheer guts and determination.
  • And much more.

Getting Started

Download/clone this repo, put the 'support' directory on a server, and then do something like this from PHP:

<?php
	require_once "support/zip_stream_writer.php";

	// Adjust various PHP settings and output relevant HTTP headers to trigger a download.
	ZipStreamWriter::StartHTTPResponse("test.zip");

	$zip = new ZipStreamWriter();
	$zip->Init();

	$lastmodified  = mktime(9, 41, 20, 12, 10, 2018);
	$lastaccessed = $lastmodified + 60;
	$created = $lastmodified - 24 * 60 * 60;

	// Register some empty directories.
	$zip->AddDirectory("dir/", array("last_modified" => $lastmodified));
	$zip->AddDirectory("dir/dir2/", array("last_modified" => $lastmodified));


	// Add smaller files with a simple call.
	$zip->AddFileFromString("dir/ Hello.txt", "Hello there!", array("last_modified" => $lastmodified));

	// Keep RAM usage low by streaming data.  Just call Read() whenever to clear out the internal buffer.
	echo $zip->Read();


	// Completely customize options per file.
	// Some combinations can break some ZIP readers though (see documentation).
	$options = array(
		"last_modified" => $lastmodified,
		"64bit" => true,
		"unix_attrs" => 0644,
		"extra_fields" => array(),
		"comment" => "Best file ever."
	);

	// NTFS timestamps.
	ZipStreamWriter::AppendNTFSExtraField($options["extra_fields"], $lastmodified, $lastaccessed, $created);

	// UNIX timestamps + uid/gid.
	$uid = 1234;
	$gid = 1234;

	ZipStreamWriter::AppendUNIXExtraField($options["extra_fields"], $lastaccessed, $lastmodified, $uid, $gid);


	// Generate and compress larger files in chunks.
	$zip->OpenFile("dir/Hello2.txt", $options);

	$zip->AppendFileData("Hello ");
	if ($zip->BytesAvailable() > 65536)  echo $zip->Read();

	$zip->AppendFileData("there!");
	echo $zip->Read();

	$zip->CloseFile();
	echo $zip->Read();

	// Finalize and close the ZIP file.  Adding a comment is optional.
	$zip->Finalize("Woot!");

	// The last Read() call is required.  The rest are optional.
	echo $zip->Read();

See the ZipStreamWriter::InitCentralDirHeader() documentation for a complete list of options.

Documentation

Limitations

The following limitations are ordered from most important to least:

  • Some tools that read ZIP files don't support Zip64 or streaming Zip64 extra fields. Any files of a declared unknown uncompressed size (uncompressed_size = -1) or specified as over 2GB without a 64-bit declaration enables Zip64 for that file.
  • Some tools that read ZIP files don't support Zip64 directory information. The ZipStreamWriter class always creates a Zip64 End of Central Directory record and locator when more than 65,535 directories/files (total) are put into a single ZIP file.
  • No encryption support, including password protection. Some parts of the specification allude to proprietary, patented technology by PKWARE, Inc.
  • Only the Store (0x0000, uncompressed) and Deflate (0x0008) compression methods are both supported and implemented.
  • Deflate compression is only available if zlib stream filter support is compiled into PHP. The class automatically falls back to the Store method if zlib stream filtering is not available or is broken. Support for Deflate compression can be verified by calling ZipStreamWriter::IsDeflateSupported().
  • Incomplete disk spanning support. The ZIP file format has the ability to span multiple disks. Even though the ZipStreamWriter class has some code that implies support for disk spanning, the implementation is incomplete and not actually usable. Not that this fact will actually matter for most people.
  • Incomplete exotic "extra fields" support. Only the most critical Zip64, NTFS, and UNIX extra fields are fully implemented. The OS/2 extra field type is also implemented - because it was easy and well-documented, not because it is actually useful. EXTRA_FIELD_WIN_NT_ACL (0x4453) support is distinctly missing. Other extra fields can be added as binary strings.
  • Limited symlink support may or may not work. The ZIP file format was originally designed for MS-DOS and FAT16. UNIX extra fields kind of support symbolic links but it's a tossup as to whether or not a reader will extract them correctly or just dump out a zero byte file to disk. NTFS supports reparse points (aka symlinks and hard links), but it is up to a ZIP file reader to create reparse points and I don't know of any that do. Symlink support is one of the major areas of the ZIP file specification that could use improvement.
  • Alternate data stream support is non-existent in the ZIP file specification even though it hints at "future support" and is therefore also not supported here.

php-zipstreamwriter's People

Stargazers

 avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

Forkers

mifort

php-zipstreamwriter's Issues

Enhancements...

  • ability to store a filename different from source (from OpenFile)

  • ability to return the headers instead of using header() function ; with psr objects, you have to use $response->withHeader() function.

Central and local directory mismatch for file?

Steps to reproduce
Try to example code in "Getting Started" to create an archive with one files add in chunks

require_once "support/zip_stream_writer.php";

ZipStreamWriter::StartHTTPResponse("test.zip");

$zip = new ZipStreamWriter();
$zip->Init();

$lastmodified  = mktime(0,1,0);
$lastaccessed = $lastmodified + 60;
$created = $lastmodified - 24 * 60 * 60;

$options = array(
    "last_modified" => $lastmodified,
    "64bit" => true,
    "unix_attrs" => 0644,
    "extra_fields" => array(),
    "comment" => "Best file ever."
);

ZipStreamWriter::AppendNTFSExtraField($options["extra_fields"], $lastmodified, $lastaccessed, $created);

$uid = 1234;
$gid = 1234;
ZipStreamWriter::AppendUNIXExtraField($options["extra_fields"], $lastaccessed, $lastmodified, $uid, $gid);

$zip->OpenFile("Hello2.txt", $options, 0);
$zip->AppendFileData("Hello ");
if ($zip->BytesAvailable() > 65536)  echo $zip->Read();
$zip->AppendFileData("there!");
echo $zip->Read();
$zip->CloseFile();
echo $zip->Read();

$zip->Finalize();
echo $zip->Read();

And running WinZip to try opening it.

Actual behavior
If you try to open it in WinZip, apparently the ZIP file header is readable, but extracting at least some files fails like this:
Capture d’écran 2023-02-27 à 16 18 09

I am looking for advice on how to track down this problem. I try to generate the archive with and without 64bit with same result.
This problem doesn't exist with AddFileFromString method.

Version of ZipStreamWriter for PHP
master

Thanks for your help looking into this.

Jann

New header...

I have seen reference to setting the header:
X-Accel-Buffering: no
when streaming files back through nginx. Is this something you may add to your library.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.