diff --git a/ext/spl/spl_directory.c b/ext/spl/spl_directory.c index daaba27cbfc6..f204a4051cc9 100644 --- a/ext/spl/spl_directory.c +++ b/ext/spl/spl_directory.c @@ -1813,21 +1813,24 @@ static zend_result spl_filesystem_file_read_ex(spl_filesystem_object *intern, bo } if (!buf) { - intern->u.file.current_line = ZSTR_EMPTY_ALLOC(); - } else { - if (!csv && SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_DROP_NEW_LINE)) { - if (line_len > 0 && buf[line_len - 1] == '\n') { + if (!silent) { + spl_filesystem_file_cannot_read(intern); + } + return FAILURE; + } + + if (!csv && SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_DROP_NEW_LINE)) { + if (line_len > 0 && buf[line_len - 1] == '\n') { + line_len--; + if (line_len > 0 && buf[line_len - 1] == '\r') { line_len--; - if (line_len > 0 && buf[line_len - 1] == '\r') { - line_len--; - } - buf[line_len] = '\0'; } + buf[line_len] = '\0'; } - - intern->u.file.current_line = zend_string_init(buf, line_len, /* persistent */ false); - efree(buf); } + + intern->u.file.current_line = zend_string_init(buf, line_len, /* persistent */ false); + efree(buf); intern->u.file.current_line_num += line_add; return SUCCESS; @@ -2093,10 +2096,17 @@ PHP_METHOD(SplFileObject, fgets) CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(intern); - if (spl_filesystem_file_read_ex(intern, /* silent */ false, /* line_add */ 1, /* csv */ false) == FAILURE) { - RETURN_THROWS(); + if (intern->u.file.current_line) { + RETVAL_STR_COPY(intern->u.file.current_line); + spl_filesystem_file_free_line(intern); + intern->u.file.current_line_num++; + } else { + if (spl_filesystem_file_read_ex(intern, /* silent */ false, /* line_add */ 1, /* csv */ false) == FAILURE) { + RETURN_THROWS(); + } + RETVAL_STR_COPY(intern->u.file.current_line); + spl_filesystem_file_free_line(intern); } - RETURN_STR_COPY(intern->u.file.current_line); } /* }}} */ /* {{{ Return current line from file */ @@ -2142,6 +2152,12 @@ PHP_METHOD(SplFileObject, next) ZEND_PARSE_PARAMETERS_NONE(); + if (!intern->u.file.current_line && Z_ISUNDEF(intern->u.file.current_zval)) { + if (spl_filesystem_file_read_line(ZEND_THIS, intern, true) == FAILURE) { + return; + } + } + spl_filesystem_file_free_line(intern); if (SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_READ_AHEAD)) { spl_filesystem_file_read_line(ZEND_THIS, intern, true); @@ -2629,7 +2645,7 @@ PHP_METHOD(SplFileObject, seek) for (i = 0; i < line_pos; i++) { if (spl_filesystem_file_read_line(ZEND_THIS, intern, true) == FAILURE) { - return; + break; } } if (line_pos > 0 && !SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_READ_AHEAD)) { @@ -2648,9 +2664,8 @@ PHP_METHOD(SplFileObject, __toString) if (!intern->u.file.current_line) { ZEND_ASSERT(Z_ISUNDEF(intern->u.file.current_zval)); - zend_result result = spl_filesystem_file_read_line(ZEND_THIS, intern, false); - if (UNEXPECTED(result != SUCCESS)) { - RETURN_THROWS(); + if (spl_filesystem_file_read_line(ZEND_THIS, intern, true) == FAILURE) { + RETURN_EMPTY_STRING(); } } diff --git a/ext/spl/tests/SplFileObject/SplFileObject_key_error001.phpt b/ext/spl/tests/SplFileObject/SplFileObject_key_error001.phpt index 0c21d0b905e9..7d0e3ae8d969 100644 --- a/ext/spl/tests/SplFileObject/SplFileObject_key_error001.phpt +++ b/ext/spl/tests/SplFileObject/SplFileObject_key_error001.phpt @@ -18,5 +18,5 @@ var_dump($s->key()); var_dump($s->valid()); ?> --EXPECT-- -int(14) +int(12) bool(false) diff --git a/ext/spl/tests/SplFileObject/SplFileObject_key_error002.phpt b/ext/spl/tests/SplFileObject/SplFileObject_key_error002.phpt index 8fc9b7fef0a5..0834dbc0524f 100644 --- a/ext/spl/tests/SplFileObject/SplFileObject_key_error002.phpt +++ b/ext/spl/tests/SplFileObject/SplFileObject_key_error002.phpt @@ -18,5 +18,5 @@ var_dump($s->key()); var_dump($s->valid()); ?> --EXPECT-- -int(13) +int(12) bool(false) diff --git a/ext/spl/tests/SplFileObject/bug81477.phpt b/ext/spl/tests/SplFileObject/bug81477.phpt index f7730a791aa0..421c74dc4d68 100644 --- a/ext/spl/tests/SplFileObject/bug81477.phpt +++ b/ext/spl/tests/SplFileObject/bug81477.phpt @@ -21,7 +21,6 @@ string(8) "baz,bat " string(10) "more,data " -string(0) "" --CLEAN-- rewind(); var_dump($file->fgetcsv()); ?> --EXPECT-- -array(1) { - [0]=> - NULL -} +bool(false) bool(false) diff --git a/ext/spl/tests/SplFileObject/gh8561.phpt b/ext/spl/tests/SplFileObject/gh8561.phpt new file mode 100644 index 000000000000..adf36afb8b29 --- /dev/null +++ b/ext/spl/tests/SplFileObject/gh8561.phpt @@ -0,0 +1,30 @@ +--TEST-- +GH-8561 (SplFileObject: key() and current() unsynchronized after fgets()) +--FILE-- +fwrite("line {$i}" . PHP_EOL); +} + +// Case 1: rewind + fgets, then key/current +$file->rewind(); +$file->fgets(); +echo "After rewind+fgets: key=" . $file->key() . " current=" . trim($file->current()) . "\n"; + +// Case 2: multiple fgets +$file->rewind(); +$file->fgets(); +$file->fgets(); +echo "After rewind+fgets+fgets: key=" . $file->key() . " current=" . trim($file->current()) . "\n"; + +// Case 3: current then fgets +$file->rewind(); +$file->current(); +$file->fgets(); +echo "After current+fgets: key=" . $file->key() . " current=" . trim($file->current()) . "\n"; +?> +--EXPECT-- +After rewind+fgets: key=1 current=line 1 +After rewind+fgets+fgets: key=2 current=line 2 +After current+fgets: key=1 current=line 1 diff --git a/ext/spl/tests/SplFileObject/gh8563.phpt b/ext/spl/tests/SplFileObject/gh8563.phpt new file mode 100644 index 000000000000..03891750f8bf --- /dev/null +++ b/ext/spl/tests/SplFileObject/gh8563.phpt @@ -0,0 +1,29 @@ +--TEST-- +GH-8563 (Different results for seek() on SplFileObject and SplTempFileObject) +--FILE-- +fwrite("line {$i}" . PHP_EOL); + $file_02->fwrite("line {$i}" . PHP_EOL); +} + +$file_01->rewind(); +$file_02->rewind(); + +$file_01->seek(10); +$file_02->seek(10); + +echo 'SplFileObject: ' . $file_01->key() . "\n"; +echo 'SplTempFileObject: ' . $file_02->key() . "\n"; +?> +--CLEAN-- + +--EXPECT-- +SplFileObject: 5 +SplTempFileObject: 5 diff --git a/ext/spl/tests/SplFileObject/gh8564.phpt b/ext/spl/tests/SplFileObject/gh8564.phpt new file mode 100644 index 000000000000..ff16893c4c6b --- /dev/null +++ b/ext/spl/tests/SplFileObject/gh8564.phpt @@ -0,0 +1,20 @@ +--TEST-- +GH-8564 (SplFileObject: next() moves to nonexistent indexes) +--FILE-- +fwrite("line {$i}" . PHP_EOL); +} + +$file->rewind(); +for ($i = 0; $i < 10; $file->next(), $i++); +echo "next() 10x: key=" . $file->key() . " valid=" . var_export($file->valid(), true) . "\n"; + +$file->rewind(); +$file->seek(10); +echo "seek(10): key=" . $file->key() . " valid=" . var_export($file->valid(), true) . "\n"; +?> +--EXPECT-- +next() 10x: key=5 valid=false +seek(10): key=5 valid=false diff --git a/ext/spl/tests/gh13685.phpt b/ext/spl/tests/gh13685.phpt index 0f679d0e93fc..2bdddec4584e 100644 --- a/ext/spl/tests/gh13685.phpt +++ b/ext/spl/tests/gh13685.phpt @@ -44,9 +44,9 @@ try { string(14) ""A", "B", "C" " string(13) ""D", "E", "F"" -Cannot read from file php://temp +string(0) "" --- Use csv control --- string(14) ""A", "B", "C" " string(13) ""D", "E", "F"" -Cannot read from file php://temp +string(0) "" diff --git a/ext/spl/tests/gh8562.phpt b/ext/spl/tests/gh8562.phpt new file mode 100644 index 000000000000..40b2554f5794 --- /dev/null +++ b/ext/spl/tests/gh8562.phpt @@ -0,0 +1,27 @@ +--TEST-- +GH-8562 (SplFileObject::current() returns wrong result after call to next()) +--FILE-- +fwrite("line {$i}" . PHP_EOL); +} + +$file->rewind(); +$file->next(); +echo "After rewind+next: key=" . $file->key() . " current=" . trim($file->current()) . "\n"; + +$file->rewind(); +$file->next(); +$file->next(); +echo "After rewind+next+next: key=" . $file->key() . " current=" . trim($file->current()) . "\n"; + +$file->rewind(); +$file->current(); +$file->next(); +echo "After current+next: key=" . $file->key() . " current=" . trim($file->current()) . "\n"; +?> +--EXPECT-- +After rewind+next: key=1 current=line 1 +After rewind+next+next: key=2 current=line 2 +After current+next: key=1 current=line 1