aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--examples/07-stream_writer.php30
-rw-r--r--src/ZipStream.php97
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
*/