Skip to content

Commit 8819e79

Browse files
authored
Use temp stream instead of string to buffer content (#52)
* Use temp stream instead of string to buffer content * Update MultipartStreamBuilder::build to buffer built content in a php://temp stream resource instead of (string) $contents. This way, the size of the stream built won't be limited by PHP runtime limit. * Detect available memory for maxmemory in buffer * Detect available memory (in bytes). Then config the buffer stream to stay in memory until reaching 1/4 of that. * Added setBufferMaxMemory to manually override that limit. * Fix code style * Improve documentation to getAvailableMemory * Improve documentation to MultipartStreamBuilder::getAvailableMemory * Update CHANGELOG.md * Remove the memory detection logic from build * Remove the memory detection logic from MultipartStreamBuilder::build. * Code style update * Minor updates * Improve readability of comment. * Use the old __toString approach if the stream is not isReadable(). * Remove unnecessary comment
1 parent 9addfcf commit 8819e79

File tree

2 files changed

+34
-23
lines changed

2 files changed

+34
-23
lines changed

CHANGELOG.md

+8-7
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
## 1.2.0 - (unreleased)
44

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

78
## 1.1.2 - 2020-07-13
89

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

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

2930
### Fixed
3031

31-
- Make sure one can add resources with same name without overwrite.
32+
- Make sure one can add resources with same name without overwrite.
3233

3334
## 0.1.6 - 2017-02-16
3435

3536
### Fixed
3637

37-
- Performance improvements by avoid using `uniqid()`.
38+
- Performance improvements by avoid using `uniqid()`.
3839

3940
## 0.1.5 - 2017-02-14
4041

4142
### Fixed
4243

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

4546
## 0.1.4 - 2016-12-31
4647

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

5354
### Added
5455

55-
- Added `CustomMimetypeHelper` to allow you to configure custom mimetypes.
56+
- Added `CustomMimetypeHelper` to allow you to configure custom mimetypes.
5657

5758
### Changed
5859

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

6364
### Added
6465

65-
- Support for Outlook msg files.
66+
- Support for Outlook msg files.
6667

6768
## 0.1.1 - 2016-08-10
6869

6970
### Added
7071

71-
- Support for Apple passbook.
72+
- Support for Apple passbook.
7273

7374
## 0.1.0 - 2016-07-19
7475

src/MultipartStreamBuilder.php

+26-16
Original file line numberDiff line numberDiff line change
@@ -73,12 +73,10 @@ public function __construct($streamFactory = null)
7373
}
7474

7575
/**
76-
* Add a resource to the Multipart Stream
76+
* Add a resource to the Multipart Stream.
7777
*
78-
* @param string|resource|\Psr\Http\Message\StreamInterface $resource
79-
* The filepath, resource or StreamInterface of the data.
80-
* @param array $headers
81-
* Additional headers array: ['header-name' => 'header-value'].
78+
* @param string|resource|\Psr\Http\Message\StreamInterface $resource the filepath, resource or StreamInterface of the data
79+
* @param array $headers additional headers array: ['header-name' => 'header-value']
8280
*
8381
* @return MultipartStreamBuilder
8482
*/
@@ -133,28 +131,40 @@ public function addResource($name, $resource, array $options = [])
133131
*/
134132
public function build()
135133
{
136-
$streams = '';
134+
// Open a temporary read-write stream as buffer.
135+
// If the size is less than predefined limit, things will stay in memory.
136+
// If the size is more than that, things will be stored in temp file.
137+
$buffer = fopen('php://temp', 'r+');
137138
foreach ($this->data as $data) {
138139
// Add start and headers
139-
$streams .= "--{$this->getBoundary()}\r\n".
140-
$this->getHeaders($data['headers'])."\r\n";
140+
fwrite($buffer, "--{$this->getBoundary()}\r\n".
141+
$this->getHeaders($data['headers'])."\r\n");
141142

142-
// Convert the stream to string
143-
/* @var $contentStream StreamInterface */
143+
/** @var $contentStream StreamInterface */
144144
$contentStream = $data['contents'];
145+
146+
// Read stream into buffer
145147
if ($contentStream->isSeekable()) {
146-
$streams .= $contentStream->__toString();
148+
$contentStream->rewind(); // rewind to beginning.
149+
}
150+
if ($contentStream->isReadable()) {
151+
while (!$contentStream->eof()) {
152+
// Read 1MB chunk into buffer until reached EOF.
153+
fwrite($buffer, $contentStream->read(1048576));
154+
}
147155
} else {
148-
$streams .= $contentStream->getContents();
156+
fwrite($buffer, $contentStream->__toString());
149157
}
150-
151-
$streams .= "\r\n";
158+
fwrite($buffer, "\r\n");
152159
}
153160

154161
// Append end
155-
$streams .= "--{$this->getBoundary()}--\r\n";
162+
fwrite($buffer, "--{$this->getBoundary()}--\r\n");
163+
164+
// Rewind to starting position for reading.
165+
fseek($buffer, 0);
156166

157-
return $this->createStream($streams);
167+
return $this->createStream($buffer);
158168
}
159169

160170
/**

0 commit comments

Comments
 (0)