Fix GH-11982: str_getcsv returns null byte for unterminated quoted string

Closes GH-12047
This commit is contained in:
Jakub Zelenka 2023-08-25 18:26:19 +01:00
parent b07a2d4714
commit aff46d75e1
No known key found for this signature in database
GPG Key ID: 1C0779DC5C0A9DE4
5 changed files with 72 additions and 0 deletions

2
NEWS
View File

@ -17,6 +17,8 @@ PHP NEWS
- Standard:
. Added $before_needle argument to strrchr(). (HypeMC)
. Fixed GH-11982 (str_getcsv returns null byte for unterminated enclosure).
(Jakub Zelenka)
17 Aug 2023, PHP 8.3.0beta3

View File

@ -352,6 +352,9 @@ PHP 8.3 UPGRADE NOTES
got silently ignored and the number got rounded to zero decimal places.
. The $before_needle argument added to strrchr() which works in the same way
like its counterpart in strstr() or stristr().
. str_getcsv() and fgetcsv() return empty string instead of a string with
a single zero byte for the last field which contains only unterminated
enclosure.
========================================
6. New Functions

View File

@ -2017,7 +2017,14 @@ PHPAPI HashTable *php_fgetcsv(php_stream *stream, char delimiter, char enclosure
memcpy(tptr, line_end, line_end_len);
tptr += line_end_len;
/* nothing can be fetched if stream is NULL (e.g. str_getcsv()) */
if (stream == NULL) {
/* the enclosure is unterminated */
if (bptr > limit) {
/* if the line ends with enclosure, we need to go back by
* one character so the \0 character is not copied. */
--bptr;
}
goto quit_loop_2;
}
@ -2028,6 +2035,11 @@ PHPAPI HashTable *php_fgetcsv(php_stream *stream, char delimiter, char enclosure
* assign all the data from the start of
* the enclosure to end of data to the
* last element */
if (bptr > limit) {
/* if the line ends with enclosure, we need to go back by
* one character so the \0 character is not copied. */
--bptr;
}
goto quit_loop_2;
}

View File

@ -0,0 +1,29 @@
--TEST--
fgetcsv() with unterminated enclosure at the end of file
--FILE--
<?php
$contents = <<<EOS
"cell1","cell2"
"cell1","
EOS;
$stream = fopen('php://memory', 'w+');
fwrite($stream, $contents);
rewind($stream);
while (($data = fgetcsv($stream)) !== false) {
var_dump($data);
}
fclose($stream);
?>
--EXPECT--
array(2) {
[0]=>
string(5) "cell1"
[1]=>
string(5) "cell2"
}
array(2) {
[0]=>
string(5) "cell1"
[1]=>
string(0) ""
}

View File

@ -0,0 +1,26 @@
--TEST--
GH-11982 (str_getcsv returns null byte for unterminated quoted string)
--FILE--
<?php
var_dump(str_getcsv('"'));
var_dump(str_getcsv('"field","'));
var_dump(str_getcsv('"","a'));
?>
--EXPECT--
array(1) {
[0]=>
string(0) ""
}
array(2) {
[0]=>
string(5) "field"
[1]=>
string(0) ""
}
array(2) {
[0]=>
string(0) ""
[1]=>
string(1) "a"
}