mirror of
https://github.com/php/php-src.git
synced 2024-11-23 18:04:36 +08:00
Fix GH-11242: Use dynamic buffer for large length in stream mem copy
This commit is contained in:
parent
c6b9db2131
commit
4a5d13e205
4
NEWS
4
NEWS
@ -22,6 +22,10 @@ PHP NEWS
|
||||
. Fixed GH-11573 (RecursiveDirectoryIterator::hasChildren is slow).
|
||||
(nielsdos)
|
||||
|
||||
- Streams:
|
||||
. Implemented GH-11242 (_php_stream_copy_to_mem: Allow specifying a maximum
|
||||
length without allocating a buffer of that size). (Jakub Zelenka)
|
||||
|
||||
06 Jul 2023, PHP 8.3.0alpha3
|
||||
|
||||
- Core:
|
||||
|
@ -0,0 +1,27 @@
|
||||
--TEST--
|
||||
Test file_get_contents() function with large length parameter
|
||||
--INI--
|
||||
memory_limit=128M
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$file_path = __DIR__ . '/file_get_contents_with_large_length_content.txt';
|
||||
$file_content = str_repeat('a', 50000);
|
||||
file_put_contents($file_path, $file_content);
|
||||
|
||||
// test lenght limiting
|
||||
$result = file_get_contents($file_path, length: 500000000);
|
||||
var_dump($result === $file_content);
|
||||
|
||||
// test lenght limiting
|
||||
$result = file_get_contents($file_path, length: 40000);
|
||||
var_dump($result === str_repeat('a', 40000));
|
||||
|
||||
?>
|
||||
--CLEAN--
|
||||
<?php
|
||||
unlink(__DIR__ . '/file_get_contents_with_large_length_content.txt');
|
||||
?>
|
||||
--EXPECT--
|
||||
bool(true)
|
||||
bool(true)
|
@ -1489,7 +1489,7 @@ PHPAPI zend_string *_php_stream_copy_to_mem(php_stream *src, size_t maxlen, int
|
||||
{
|
||||
ssize_t ret = 0;
|
||||
char *ptr;
|
||||
size_t len = 0, max_len;
|
||||
size_t len = 0, buflen;
|
||||
int step = CHUNK_SIZE;
|
||||
int min_room = CHUNK_SIZE / 4;
|
||||
php_stream_statbuf ssbuf;
|
||||
@ -1503,7 +1503,7 @@ PHPAPI zend_string *_php_stream_copy_to_mem(php_stream *src, size_t maxlen, int
|
||||
maxlen = 0;
|
||||
}
|
||||
|
||||
if (maxlen > 0) {
|
||||
if (maxlen > 0 && maxlen < 4 * CHUNK_SIZE) {
|
||||
result = zend_string_alloc(maxlen, persistent);
|
||||
ptr = ZSTR_VAL(result);
|
||||
while ((len < maxlen) && !php_stream_eof(src)) {
|
||||
@ -1537,20 +1537,30 @@ PHPAPI zend_string *_php_stream_copy_to_mem(php_stream *src, size_t maxlen, int
|
||||
* by a downsize of the buffer, overestimate by the step size (which is
|
||||
* 8K). */
|
||||
if (php_stream_stat(src, &ssbuf) == 0 && ssbuf.sb.st_size > 0) {
|
||||
max_len = MAX(ssbuf.sb.st_size - src->position, 0) + step;
|
||||
buflen = MAX(ssbuf.sb.st_size - src->position, 0) + step;
|
||||
if (maxlen > 0 && buflen > maxlen) {
|
||||
buflen = maxlen;
|
||||
}
|
||||
} else {
|
||||
max_len = step;
|
||||
buflen = step;
|
||||
}
|
||||
|
||||
result = zend_string_alloc(max_len, persistent);
|
||||
result = zend_string_alloc(buflen, persistent);
|
||||
ptr = ZSTR_VAL(result);
|
||||
|
||||
// TODO: Propagate error?
|
||||
while ((ret = php_stream_read(src, ptr, max_len - len)) > 0){
|
||||
while ((ret = php_stream_read(src, ptr, buflen - len)) > 0) {
|
||||
len += ret;
|
||||
if (len + min_room >= max_len) {
|
||||
result = zend_string_extend(result, max_len + step, persistent);
|
||||
max_len += step;
|
||||
if (len + min_room >= buflen) {
|
||||
if (maxlen == len) {
|
||||
break;
|
||||
}
|
||||
if (maxlen > 0 && buflen + step > maxlen) {
|
||||
buflen = maxlen;
|
||||
} else {
|
||||
buflen += step;
|
||||
}
|
||||
result = zend_string_extend(result, buflen, persistent);
|
||||
ptr = ZSTR_VAL(result) + len;
|
||||
} else {
|
||||
ptr += ret;
|
||||
|
Loading…
Reference in New Issue
Block a user