From c4c3bed2c7a0b41cd207b01e8f0405991a92246c Mon Sep 17 00:00:00 2001 From: Ilia Alshanetsky Date: Wed, 8 Apr 2026 17:56:49 -0400 Subject: [PATCH] Fix GH-8562: SplFileObject::current() returns wrong value after next() SplFileObject::next() without READ_AHEAD cleared the cached line and incremented current_line_num but didn't advance the stream. When called without a preceding current() (e.g. rewind() then next()), the stream position stayed put, so the subsequent current() read stale data. Read a line to advance the stream when next() is called with no cached line. Closes GH-8562 --- ext/spl/spl_directory.c | 4 ++++ ext/spl/tests/gh8562.phpt | 27 +++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 ext/spl/tests/gh8562.phpt diff --git a/ext/spl/spl_directory.c b/ext/spl/spl_directory.c index daaba27cbfc6..da83104b2729 100644 --- a/ext/spl/spl_directory.c +++ b/ext/spl/spl_directory.c @@ -2142,6 +2142,10 @@ PHP_METHOD(SplFileObject, next) ZEND_PARSE_PARAMETERS_NONE(); + if (!intern->u.file.current_line && Z_ISUNDEF(intern->u.file.current_zval)) { + spl_filesystem_file_read_line(ZEND_THIS, intern, true); + } + 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); 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