Skip to content

Commit e4c2b52

Browse files
committed
Fix GH-8121: SplFileObject - seek and key with csv file inconsistent
First, we must not free the current line before we call `spl_filesystem_file_read_csv()`, because then the `current_line` will not be properly updated. Since the EOF check is superfluous here, we move that part of the code to the branch for subtypes. This issue has been introduced by the fix for bug 75917. Second, we only must increase the `current_line` if we're not reading ahead. This issue has been introduced by the fix for bug 62004.
1 parent ef80dcb commit e4c2b52

File tree

3 files changed

+53
-9
lines changed

3 files changed

+53
-9
lines changed

ext/spl/spl_directory.c

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1939,18 +1939,18 @@ static int spl_filesystem_file_read_line_ex(zval * this_ptr, spl_filesystem_obje
19391939

19401940
/* 1) use fgetcsv? 2) overloaded call the function, 3) do it directly */
19411941
if (SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_READ_CSV) || intern->u.file.func_getCurr->common.scope != spl_ce_SplFileObject) {
1942-
spl_filesystem_file_free_line(intern);
1943-
1944-
if (php_stream_eof(intern->u.file.stream)) {
1945-
if (!silent) {
1946-
zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Cannot read from file %s", intern->file_name);
1947-
}
1948-
return FAILURE;
1949-
}
19501942
if (SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_READ_CSV)) {
19511943
return spl_filesystem_file_read_csv(intern, intern->u.file.delimiter, intern->u.file.enclosure, intern->u.file.escape, NULL);
19521944
} else {
19531945
zend_execute_data *execute_data = EG(current_execute_data);
1946+
spl_filesystem_file_free_line(intern);
1947+
1948+
if (php_stream_eof(intern->u.file.stream)) {
1949+
if (!silent) {
1950+
zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Cannot read from file %s", intern->file_name);
1951+
}
1952+
return FAILURE;
1953+
}
19541954
zend_call_method_with_0_params(Z_OBJ_P(this_ptr), Z_OBJCE_P(ZEND_THIS), &intern->u.file.func_getCurr, "getCurrentLine", &retval);
19551955
}
19561956
if (!Z_ISUNDEF(retval)) {
@@ -2739,8 +2739,8 @@ PHP_METHOD(SplFileObject, seek)
27392739
}
27402740
}
27412741
if (line_pos > 0) {
2742-
intern->u.file.current_line_num++;
27432742
if (!SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_READ_AHEAD)) {
2743+
intern->u.file.current_line_num++;
27442744
spl_filesystem_file_free_line(intern);
27452745
}
27462746
}

ext/spl/tests/gh8121.csv

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
id,status,on_sale,brand,name,link,meta_title,meta_desc,description
2+
1,2,15,Samsung,M21,samsung-m21,Samsung M21,Samsung M21,Samsung M21
3+
2,2,15,Samsung,M32,samsung-m32,Samsung M32,Samsung M32,Samsung M32
4+
3,2,15,Samsung,M21,samsung-m21,Samsung M21,Samsung M21,Samsung M21
5+
4,2,15,Samsung,M32,samsung-m32,Samsung M32,Samsung M32,Samsung M32

ext/spl/tests/gh8121.phpt

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
--TEST--
2+
GH-8121 (SplFileObject - seek and key with csv file inconsistent)
3+
--FILE--
4+
<?php
5+
$flagss = [
6+
SplFileObject::READ_AHEAD | SplFileObject::READ_CSV | SplFileObject::SKIP_EMPTY | SplFileObject::DROP_NEW_LINE,
7+
SplFileObject::READ_AHEAD | SplFileObject::SKIP_EMPTY | SplFileObject::DROP_NEW_LINE,
8+
SplFileObject::SKIP_EMPTY | SplFileObject::DROP_NEW_LINE,
9+
];
10+
foreach ($flagss as $flags) {
11+
$file = new SplFileObject(__DIR__ . "/gh8121.csv", "r");
12+
echo "flags: $flags\n";
13+
$file->setFlags($flags);
14+
$file->seek(0);
15+
var_dump($file->key());
16+
$file->seek(1);
17+
var_dump($file->key());
18+
$file->seek(2);
19+
var_dump($file->key());
20+
$file->seek(3);
21+
var_dump($file->key());
22+
}
23+
?>
24+
--EXPECT--
25+
flags: 15
26+
int(0)
27+
int(1)
28+
int(2)
29+
int(3)
30+
flags: 7
31+
int(0)
32+
int(1)
33+
int(2)
34+
int(3)
35+
flags: 5
36+
int(0)
37+
int(1)
38+
int(2)
39+
int(3)

0 commit comments

Comments
 (0)