Skip to content

Commit f1d11c1

Browse files
committed
Fix #62004: SplFileObject: fgets after seek returns wrong line
As it is, `::seek(0)` sets the file pointer to the beginning of the file, but `::seek($n)` where `$n > 0` sets the file pointer to the beginning of the following line, having line `$n` already read into the line buffer. This is pretty inconsistent; we fix it by always seeking to the beginning of the line. We also add a test case for the duplicate bug #46569. Closes GH-6434.
1 parent 841b00f commit f1d11c1

10 files changed

+56
-7
lines changed

NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ PHP NEWS
3333
- Phpdbg:
3434
. Fixed bug #76813 (Access violation near NULL on source operand). (cmb)
3535

36+
- SPL:
37+
. Fixed #62004 (SplFileObject: fgets after seek returns wrong line). (cmb)
38+
3639
- Standard:
3740
. Fixed bug #80366 (Return Value of zend_fstat() not Checked). (sagpant, cmb)
3841

UPGRADING

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,8 @@ PHP 8.0 UPGRADE NOTES
516516

517517
- SPL:
518518
. SplFileObject::fgetss() has been removed.
519+
. SplFileObject::seek() now always seeks to the beginning of the line.
520+
Previously, positions >=1 sought to the beginning of the next line.
519521
. SplHeap::compare($a, $b) now specifies a method signature. Inheriting
520522
classes implementing this method will now have to use a compatible
521523
method signature.

ext/spl/spl_directory.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2727,7 +2727,7 @@ PHP_METHOD(SplFileObject, ftruncate)
27272727
PHP_METHOD(SplFileObject, seek)
27282728
{
27292729
spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
2730-
zend_long line_pos;
2730+
zend_long line_pos, i;
27312731

27322732
if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &line_pos) == FAILURE) {
27332733
RETURN_THROWS();
@@ -2742,11 +2742,15 @@ PHP_METHOD(SplFileObject, seek)
27422742

27432743
spl_filesystem_file_rewind(ZEND_THIS, intern);
27442744

2745-
while(intern->u.file.current_line_num < line_pos) {
2745+
for (i = 0; i < line_pos; i++) {
27462746
if (spl_filesystem_file_read_line(ZEND_THIS, intern, 1) == FAILURE) {
2747-
break;
2747+
return;
27482748
}
27492749
}
2750+
if (line_pos > 0) {
2751+
intern->u.file.current_line_num++;
2752+
spl_filesystem_file_free_line(intern);
2753+
}
27502754
} /* }}} */
27512755

27522756
/* {{{ PHP_MINIT_FUNCTION(spl_directory) */

ext/spl/tests/SplFileObject_key_error001.phpt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@ Erwin Poeze <erwin.poeze@gmail.com>
1212
//line 5
1313
$s = new SplFileObject(__FILE__);
1414

15-
$s->seek(12);
15+
$s->seek(13);
1616
$s->next();
1717
var_dump($s->key());
1818
var_dump($s->valid());
1919
?>
2020
--EXPECT--
21-
int(13)
21+
int(14)
2222
bool(false)

ext/spl/tests/SplFileObject_next_variation002.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,5 @@ echo $s->current();
2626
--EXPECT--
2727
//line 3
2828
//line 4
29-
//line 3
3029
//line 4
30+
//line 5

ext/spl/tests/bug46569.csv

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
first,line
2+
second,line
3+
third,line
4+
fourth,line
5+
fifth,line

ext/spl/tests/bug46569.phpt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
--TEST--
2+
Bug #46569 (SplFileObject: fgetcsv after seek returns wrong line)
3+
--FILE--
4+
<?php
5+
$file = new SplFileObject(__DIR__ . '/bug46569.csv');
6+
$file->seek(1);
7+
print_r($file->fgetcsv());
8+
?>
9+
--EXPECT--
10+
Array
11+
(
12+
[0] => second
13+
[1] => line
14+
)

ext/spl/tests/bug62004.phpt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
--TEST--
2+
Bug #62004 (SplFileObject: fgets after seek returns wrong line)
3+
--FILE--
4+
<?php
5+
$f = new SplFileObject(__DIR__ . '/bug62004.txt');
6+
$f->setFlags(SplFileObject::SKIP_EMPTY);
7+
$f->seek(0);
8+
echo $f->fgets();
9+
$f->seek(1);
10+
echo $f->fgets();
11+
$f->seek(2);
12+
echo $f->fgets();
13+
?>
14+
--EXPECT--
15+
Line 1
16+
Line 2
17+
Line 3

ext/spl/tests/bug62004.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Line 1
2+
Line 2
3+
Line 3
4+
Line 4

ext/spl/tests/fileobject_getcurrentline_basic.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,5 @@ echo $s->getCurrentLine();
1515
echo $s->getCurrentLine();
1616
?>
1717
--EXPECT--
18+
//line 2
1819
//line 3
19-
//line 4

0 commit comments

Comments
 (0)