Skip to content

Commit f756b96

Browse files
authored
Make CSV deprecation less annoying to deal with (#15569)
1 parent e73a855 commit f756b96

File tree

88 files changed

+408
-341
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

88 files changed

+408
-341
lines changed

UPGRADING

+4-4
Original file line numberDiff line numberDiff line change
@@ -581,11 +581,11 @@ PHP 8.4 UPGRADE NOTES
581581
- SPL:
582582
. The SplFixedArray::__wakeup() method has been deprecated as it implements
583583
__serialize() and __unserialize() which need to be overwritten instead.
584-
. Passing a non-empty string for the $enclosure parameter of:
584+
. Using the default value for $escape parameter of:
585585
- SplFileObject::setCsvControl()
586586
- SplFileObject::fputcsv()
587587
- SplFileObject::fgetcsv()
588-
is now deprecated.
588+
is now deprecated. It must be passed explicitly either positionally or via named arguments.
589589
RFC: https://wiki.php.net/rfc/deprecations_php_8_4#deprecate_proprietary_csv_escaping_mechanism
590590

591591
- Standard:
@@ -595,11 +595,11 @@ PHP 8.4 UPGRADE NOTES
595595
RFC: https://wiki.php.net/rfc/raising_zero_to_power_of_negative_number
596596
. Unserializing strings using the uppercase 'S' tag is deprecated.
597597
RFC: https://wiki.php.net/rfc/deprecations_php_8_4#unserialize_s_s_tag
598-
. Passing a non-empty string for the $enclosure parameter of:
598+
. Using the default value for $escape parameter of:
599599
- fputcsv()
600600
- fgetcsv()
601601
- str_getcsv()
602-
is now deprecated.
602+
is now deprecated. It must be passed explicitly either positionally or via named arguments.
603603
RFC: https://wiki.php.net/rfc/deprecations_php_8_4#deprecate_proprietary_csv_escaping_mechanism
604604

605605
- XML:

ext/phar/tests/phar_oo_008.phpt

+4-4
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ class MyCSVFile extends SplFileObject
3333
{
3434
function current(): array|false
3535
{
36-
return parent::fgetcsv(',', '"');
36+
return parent::fgetcsv(',', '"', escape: '');
3737
}
3838
}
3939

@@ -44,14 +44,14 @@ $v = $phar['a.csv'];
4444
echo "===3===\n";
4545
while(!$v->eof())
4646
{
47-
echo $v->key() . "=>" . join('|', $v->fgetcsv()) . "\n";
47+
echo $v->key() . "=>" . join('|', $v->fgetcsv(escape: '')) . "\n";
4848
}
4949

5050
echo "===4===\n";
5151
$v->rewind();
5252
while(!$v->eof())
5353
{
54-
$l = $v->fgetcsv();
54+
$l = $v->fgetcsv(escape: '');
5555
echo $v->key() . "=>" . join('|', $l) . "\n";
5656
}
5757

@@ -66,7 +66,7 @@ class MyCSVFile2 extends SplFileObject
6666
function getCurrentLine(): string
6767
{
6868
echo __METHOD__ . "\n";
69-
return implode('|', parent::fgetcsv(',', '"'));
69+
return implode('|', parent::fgetcsv(',', '"', escape: ''));
7070
}
7171
}
7272

ext/spl/spl_directory.c

+45-57
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,7 @@ static zend_result spl_filesystem_file_open(spl_filesystem_object *intern, bool
365365
intern->u.file.delimiter = ',';
366366
intern->u.file.enclosure = '"';
367367
intern->u.file.escape = (unsigned char) '\\';
368+
intern->u.file.is_escape_default = true;
368369

369370
intern->u.file.func_getCurr = zend_hash_str_find_ptr(&intern->std.ce->function_table, "getcurrentline", sizeof("getcurrentline") - 1);
370371

@@ -2273,16 +2274,33 @@ PHP_METHOD(SplFileObject, getChildren)
22732274
/* return NULL */
22742275
} /* }}} */
22752276

2277+
static int spl_csv_enclosure_param_handling(const zend_string* escape_str, const spl_filesystem_object *intern, uint32_t arg_num)
2278+
{
2279+
if (escape_str == NULL) {
2280+
if (intern->u.file.is_escape_default) {
2281+
php_error_docref(NULL, E_DEPRECATED, "the $escape parameter must be provided,"
2282+
" as its default value will change,"
2283+
" either explicitly or via SplFileObject::setCsvControl()");
2284+
if (UNEXPECTED(EG(exception))) {
2285+
return PHP_CSV_ESCAPE_ERROR;
2286+
}
2287+
}
2288+
return intern->u.file.escape;
2289+
} else {
2290+
return php_csv_handle_escape_argument(escape_str, arg_num);
2291+
}
2292+
}
2293+
22762294
/* {{{ Return current line as CSV */
22772295
PHP_METHOD(SplFileObject, fgetcsv)
22782296
{
22792297
spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
22802298
char delimiter = intern->u.file.delimiter, enclosure = intern->u.file.enclosure;
2281-
int escape = intern->u.file.escape;
2282-
char *delim = NULL, *enclo = NULL, *esc = NULL;
2283-
size_t d_len = 0, e_len = 0, esc_len = 0;
2299+
char *delim = NULL, *enclo = NULL;
2300+
size_t d_len = 0, e_len = 0;
2301+
zend_string *escape_str = NULL;
22842302

2285-
if (zend_parse_parameters(ZEND_NUM_ARGS(), "|sss", &delim, &d_len, &enclo, &e_len, &esc, &esc_len) == FAILURE) {
2303+
if (zend_parse_parameters(ZEND_NUM_ARGS(), "|ssS", &delim, &d_len, &enclo, &e_len, &escape_str) == FAILURE) {
22862304
RETURN_THROWS();
22872305
}
22882306

@@ -2302,23 +2320,12 @@ PHP_METHOD(SplFileObject, fgetcsv)
23022320
}
23032321
enclosure = enclo[0];
23042322
}
2305-
if (esc) {
2306-
if (esc_len > 1) {
2307-
zend_argument_value_error(3, "must be empty or a single character");
2308-
RETURN_THROWS();
2309-
}
2310-
if (esc_len == 0) {
2311-
escape = PHP_CSV_NO_ESCAPE;
2312-
} else {
2313-
php_error_docref(NULL, E_DEPRECATED, "Passing a non-empty string to the $escape parameter is deprecated since 8.4");
2314-
if (UNEXPECTED(EG(exception))) {
2315-
RETURN_THROWS();
2316-
}
2317-
escape = (unsigned char) esc[0];
2318-
}
2323+
int escape_char = spl_csv_enclosure_param_handling(escape_str, intern, 3);
2324+
if (escape_char == PHP_CSV_ESCAPE_ERROR) {
2325+
RETURN_THROWS();
23192326
}
23202327

2321-
if (spl_filesystem_file_read_csv(intern, delimiter, enclosure, escape, return_value, true) == FAILURE) {
2328+
if (spl_filesystem_file_read_csv(intern, delimiter, enclosure, escape_char, return_value, true) == FAILURE) {
23222329
RETURN_FALSE;
23232330
}
23242331
}
@@ -2329,14 +2336,14 @@ PHP_METHOD(SplFileObject, fputcsv)
23292336
{
23302337
spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
23312338
char delimiter = intern->u.file.delimiter, enclosure = intern->u.file.enclosure;
2332-
int escape = intern->u.file.escape;
2333-
char *delim = NULL, *enclo = NULL, *esc = NULL;
2334-
size_t d_len = 0, e_len = 0, esc_len = 0;
2339+
char *delim = NULL, *enclo = NULL;
2340+
size_t d_len = 0, e_len = 0;
23352341
zend_long ret;
23362342
zval *fields = NULL;
2343+
zend_string *escape_str = NULL;
23372344
zend_string *eol = NULL;
23382345

2339-
if (zend_parse_parameters(ZEND_NUM_ARGS(), "a|sssS", &fields, &delim, &d_len, &enclo, &e_len, &esc, &esc_len, &eol) == FAILURE) {
2346+
if (zend_parse_parameters(ZEND_NUM_ARGS(), "a|ssSS", &fields, &delim, &d_len, &enclo, &e_len, &escape_str, &eol) == FAILURE) {
23402347
RETURN_THROWS();
23412348
}
23422349

@@ -2354,23 +2361,12 @@ PHP_METHOD(SplFileObject, fputcsv)
23542361
}
23552362
enclosure = enclo[0];
23562363
}
2357-
if (esc) {
2358-
if (esc_len > 1) {
2359-
zend_argument_value_error(4, "must be empty or a single character");
2360-
RETURN_THROWS();
2361-
}
2362-
if (esc_len == 0) {
2363-
escape = PHP_CSV_NO_ESCAPE;
2364-
} else {
2365-
php_error_docref(NULL, E_DEPRECATED, "Passing a non-empty string to the $escape parameter is deprecated since 8.4");
2366-
if (UNEXPECTED(EG(exception))) {
2367-
RETURN_THROWS();
2368-
}
2369-
escape = (unsigned char) esc[0];
2370-
}
2364+
int escape_char = spl_csv_enclosure_param_handling(escape_str, intern, 4);
2365+
if (escape_char == PHP_CSV_ESCAPE_ERROR) {
2366+
RETURN_THROWS();
23712367
}
23722368

2373-
ret = php_fputcsv(intern->u.file.stream, fields, delimiter, enclosure, escape, eol);
2369+
ret = php_fputcsv(intern->u.file.stream, fields, delimiter, enclosure, escape_char, eol);
23742370
if (ret < 0) {
23752371
RETURN_FALSE;
23762372
}
@@ -2383,11 +2379,11 @@ PHP_METHOD(SplFileObject, setCsvControl)
23832379
{
23842380
spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
23852381
char delimiter = ',', enclosure = '"';
2386-
int escape = (unsigned char) '\\';
2387-
char *delim = NULL, *enclo = NULL, *esc = NULL;
2388-
size_t d_len = 0, e_len = 0, esc_len = 0;
2382+
char *delim = NULL, *enclo = NULL;
2383+
size_t d_len = 0, e_len = 0;
2384+
zend_string *escape_str = NULL;
23892385

2390-
if (zend_parse_parameters(ZEND_NUM_ARGS(), "|sss", &delim, &d_len, &enclo, &e_len, &esc, &esc_len) == FAILURE) {
2386+
if (zend_parse_parameters(ZEND_NUM_ARGS(), "|ssS", &delim, &d_len, &enclo, &e_len, &escape_str) == FAILURE) {
23912387
RETURN_THROWS();
23922388
}
23932389

@@ -2405,25 +2401,17 @@ PHP_METHOD(SplFileObject, setCsvControl)
24052401
}
24062402
enclosure = enclo[0];
24072403
}
2408-
if (esc) {
2409-
if (esc_len > 1) {
2410-
zend_argument_value_error(3, "must be empty or a single character");
2411-
RETURN_THROWS();
2412-
}
2413-
if (esc_len == 0) {
2414-
escape = PHP_CSV_NO_ESCAPE;
2415-
} else {
2416-
php_error_docref(NULL, E_DEPRECATED, "Passing a non-empty string to the $escape parameter is deprecated since 8.4");
2417-
if (UNEXPECTED(EG(exception))) {
2418-
RETURN_THROWS();
2419-
}
2420-
escape = (unsigned char) esc[0];
2421-
}
2404+
int escape_char = php_csv_handle_escape_argument(escape_str, 3);
2405+
if (escape_char == PHP_CSV_ESCAPE_ERROR) {
2406+
RETURN_THROWS();
2407+
}
2408+
if (escape_str != NULL) {
2409+
intern->u.file.is_escape_default = false;
24222410
}
24232411

24242412
intern->u.file.delimiter = delimiter;
24252413
intern->u.file.enclosure = enclosure;
2426-
intern->u.file.escape = escape;
2414+
intern->u.file.escape = escape_char;
24272415
}
24282416
/* }}} */
24292417

ext/spl/spl_directory.h

+1
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ struct _spl_filesystem_object {
8282
char delimiter;
8383
char enclosure;
8484
int escape;
85+
bool is_escape_default;
8586
} file;
8687
} u;
8788
zend_object std;

ext/spl/tests/SplFileObject/SplFileObject_fgetcsv_basic.phpt

+11-6
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,20 @@ SplFileObject::fgetcsv default path
33
--FILE--
44
<?php
55
$fp = fopen('SplFileObject__fgetcsv1.csv', 'w+');
6-
fputcsv($fp, array(
7-
'field1',
8-
'field2',
9-
'field3',
10-
5
11-
));
6+
fputcsv(
7+
$fp,
8+
[
9+
'field1',
10+
'field2',
11+
'field3',
12+
5,
13+
],
14+
escape: '',
15+
);
1216
fclose($fp);
1317

1418
$fo = new SplFileObject('SplFileObject__fgetcsv1.csv');
19+
$fo->setCsvControl(escape: '');
1520
var_dump($fo->fgetcsv());
1621
?>
1722
--CLEAN--

ext/spl/tests/SplFileObject/SplFileObject_fgetcsv_delimiter_basic.phpt

+13-7
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,23 @@
11
--TEST--
2-
SplFileObject::fgetcsv with alternative delimiter
2+
SplFileObject::fgetcsv with alternative separator
33
--FILE--
44
<?php
55
$fp = fopen('SplFileObject__fgetcsv2.csv', 'w+');
6-
fputcsv($fp, array(
7-
'field1',
8-
'field2',
9-
'field3',
10-
5
11-
), '|');
6+
fputcsv(
7+
$fp,
8+
[
9+
'field1',
10+
'field2',
11+
'field3',
12+
5,
13+
],
14+
separator: '|',
15+
escape: '',
16+
);
1217
fclose($fp);
1318

1419
$fo = new SplFileObject('SplFileObject__fgetcsv2.csv');
20+
$fo->setCsvControl(escape: '');
1521
var_dump($fo->fgetcsv('|'));
1622
?>
1723
--CLEAN--

ext/spl/tests/SplFileObject/SplFileObject_fgetcsv_delimiter_error.phpt

+12-7
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,22 @@
11
--TEST--
2-
SplFileObject::fgetcsv with alternative delimiter
2+
SplFileObject::fgetcsv() delimiter error
33
--FILE--
44
<?php
55
$fp = fopen('SplFileObject__fgetcsv3.csv', 'w+');
6-
fputcsv($fp, array(
7-
'field1',
8-
'field2',
9-
'field3',
10-
5
11-
), '|');
6+
fputcsv(
7+
$fp,
8+
[
9+
'field1',
10+
'field2',
11+
'field3',
12+
5,
13+
],
14+
escape: '',
15+
);
1216
fclose($fp);
1317

1418
$fo = new SplFileObject('SplFileObject__fgetcsv3.csv');
19+
$fo->setCsvControl(escape: '');
1520
try {
1621
var_dump($fo->fgetcsv('invalid'));
1722
} catch (ValueError $e) {

ext/spl/tests/SplFileObject/SplFileObject_fgetcsv_enclosure_basic.phpt

+14-8
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,24 @@
11
--TEST--
2-
SplFileObject::fgetcsv with alternative delimiter
2+
SplFileObject::fgetcsv with alternative enclosure
33
--FILE--
44
<?php
55
$fp = fopen('SplFileObject__fgetcsv4.csv', 'w+');
6-
fputcsv($fp, array(
7-
'field1',
8-
'field2',
9-
'field3',
10-
5
11-
), ',', '"');
6+
fputcsv(
7+
$fp,
8+
[
9+
'field1',
10+
'field2',
11+
'field3',
12+
5,
13+
],
14+
enclosure: '"',
15+
escape: '',
16+
);
1217
fclose($fp);
1318

1419
$fo = new SplFileObject('SplFileObject__fgetcsv4.csv');
15-
var_dump($fo->fgetcsv(',', '"'));
20+
$fo->setCsvControl(escape: '');
21+
var_dump($fo->fgetcsv(enclosure: '"'));
1622
?>
1723
--CLEAN--
1824
<?php

ext/spl/tests/SplFileObject/SplFileObject_fgetcsv_enclosure_error.phpt

+13-8
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,24 @@
11
--TEST--
2-
SplFileObject::fgetcsv with alternative delimiter
2+
SplFileObject::fgetcsv() enclosure error
33
--FILE--
44
<?php
55
$fp = fopen('SplFileObject__fgetcsv5.csv', 'w+');
6-
fputcsv($fp, array(
7-
'field1',
8-
'field2',
9-
'field3',
10-
5
11-
), ',', '"');
6+
fputcsv(
7+
$fp,
8+
[
9+
'field1',
10+
'field2',
11+
'field3',
12+
5,
13+
],
14+
escape: '',
15+
);
1216
fclose($fp);
1317

1418
$fo = new SplFileObject('SplFileObject__fgetcsv5.csv');
19+
$fo->setCsvControl(escape: '');
1520
try {
16-
var_dump($fo->fgetcsv(',', 'invalid'));
21+
var_dump($fo->fgetcsv(enclosure: 'invalid'));
1722
} catch (ValueError $e) {
1823
echo $e->getMessage(), "\n";
1924
}

0 commit comments

Comments
 (0)