diff options
-rw-r--r-- | examples/07-stream_writer.php | 30 | ||||
-rw-r--r-- | src/ZipStream.php | 97 |
2 files changed, 125 insertions, 2 deletions
diff --git a/examples/07-stream_writer.php b/examples/07-stream_writer.php new file mode 100644 index 0000000..d94e7ac --- /dev/null +++ b/examples/07-stream_writer.php @@ -0,0 +1,30 @@ +<?php +declare(strict_types = 1); + +require_once __DIR__ . '/../src/ZipStream.php'; + +# import zipstream classes +use Pablotron\ZipStream\ZipStream; +use Pablotron\ZipStream\StreamWriter; + +# save as "example.zip" in examples directory +$zip_path = __DIR__ . '/example.zip'; + +# open output stream +$out_stream = fopen($zip_path, 'wb'); + +# create zipstream +# NOTE: output archive name is ignored for StreamWriter +$zip = new ZipStream('', [ + 'output' => new StreamWriter($out_stream), +]); + +# add a file named "hello.txt" to output archive, containing +# the string "hello world!" +$zip->add_file('hello.txt', 'hello world!'); + +# finalize archive +$zip->close(); + +# close output stream +fclose($out_stream); diff --git a/src/ZipStream.php b/src/ZipStream.php index 2759d4d..b3f41dd 100644 --- a/src/ZipStream.php +++ b/src/ZipStream.php @@ -177,8 +177,6 @@ final class HTTPResponseWriter implements Writer { * @api * * {@example ../examples/06-file_writer.php} - * - * @see Writer */ final class FileWriter implements Writer { /** @var string Output file path. */ @@ -304,6 +302,101 @@ final class FileWriter implements Writer { }; /** + * Write generated zip archive to a stream. + * + * @api + * + * {@example ../examples/07-stream_writer.php} + */ +final class StreamWriter implements Writer { + /** @var resource Output stream. */ + public $stream; + + const STREAM_WRITER_STATE_INIT = 0; + const STREAM_WRITER_STATE_OPEN = 1; + const STREAM_WRITER_STATE_CLOSED = 2; + const STREAM_WRITER_STATE_ERROR = 3; + + /** + * Create a new StreamWriter. + * + * @api + */ + public function __construct($stream) { + # check stream + if (!is_resource($stream)) { + $this->state = self::STREAM_WRITER_STATE_ERROR; + throw new Error('stream is not a resource'); + } + + # set state, cache stream + $this->state = self::STREAM_WRITER_STATE_INIT; + $this->stream = $stream; + } + + public function set(string $key, string $val) : void { + # ignore metadata + } + + public function open() : void { + # set state + $this->state = self::STREAM_WRITER_STATE_OPEN; + } + + /** + * Write archive contents. + * + * @param string $data Archive file data. + * + * @return void + */ + public function write(string $data) : void { + # check state + if ($this->state != self::STREAM_WRITER_STATE_OPEN) { + # set state, raise error + $this->state = self::STREAM_WRITER_STATE_ERROR; + throw new Error("invalid output state"); + } + + # write data + $len = fwrite($this->stream, $data); + + # check for error + if ($len === false) { + # set state, raise error + $this->state = self::STREAM_WRITER_STATE_ERROR; + throw new Error('fwrite() failed'); + } + } + + /** + * Finish writing archive data. + * + * @return void + */ + public function close() : void { + # check state + if ($this->state == self::STREAM_WRITER_STATE_CLOSED) { + return; + } else if ($this->state != self::STREAM_WRITER_STATE_OPEN) { + # set state, raise error + $this->state = self::STREAM_WRITER_STATE_ERROR; + throw new Error("invalid output state"); + } + + # flush output + if (!@fflush($this->stream)) { + # set state, raise error + $this->state = self::STREAM_WRITER_STATE_ERROR; + throw new Error("fflush() failed"); + } + + # set state + $this->state = self::STREAM_WRITER_STATE_CLOSED; + } +}; + +/** * Convert a UNIX timestamp into DOS date and time components. * @internal */ |