ext/(standard|spl): Deprecate passing a non-empty string as the $enclosure parameter (#15362)

This commit is contained in:
Gina Peter Banyard 2024-08-12 16:09:56 +01:00 committed by GitHub
parent 37c22c4c7e
commit c818d944cf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 184 additions and 45 deletions

10
NEWS
View File

@ -77,10 +77,20 @@ PHP NEWS
. The SplFixedArray::__wakeup() method has been deprecated as it implements . The SplFixedArray::__wakeup() method has been deprecated as it implements
__serialize() and __unserialize() which need to be overwritten instead. __serialize() and __unserialize() which need to be overwritten instead.
(TysonAndre) (TysonAndre)
. Passing a non-empty string for the $enclosure parameter of:
- SplFileObject::setCsvControl()
- SplFileObject::fputcsv()
- SplFileObject::fgetcsv()
is now deprecated. (Girgias)
- Standard: - Standard:
. Unserializing the uppercase 'S' tag is now deprecated. (timwolla) . Unserializing the uppercase 'S' tag is now deprecated. (timwolla)
. Enables crc32 auxiliary detection on OpenBSD. (David Carlier) . Enables crc32 auxiliary detection on OpenBSD. (David Carlier)
. Passing a non-empty string for the $enclosure parameter of:
- fputcsv()
- fgetcsv()
- str_getcsv()
is now deprecated. (Girgias)
- Streams: - Streams:
. Implemented GH-15155 (Stream context is lost when custom stream wrapper is . Implemented GH-15155 (Stream context is lost when custom stream wrapper is

View File

@ -506,6 +506,12 @@ PHP 8.4 UPGRADE NOTES
- SPL: - SPL:
. The SplFixedArray::__wakeup() method has been deprecated as it implements . The SplFixedArray::__wakeup() method has been deprecated as it implements
__serialize() and __unserialize() which need to be overwritten instead. __serialize() and __unserialize() which need to be overwritten instead.
. Passing a non-empty string for the $enclosure parameter of:
- SplFileObject::setCsvControl()
- SplFileObject::fputcsv()
- SplFileObject::fgetcsv()
is now deprecated.
RFC: https://wiki.php.net/rfc/deprecations_php_8_4#deprecate_proprietary_csv_escaping_mechanism
- Standard: - Standard:
. Calling stream_context_set_option() with 2 arguments is deprecated. . Calling stream_context_set_option() with 2 arguments is deprecated.
@ -514,6 +520,12 @@ PHP 8.4 UPGRADE NOTES
RFC: https://wiki.php.net/rfc/raising_zero_to_power_of_negative_number RFC: https://wiki.php.net/rfc/raising_zero_to_power_of_negative_number
. Unserializing strings using the uppercase 'S' tag is deprecated. . Unserializing strings using the uppercase 'S' tag is deprecated.
RFC: https://wiki.php.net/rfc/deprecations_php_8_4 RFC: https://wiki.php.net/rfc/deprecations_php_8_4
. Passing a non-empty string for the $enclosure parameter of:
- fputcsv()
- fgetcsv()
- str_getcsv()
is now deprecated.
RFC: https://wiki.php.net/rfc/deprecations_php_8_4#deprecate_proprietary_csv_escaping_mechanism
- XML: - XML:
. The xml_set_object() function has been deprecated. . The xml_set_object() function has been deprecated.

View File

@ -2310,6 +2310,10 @@ PHP_METHOD(SplFileObject, fgetcsv)
if (esc_len == 0) { if (esc_len == 0) {
escape = PHP_CSV_NO_ESCAPE; escape = PHP_CSV_NO_ESCAPE;
} else { } else {
php_error_docref(NULL, E_DEPRECATED, "Passing a non-empty string to the $escape parameter is deprecated since 8.4");
if (UNEXPECTED(EG(exception))) {
RETURN_THROWS();
}
escape = (unsigned char) esc[0]; escape = (unsigned char) esc[0];
} }
} }
@ -2358,6 +2362,10 @@ PHP_METHOD(SplFileObject, fputcsv)
if (esc_len == 0) { if (esc_len == 0) {
escape = PHP_CSV_NO_ESCAPE; escape = PHP_CSV_NO_ESCAPE;
} else { } else {
php_error_docref(NULL, E_DEPRECATED, "Passing a non-empty string to the $escape parameter is deprecated since 8.4");
if (UNEXPECTED(EG(exception))) {
RETURN_THROWS();
}
escape = (unsigned char) esc[0]; escape = (unsigned char) esc[0];
} }
} }
@ -2405,6 +2413,10 @@ PHP_METHOD(SplFileObject, setCsvControl)
if (esc_len == 0) { if (esc_len == 0) {
escape = PHP_CSV_NO_ESCAPE; escape = PHP_CSV_NO_ESCAPE;
} else { } else {
php_error_docref(NULL, E_DEPRECATED, "Passing a non-empty string to the $escape parameter is deprecated since 8.4");
if (UNEXPECTED(EG(exception))) {
RETURN_THROWS();
}
escape = (unsigned char) esc[0]; escape = (unsigned char) esc[0];
} }
} }

View File

@ -13,7 +13,8 @@ var_dump($fo->fgetcsv(',', '"', '"'));
<?php <?php
unlink('SplFileObject__fgetcsv6.csv'); unlink('SplFileObject__fgetcsv6.csv');
?> ?>
--EXPECT-- --EXPECTF--
Deprecated: SplFileObject::fgetcsv(): Passing a non-empty string to the $escape parameter is deprecated since 8.4 in %s on line %d
array(3) { array(3) {
[0]=> [0]=>
string(3) "aaa" string(3) "aaa"

View File

@ -4,16 +4,17 @@ SPL: SplFileObject::setCsvControl basic
Erwin Poeze <erwin.poeze at gmail.com> Erwin Poeze <erwin.poeze at gmail.com>
--FILE-- --FILE--
<?php <?php
file_put_contents('csv_control_data_basic.csv', file_put_contents(
<<<CDATA 'csv_control_data_basic.csv',
'groene appelen'|10 <<<CDATA
'gele bananen'|20 'groene appelen'|10
'rode kersen'|30 'gele bananen'|20
CDATA 'rode kersen'|30
CDATA
); );
$s = new SplFileObject('csv_control_data_basic.csv'); $s = new SplFileObject('csv_control_data_basic.csv');
$s->setFlags(SplFileObject::READ_CSV); $s->setFlags(SplFileObject::READ_CSV);
$s->setCsvControl('|', '\'', '/'); $s->setCsvControl('|', '\'', '');
foreach ($s as $row) { foreach ($s as $row) {
list($fruit, $quantity) = $row; list($fruit, $quantity) = $row;
echo "$fruit : $quantity\n"; echo "$fruit : $quantity\n";

View File

@ -1734,6 +1734,10 @@ PHP_FUNCTION(fputcsv)
if (escape_str_len < 1) { if (escape_str_len < 1) {
escape_char = PHP_CSV_NO_ESCAPE; escape_char = PHP_CSV_NO_ESCAPE;
} else { } else {
php_error_docref(NULL, E_DEPRECATED, "Passing a non-empty string to the $escape parameter is deprecated since 8.4");
if (UNEXPECTED(EG(exception))) {
RETURN_THROWS();
}
/* use first character from string */ /* use first character from string */
escape_char = (unsigned char) *escape_str; escape_char = (unsigned char) *escape_str;
} }
@ -1875,6 +1879,10 @@ PHP_FUNCTION(fgetcsv)
if (escape_str_len < 1) { if (escape_str_len < 1) {
escape = PHP_CSV_NO_ESCAPE; escape = PHP_CSV_NO_ESCAPE;
} else { } else {
php_error_docref(NULL, E_DEPRECATED, "Passing a non-empty string to the $escape parameter is deprecated since 8.4");
if (UNEXPECTED(EG(exception))) {
RETURN_THROWS();
}
escape = (unsigned char) escape_str[0]; escape = (unsigned char) escape_str[0];
} }
} }

View File

@ -5447,25 +5447,40 @@ PHP_FUNCTION(str_getcsv)
{ {
zend_string *str; zend_string *str;
char delim = ',', enc = '"'; char delim = ',', enc = '"';
int esc = (unsigned char) '\\'; int escape = (unsigned char) '\\';
char *delim_str = NULL, *enc_str = NULL, *esc_str = NULL; char *delim_str = NULL, *enc_str = NULL, *escape_str = NULL;
size_t delim_len = 0, enc_len = 0, esc_len = 0; size_t delim_len = 0, enc_len = 0, escape_str_len = 0;
ZEND_PARSE_PARAMETERS_START(1, 4) ZEND_PARSE_PARAMETERS_START(1, 4)
Z_PARAM_STR(str) Z_PARAM_STR(str)
Z_PARAM_OPTIONAL Z_PARAM_OPTIONAL
Z_PARAM_STRING(delim_str, delim_len) Z_PARAM_STRING(delim_str, delim_len)
Z_PARAM_STRING(enc_str, enc_len) Z_PARAM_STRING(enc_str, enc_len)
Z_PARAM_STRING(esc_str, esc_len) Z_PARAM_STRING(escape_str, escape_str_len)
ZEND_PARSE_PARAMETERS_END(); ZEND_PARSE_PARAMETERS_END();
delim = delim_len ? delim_str[0] : delim; delim = delim_len ? delim_str[0] : delim;
enc = enc_len ? enc_str[0] : enc; enc = enc_len ? enc_str[0] : enc;
if (esc_str != NULL) {
esc = esc_len ? (unsigned char) esc_str[0] : PHP_CSV_NO_ESCAPE; // TODO ValueError for delimiter and enclosure string being longer than 1 byte
if (escape_str != NULL) {
if (escape_str_len > 1) {
zend_argument_value_error(4, "must be empty or a single character");
RETURN_THROWS();
}
if (escape_str_len < 1) {
escape = PHP_CSV_NO_ESCAPE;
} else {
php_error_docref(NULL, E_DEPRECATED, "Passing a non-empty string to the $escape parameter is deprecated since 8.4");
if (UNEXPECTED(EG(exception))) {
RETURN_THROWS();
}
escape = (unsigned char) escape_str[0];
}
} }
HashTable *values = php_fgetcsv(NULL, delim, enc, esc, ZSTR_LEN(str), ZSTR_VAL(str)); HashTable *values = php_fgetcsv(NULL, delim, enc, escape, ZSTR_LEN(str), ZSTR_VAL(str));
if (values == NULL) { if (values == NULL) {
values = php_bc_fgetcsv_empty_line(); values = php_bc_fgetcsv_empty_line();
} }

View File

@ -11,6 +11,7 @@ fclose($h);
var_dump($data); var_dump($data);
?> ?>
--EXPECTF-- --EXPECTF--
Deprecated: fgetcsv(): Passing a non-empty string to the $escape parameter is deprecated since 8.4 in %s on line %d
array(2) { array(2) {
[0]=> [0]=>
string(%d) "this element contains the delimiter, and ends with an odd number of string(%d) "this element contains the delimiter, and ends with an odd number of

View File

@ -17,7 +17,8 @@ $string = '"first #' . $utf_1 . $utf_2 . '";"second"';
$fields = str_getcsv($string, ';', '"', "#"); $fields = str_getcsv($string, ';', '"', "#");
var_dump($fields); var_dump($fields);
?> ?>
--EXPECT-- --EXPECTF--
Deprecated: str_getcsv(): Passing a non-empty string to the $escape parameter is deprecated since 8.4 in %s on line %d
array(2) { array(2) {
[0]=> [0]=>
string(11) "first #с؀" string(11) "first #с؀"

View File

@ -22,18 +22,13 @@ $list = array (
13 => 'aaa,"bbb "', 13 => 'aaa,"bbb "',
14 => 'aaa"aaa","bbb"bbb', 14 => 'aaa"aaa","bbb"bbb',
15 => 'aaa"aaa""",bbb', 15 => 'aaa"aaa""",bbb',
16 => 'aaa,"/"bbb,ccc',
17 => 'aaa"/"a","bbb"',
18 => '"/"","aaa"',
19 => '"/""",aaa',
); );
$file = __DIR__ . '/fputcsv_variation15.csv'; $file = __DIR__ . '/fputcsv_variation15.csv';
@unlink($file);
$fp = fopen($file, "w"); $fp = fopen($file, "w");
foreach ($list as $v) { foreach ($list as $v) {
fputcsv($fp, explode(',', $v), ',', '"', '/'); fputcsv($fp, explode(',', $v), ',', '"', '');
} }
fclose($fp); fclose($fp);
@ -46,7 +41,7 @@ echo '$list = ';var_export($res);echo ";\n";
$fp = fopen($file, "r"); $fp = fopen($file, "r");
$res = array(); $res = array();
while($l=fgetcsv($fp, 0, ',', '"', '/')) while($l=fgetcsv($fp, 0, ',', '"', ''))
{ {
$res[] = join(',',$l); $res[] = join(',',$l);
} }
@ -54,8 +49,11 @@ fclose($fp);
echo '$list = ';var_export($res);echo ";\n"; echo '$list = ';var_export($res);echo ";\n";
?>
--CLEAN--
<?php
$file = __DIR__ . '/fputcsv_variation15.csv';
@unlink($file); @unlink($file);
?> ?>
--EXPECT-- --EXPECT--
$list = array ( $list = array (
@ -75,10 +73,6 @@ $list = array (
13 => 'aaa,"""bbb """', 13 => 'aaa,"""bbb """',
14 => '"aaa""aaa""","""bbb""bbb"', 14 => '"aaa""aaa""","""bbb""bbb"',
15 => '"aaa""aaa""""""",bbb', 15 => '"aaa""aaa""""""",bbb',
16 => 'aaa,"""/"bbb",ccc',
17 => '"aaa""/"a""","""bbb"""',
18 => '"""/"""","""aaa"""',
19 => '"""/"""""",aaa',
); );
$list = array ( $list = array (
0 => 'aaa,bbb', 0 => 'aaa,bbb',
@ -97,8 +91,4 @@ $list = array (
13 => 'aaa,"bbb "', 13 => 'aaa,"bbb "',
14 => 'aaa"aaa","bbb"bbb', 14 => 'aaa"aaa","bbb"bbb',
15 => 'aaa"aaa""",bbb', 15 => 'aaa"aaa""",bbb',
16 => 'aaa,"/"bbb,ccc',
17 => 'aaa"/"a","bbb"',
18 => '"/"","aaa"',
19 => '"/""",aaa',
); );

View File

@ -12,7 +12,7 @@ $eol_chars = ['||', '|', '\n', "\n", "\0"];
foreach ($eol_chars as $eol_char) { foreach ($eol_chars as $eol_char) {
$stream = fopen('php://memory', 'w+'); $stream = fopen('php://memory', 'w+');
foreach ($data as $record) { foreach ($data as $record) {
fputcsv($stream, $record, ',', '"', '\\', $eol_char); fputcsv($stream, $record, ',', '"', '', $eol_char);
} }
rewind($stream); rewind($stream);
echo stream_get_contents($stream), "\n"; echo stream_get_contents($stream), "\n";

View File

@ -0,0 +1,73 @@
--TEST--
fputcsv() variant where escape parameter matters
--FILE--
<?php
$list = [
1 => 'aaa,"/"bbb,ccc',
2 => 'aaa"/"a","bbb"',
3 => '"/"","aaa"',
4 => '"/""",aaa',
];
$file = __DIR__ . '/fputcsv_variation18.csv';
$fp = fopen($file, "w");
foreach ($list as $v) {
fputcsv($fp, explode(',', $v), ',', '"', '/');
}
fclose($fp);
$res = file($file);
foreach($res as &$val)
{
$val = substr($val, 0, -1);
}
echo '$list = ';var_export($res);echo ";\n";
$fp = fopen($file, "r");
$res = array();
while($l=fgetcsv($fp, 0, ',', '"', '/'))
{
$res[] = join(',',$l);
}
fclose($fp);
echo '$list = ';var_export($res);echo ";\n";
?>
--CLEAN--
<?php
$file = __DIR__ . '/fputcsv_variation18.csv';
@unlink($file);
?>
--EXPECTF--
Deprecated: fputcsv(): Passing a non-empty string to the $escape parameter is deprecated since 8.4 in %s on line %d
Deprecated: fputcsv(): Passing a non-empty string to the $escape parameter is deprecated since 8.4 in %s on line %d
Deprecated: fputcsv(): Passing a non-empty string to the $escape parameter is deprecated since 8.4 in %s on line %d
Deprecated: fputcsv(): Passing a non-empty string to the $escape parameter is deprecated since 8.4 in %s on line %d
$list = array (
0 => 'aaa,"""/"bbb",ccc',
1 => '"aaa""/"a""","""bbb"""',
2 => '"""/"""","""aaa"""',
3 => '"""/"""""",aaa',
);
Deprecated: fgetcsv(): Passing a non-empty string to the $escape parameter is deprecated since 8.4 in %s on line %d
Deprecated: fgetcsv(): Passing a non-empty string to the $escape parameter is deprecated since 8.4 in %s on line %d
Deprecated: fgetcsv(): Passing a non-empty string to the $escape parameter is deprecated since 8.4 in %s on line %d
Deprecated: fgetcsv(): Passing a non-empty string to the $escape parameter is deprecated since 8.4 in %s on line %d
Deprecated: fgetcsv(): Passing a non-empty string to the $escape parameter is deprecated since 8.4 in %s on line %d
$list = array (
0 => 'aaa,"/"bbb,ccc',
1 => 'aaa"/"a","bbb"',
2 => '"/"","aaa"',
3 => '"/""",aaa',
);

View File

@ -5,10 +5,13 @@ GH-12151 (str_getcsv ending with escape zero segfualt)
var_export(str_getcsv("y","","y","\000")); var_export(str_getcsv("y","","y","\000"));
var_export(str_getcsv("\0yy","y","y","\0")); var_export(str_getcsv("\0yy","y","y","\0"));
?> ?>
--EXPECT-- --EXPECTF--
Deprecated: str_getcsv(): Passing a non-empty string to the $escape parameter is deprecated since 8.4 in %s on line %d
array ( array (
0 => '' . "\0" . '', 0 => '' . "\0" . '',
)array ( )
Deprecated: str_getcsv(): Passing a non-empty string to the $escape parameter is deprecated since 8.4 in %s on line %d
array (
0 => '' . "\0" . '', 0 => '' . "\0" . '',
1 => '' . "\0" . '', 1 => '' . "\0" . '',
) )

View File

@ -18,8 +18,6 @@ var_dump(str_getcsv('.foo..bar.', '.', '.', '.'));
print "-----\n"; print "-----\n";
var_dump(str_getcsv('.foo. .bar.', ' ', '.', '.')); var_dump(str_getcsv('.foo. .bar.', ' ', '.', '.'));
print "-----\n"; print "-----\n";
var_dump(str_getcsv('1foo1 1bar111', ' ', '1 ', '\ '));
print "-----\n";
var_dump(str_getcsv('.foo . . bar .', ' ', '.', '')); var_dump(str_getcsv('.foo . . bar .', ' ', '.', ''));
print "-----\n"; print "-----\n";
var_dump(str_getcsv('" "" "', ' ')); var_dump(str_getcsv('" "" "', ' '));
@ -28,7 +26,7 @@ var_dump(str_getcsv(''));
print "-----\n"; print "-----\n";
?> ?>
--EXPECT-- --EXPECTF--
array(3) { array(3) {
[0]=> [0]=>
string(1) "f" string(1) "f"
@ -61,6 +59,8 @@ array(2) {
string(3) "bar" string(3) "bar"
} }
----- -----
Deprecated: str_getcsv(): Passing a non-empty string to the $escape parameter is deprecated since 8.4 in %s on line %d
array(3) { array(3) {
[0]=> [0]=>
string(2) "f." string(2) "f."
@ -70,11 +70,15 @@ array(3) {
string(4) "-|-." string(4) "-|-."
} }
----- -----
Deprecated: str_getcsv(): Passing a non-empty string to the $escape parameter is deprecated since 8.4 in %s on line %d
array(1) { array(1) {
[0]=> [0]=>
string(7) "foo.bar" string(7) "foo.bar"
} }
----- -----
Deprecated: str_getcsv(): Passing a non-empty string to the $escape parameter is deprecated since 8.4 in %s on line %d
array(2) { array(2) {
[0]=> [0]=>
string(3) "foo" string(3) "foo"
@ -82,13 +86,6 @@ array(2) {
string(3) "bar" string(3) "bar"
} }
----- -----
array(2) {
[0]=>
string(3) "foo"
[1]=>
string(4) "bar1"
}
-----
array(2) { array(2) {
[0]=> [0]=>
string(5) "foo " string(5) "foo "

View File

@ -0,0 +1,15 @@
--TEST--
str_getcsv(): Invalid arguments
--FILE--
<?php
// string input[, string delimiter[, string enclosure[, string escape]]]
try {
var_dump(str_getcsv('csv_string', ',', '"', 'enclosure'));
} catch (Throwable $e) {
echo $e::class, ': ', $e->getMessage(), PHP_EOL;
}
?>
--EXPECT--
ValueError: str_getcsv(): Argument #4 ($escape) must be empty or a single character