Skip to content

Commit a986e70

Browse files
committed
Avoid double buffering in Zend streams
Disable buffering in PHP streams, to avoid storing and copying the file contents twice. This will call stream_set_option() on custom stream wrapper as well, so the method needs to be implemented to avoid a warning.
1 parent 918f09f commit a986e70

File tree

6 files changed

+15
-5
lines changed

6 files changed

+15
-5
lines changed

Zend/tests/bug38779.phpt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ class Loader {
2222
function stream_stat() {
2323
return array('size' => strlen($this->data));
2424
}
25+
function stream_set_option($option, $arg1, $arg2) {
26+
return false;
27+
}
2528
}
2629
stream_wrapper_register('Loader', 'Loader');
2730
require 'Loader://qqq.php';

Zend/zend_stream.c

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ static size_t zend_stream_read(zend_file_handle *file_handle, char *buf, size_t
126126
ZEND_API int zend_stream_fixup(zend_file_handle *file_handle, char **buf, size_t *len) /* {{{ */
127127
{
128128
size_t size;
129-
zend_stream_type old_type;
129+
zend_bool is_fp = 0;
130130

131131
if (file_handle->buf) {
132132
*buf = file_handle->buf;
@@ -145,6 +145,7 @@ ZEND_API int zend_stream_fixup(zend_file_handle *file_handle, char **buf, size_t
145145
return FAILURE;
146146
}
147147

148+
is_fp = 1;
148149
file_handle->type = ZEND_HANDLE_STREAM;
149150
file_handle->handle.stream.handle = file_handle->handle.fp;
150151
file_handle->handle.stream.isatty = isatty(fileno((FILE *)file_handle->handle.stream.handle));
@@ -158,10 +159,7 @@ ZEND_API int zend_stream_fixup(zend_file_handle *file_handle, char **buf, size_t
158159
return FAILURE;
159160
}
160161

161-
old_type = file_handle->type;
162-
file_handle->type = ZEND_HANDLE_STREAM; /* we might still be _FP but we need fsize() work */
163-
164-
if (old_type == ZEND_HANDLE_FP && !file_handle->handle.stream.isatty && size) {
162+
if (is_fp && !file_handle->handle.stream.isatty && size) {
165163
file_handle->buf = *buf = safe_emalloc(1, size, ZEND_MMAP_AHEAD);
166164
file_handle->len = zend_stream_read(file_handle, *buf, size);
167165
} else {

ext/standard/tests/file/fopencookie.phpt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,9 @@ class userstream {
7676
function stream_stat() {
7777
return array('size' => strlen($this->data));
7878
}
79+
function stream_set_option($option, $arg1, $arg2) {
80+
return false;
81+
}
7982
}
8083

8184
stream_wrapper_register("cookietest", "userstream");

ext/standard/tests/file/include_streams.phpt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,9 @@ class mystream
9696
}
9797
}
9898

99+
function stream_set_option($option, $arg1, $arg2) {
100+
return false;
101+
}
99102
}
100103

101104
if (!stream_wrapper_register("test", "mystream")) {

main/main.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1594,6 +1594,8 @@ PHPAPI int php_stream_open_for_zend_ex(const char *filename, zend_file_handle *h
15941594
handle->handle.stream.closer = php_zend_stream_closer;
15951595
/* suppress warning if this stream is not explicitly closed */
15961596
php_stream_auto_cleanup(stream);
1597+
/* Disable buffering to avoid double buffering between PHP and Zend streams. */
1598+
php_stream_set_option(stream, PHP_STREAM_OPTION_READ_BUFFER, PHP_STREAM_BUFFER_NONE, NULL);
15971599

15981600
return SUCCESS;
15991601
}

sapi/phpdbg/tests/phpdbg_get_executable_stream_wrapper.phpt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ final class StreamWrapper
5959
public function stream_close() : bool { return \fclose($this->stream); }
6060
public function stream_eof() : bool { return \feof($this->stream); }
6161
public function stream_stat() { return \fstat($this->stream); }
62+
public function stream_set_option($option, $arg1, $arg2) { return false; }
6263

6364
private $stream = false;
6465
}

0 commit comments

Comments
 (0)