Skip to content

Commit 9dce97b

Browse files
committed
Make Psr7 Stream optional
1 parent e96d38d commit 9dce97b

13 files changed

+309
-339
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ require 'vendor/autoload.php';
4141

4242
// create a new zipstream object
4343
$zip = new ZipStream\ZipStream(
44-
fileName: 'example.zip',
44+
outputName: 'example.zip',
4545

4646
// enable output of HTTP headers
4747
sendHttpHeaders: true,

composer.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
"require": {
2525
"php-64bit": "^8.1",
2626
"ext-mbstring": "*",
27-
"psr/http-message": "^1.0",
2827
"ext-zlib": "*"
2928
},
3029
"require-dev": {
@@ -36,6 +35,10 @@
3635
"friendsofphp/php-cs-fixer": "^3.13",
3736
"vimeo/psalm": "^5.0"
3837
},
38+
"suggest": {
39+
"psr/http-message": "^1.0",
40+
"guzzlehttp/psr7": "^2.4"
41+
},
3942
"scripts": {
4043
"format": "PHP_CS_FIXER_IGNORE_ENV=true php-cs-fixer fix",
4144
"test": "composer run test:unit && composer run test:formatted && composer run test:lint",

guides/Options.rst

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,11 @@ Here is the full list of options available to you. You can also have a look at
1212
1313
$zip = new ZipStream(
1414
// Define output stream
15-
// (argument is eiter a resource or implementing StreamInterface)
15+
// (argument is eiter a resource or implementing
16+
// `Psr\Http\Message\StreamInterface`)
17+
//
18+
// Setup with `psr/http-message` & `guzzlehttp/psr7` dependencies
19+
// required when using `Psr\Http\Message\StreamInterface`.
1620
outputStream: $filePointer,
1721
1822
// Set the deflate level (default is 6; use -1 to disable it)

guides/index.rst

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,20 @@ Installation
2222

2323
Simply add a dependency on ``maennchen/zipstream-php`` to your project's
2424
``composer.json`` file if you use Composer to manage the dependencies of your
25-
project. Use following command to add the package to your project's dependencies:
25+
project. Use following command to add the package to your project's
26+
dependencies:
2627

2728
.. code-block:: sh
2829
composer require maennchen/zipstream-php
2930
31+
If you want to use``addFileFromPsr7Stream```
32+
(``Psr\Http\Message\StreamInterface``) or use a stream instead of a
33+
``resource`` as ``outputStream``, the following dependencies must be installed
34+
as well:
35+
36+
.. code-block:: sh
37+
composer require psr/http-message guzzlehttp/psr7
38+
3039
If ``composer install`` yields the following error, your installation is missing
3140
the `mbstring extension <https://www.php.net/manual/en/book.mbstring.php>`_,
3241
either `install it <https://www.php.net/manual/en/mbstring.installation.php>`_
@@ -54,7 +63,7 @@ Here's a simple example:
5463
5564
// create a new zipstream object
5665
$zip = new ZipStream\ZipStream(
57-
fileName: 'example.zip',
66+
outputName: 'example.zip',
5867
5968
// enable output of HTTP headers
6069
sendHttpHeaders: true,
@@ -83,9 +92,10 @@ Here's a simple example:
8392
fclose($filePointer);
8493
8594
// add a file named 'streamfile.txt' from the body of a `guzzle` response
95+
// Setup with `psr/http-message` & `guzzlehttp/psr7` dependencies required.
8696
$zip->addFileFromPsr7Stream(
87-
fileName: 'streamfile.txt',
88-
stream: $response->getBody(),
97+
fileName: 'streamfile.txt',
98+
stream: $response->getBody(),
8999
);
90100
91101
// finish the zip stream
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace ZipStream\Exception;
6+
7+
use ZipStream\Exception;
8+
9+
/**
10+
* This Exception gets invoked if a resource like `fread` returns false
11+
*/
12+
class ResourceActionException extends Exception
13+
{
14+
/**
15+
* @var ?resource
16+
*/
17+
private $resource;
18+
19+
/**
20+
* @param resource $resource
21+
*/
22+
public function __construct(
23+
private readonly string $function,
24+
$resource = null,
25+
) {
26+
$this->resource = $resource;
27+
parent::__construct('Function ' . $function . 'failed on resource.');
28+
}
29+
}

src/File.php

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77
use Closure;
88
use DateTimeInterface;
99
use DeflateContext;
10-
use Psr\Http\Message\StreamInterface;
1110
use RuntimeException;
1211
use ZipStream\Exception\OverflowException;
12+
use ZipStream\Exception\ResourceActionException;
1313
use ZipStream\Exception\StreamNotReadableException;
1414
use ZipStream\Exception\StreamNotSeekableException;
1515

@@ -34,6 +34,14 @@ class File
3434

3535
private int $totalSize = 0;
3636

37+
/**
38+
* @var resource
39+
*/
40+
private $stream;
41+
42+
/**
43+
* @param resource $stream
44+
*/
3745
public function __construct(
3846
string $fileName,
3947
private int $startOffset,
@@ -45,7 +53,7 @@ public function __construct(
4553
private readonly bool $enableZip64,
4654
private readonly bool $enableZeroHeader,
4755
private readonly Closure $send,
48-
private readonly StreamInterface $stream,
56+
$stream,
4957
) {
5058
$this->fileName = self::filterFilename($fileName);
5159
$this->checkEncoding();
@@ -56,12 +64,19 @@ public function __construct(
5664

5765
$this->selectVersion();
5866

59-
if (!$this->enableZeroHeader && !$stream->isSeekable()) {
67+
if (!$this->enableZeroHeader && !stream_get_meta_data($stream)['seekable']) {
6068
throw new StreamNotSeekableException();
6169
}
62-
if (!$stream->isReadable()) {
70+
if (!(
71+
str_contains(stream_get_meta_data($stream)['mode'], 'r')
72+
|| str_contains(stream_get_meta_data($stream)['mode'], 'w+')
73+
|| str_contains(stream_get_meta_data($stream)['mode'], 'a+')
74+
|| str_contains(stream_get_meta_data($stream)['mode'], 'x+')
75+
|| str_contains(stream_get_meta_data($stream)['mode'], 'c+')
76+
)) {
6377
throw new StreamNotReadableException();
6478
}
79+
$this->stream = $stream;
6580
}
6681

6782
/**
@@ -121,7 +136,9 @@ public function process(): string
121136
{
122137
if (!$this->enableZeroHeader) {
123138
$this->readStream(send: false);
124-
$this->stream->rewind();
139+
if (rewind($this->stream) === false) {
140+
throw new ResourceActionException('rewind', $this->stream);
141+
}
125142
}
126143

127144
$this->addFileHeader();
@@ -234,10 +251,10 @@ private function readStream(bool $send): void
234251

235252
$deflate = $this->compressionInit();
236253

237-
while (!$this->stream->eof() && ($this->maxSize === null || $this->uncompressedSize < $this->maxSize)) {
254+
while (!feof($this->stream) && ($this->maxSize === null || $this->uncompressedSize < $this->maxSize)) {
238255
$readLength = min(($this->maxSize ?? PHP_INT_MAX) - $this->uncompressedSize, self::CHUNKED_READ_BLOCK_SIZE);
239256

240-
$data = $this->stream->read($readLength);
257+
$data = fread($this->stream, $readLength);
241258

242259
hash_update($hash, $data);
243260

@@ -248,9 +265,7 @@ private function readStream(bool $send): void
248265
$data = deflate_add(
249266
$deflate,
250267
$data,
251-
$this->stream->eof()
252-
? ZLIB_FINISH
253-
: ZLIB_NO_FLUSH
268+
feof($this->stream) ? ZLIB_FINISH : ZLIB_NO_FLUSH
254269
);
255270
}
256271

src/StaticStream.php

Lines changed: 0 additions & 111 deletions
This file was deleted.

0 commit comments

Comments
 (0)