Skip to content

Use temp stream instead of string to buffer content #52

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Dec 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 8 additions & 7 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## 1.2.0 - (unreleased)

- Refactored MultipartStreamBuilder to clean up and allow injecting data without a filename
- Dynamically use memory or temp file to buffer the stream content.

## 1.1.2 - 2020-07-13

Expand All @@ -24,23 +25,23 @@ No changes from 0.2.0.
## 0.2.0 - 2017-02-20

You may do a BC update to version 0.2.0 if you are sure that you are not adding
multiple resources with the same name to the Builder.
multiple resources with the same name to the Builder.

### Fixed

- Make sure one can add resources with same name without overwrite.
- Make sure one can add resources with same name without overwrite.

## 0.1.6 - 2017-02-16

### Fixed

- Performance improvements by avoid using `uniqid()`.
- Performance improvements by avoid using `uniqid()`.

## 0.1.5 - 2017-02-14

### Fixed

- Support for non-readable streams. This fix was needed because flaws in Guzzle, Zend and Slims implementations of PSR-7.
- Support for non-readable streams. This fix was needed because flaws in Guzzle, Zend and Slims implementations of PSR-7.

## 0.1.4 - 2016-12-31

Expand All @@ -52,7 +53,7 @@ multiple resources with the same name to the Builder.

### Added

- Added `CustomMimetypeHelper` to allow you to configure custom mimetypes.
- Added `CustomMimetypeHelper` to allow you to configure custom mimetypes.

### Changed

Expand All @@ -62,13 +63,13 @@ multiple resources with the same name to the Builder.

### Added

- Support for Outlook msg files.
- Support for Outlook msg files.

## 0.1.1 - 2016-08-10

### Added

- Support for Apple passbook.
- Support for Apple passbook.

## 0.1.0 - 2016-07-19

Expand Down
42 changes: 26 additions & 16 deletions src/MultipartStreamBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,10 @@ public function __construct($streamFactory = null)
}

/**
* Add a resource to the Multipart Stream
* Add a resource to the Multipart Stream.
*
* @param string|resource|\Psr\Http\Message\StreamInterface $resource
* The filepath, resource or StreamInterface of the data.
* @param array $headers
* Additional headers array: ['header-name' => 'header-value'].
* @param string|resource|\Psr\Http\Message\StreamInterface $resource the filepath, resource or StreamInterface of the data
* @param array $headers additional headers array: ['header-name' => 'header-value']
*
* @return MultipartStreamBuilder
*/
Expand Down Expand Up @@ -133,28 +131,40 @@ public function addResource($name, $resource, array $options = [])
*/
public function build()
{
$streams = '';
// Open a temporary read-write stream as buffer.
// If the size is less than predefined limit, things will stay in memory.
// If the size is more than that, things will be stored in temp file.
$buffer = fopen('php://temp', 'r+');
foreach ($this->data as $data) {
// Add start and headers
$streams .= "--{$this->getBoundary()}\r\n".
$this->getHeaders($data['headers'])."\r\n";
fwrite($buffer, "--{$this->getBoundary()}\r\n".
$this->getHeaders($data['headers'])."\r\n");

// Convert the stream to string
/* @var $contentStream StreamInterface */
/** @var $contentStream StreamInterface */
$contentStream = $data['contents'];

// Read stream into buffer
if ($contentStream->isSeekable()) {
$streams .= $contentStream->__toString();
$contentStream->rewind(); // rewind to beginning.
}
if ($contentStream->isReadable()) {
while (!$contentStream->eof()) {
// Read 1MB chunk into buffer until reached EOF.
fwrite($buffer, $contentStream->read(1048576));
}
} else {
$streams .= $contentStream->getContents();
fwrite($buffer, $contentStream->__toString());
}

$streams .= "\r\n";
fwrite($buffer, "\r\n");
}

// Append end
$streams .= "--{$this->getBoundary()}--\r\n";
fwrite($buffer, "--{$this->getBoundary()}--\r\n");

// Rewind to starting position for reading.
fseek($buffer, 0);

return $this->createStream($streams);
return $this->createStream($buffer);
}

/**
Expand Down