Skip to content

Make CSV deprecation less annoying to deal with #15569

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions UPGRADING
Original file line number Diff line number Diff line change
Expand Up @@ -581,11 +581,11 @@ PHP 8.4 UPGRADE NOTES
- SPL:
. The SplFixedArray::__wakeup() method has been deprecated as it implements
__serialize() and __unserialize() which need to be overwritten instead.
. Passing a non-empty string for the $enclosure parameter of:
. Using the default value for $escape parameter of:
- SplFileObject::setCsvControl()
- SplFileObject::fputcsv()
- SplFileObject::fgetcsv()
is now deprecated.
is now deprecated. It must be passed explicitly either positionally or via named arguments.
RFC: https://wiki.php.net/rfc/deprecations_php_8_4#deprecate_proprietary_csv_escaping_mechanism

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

- XML:
Expand Down
8 changes: 4 additions & 4 deletions ext/phar/tests/phar_oo_008.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class MyCSVFile extends SplFileObject
{
function current(): array|false
{
return parent::fgetcsv(',', '"');
return parent::fgetcsv(',', '"', escape: '');
}
}

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

echo "===4===\n";
$v->rewind();
while(!$v->eof())
{
$l = $v->fgetcsv();
$l = $v->fgetcsv(escape: '');
echo $v->key() . "=>" . join('|', $l) . "\n";
}

Expand All @@ -66,7 +66,7 @@ class MyCSVFile2 extends SplFileObject
function getCurrentLine(): string
{
echo __METHOD__ . "\n";
return implode('|', parent::fgetcsv(',', '"'));
return implode('|', parent::fgetcsv(',', '"', escape: ''));
}
}

Expand Down
102 changes: 45 additions & 57 deletions ext/spl/spl_directory.c
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,7 @@ static zend_result spl_filesystem_file_open(spl_filesystem_object *intern, bool
intern->u.file.delimiter = ',';
intern->u.file.enclosure = '"';
intern->u.file.escape = (unsigned char) '\\';
intern->u.file.is_escape_default = true;

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

Expand Down Expand Up @@ -2273,16 +2274,33 @@ PHP_METHOD(SplFileObject, getChildren)
/* return NULL */
} /* }}} */

static int spl_csv_enclosure_param_handling(const zend_string* escape_str, const spl_filesystem_object *intern, uint32_t arg_num)
{
if (escape_str == NULL) {
if (intern->u.file.is_escape_default) {
php_error_docref(NULL, E_DEPRECATED, "the $escape parameter must be provided,"
" as its default value will change,"
" either explicitly or via SplFileObject::setCsvControl()");
if (UNEXPECTED(EG(exception))) {
return PHP_CSV_ESCAPE_ERROR;
}
}
return intern->u.file.escape;
} else {
return php_csv_handle_escape_argument(escape_str, arg_num);
}
}

/* {{{ Return current line as CSV */
PHP_METHOD(SplFileObject, fgetcsv)
{
spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
char delimiter = intern->u.file.delimiter, enclosure = intern->u.file.enclosure;
int escape = intern->u.file.escape;
char *delim = NULL, *enclo = NULL, *esc = NULL;
size_t d_len = 0, e_len = 0, esc_len = 0;
char *delim = NULL, *enclo = NULL;
size_t d_len = 0, e_len = 0;
zend_string *escape_str = NULL;

if (zend_parse_parameters(ZEND_NUM_ARGS(), "|sss", &delim, &d_len, &enclo, &e_len, &esc, &esc_len) == FAILURE) {
if (zend_parse_parameters(ZEND_NUM_ARGS(), "|ssS", &delim, &d_len, &enclo, &e_len, &escape_str) == FAILURE) {
RETURN_THROWS();
}

Expand All @@ -2302,23 +2320,12 @@ PHP_METHOD(SplFileObject, fgetcsv)
}
enclosure = enclo[0];
}
if (esc) {
if (esc_len > 1) {
zend_argument_value_error(3, "must be empty or a single character");
RETURN_THROWS();
}
if (esc_len == 0) {
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) esc[0];
}
int escape_char = spl_csv_enclosure_param_handling(escape_str, intern, 3);
if (escape_char == PHP_CSV_ESCAPE_ERROR) {
RETURN_THROWS();
}

if (spl_filesystem_file_read_csv(intern, delimiter, enclosure, escape, return_value, true) == FAILURE) {
if (spl_filesystem_file_read_csv(intern, delimiter, enclosure, escape_char, return_value, true) == FAILURE) {
RETURN_FALSE;
}
}
Expand All @@ -2329,14 +2336,14 @@ PHP_METHOD(SplFileObject, fputcsv)
{
spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
char delimiter = intern->u.file.delimiter, enclosure = intern->u.file.enclosure;
int escape = intern->u.file.escape;
char *delim = NULL, *enclo = NULL, *esc = NULL;
size_t d_len = 0, e_len = 0, esc_len = 0;
char *delim = NULL, *enclo = NULL;
size_t d_len = 0, e_len = 0;
zend_long ret;
zval *fields = NULL;
zend_string *escape_str = NULL;
zend_string *eol = NULL;

if (zend_parse_parameters(ZEND_NUM_ARGS(), "a|sssS", &fields, &delim, &d_len, &enclo, &e_len, &esc, &esc_len, &eol) == FAILURE) {
if (zend_parse_parameters(ZEND_NUM_ARGS(), "a|ssSS", &fields, &delim, &d_len, &enclo, &e_len, &escape_str, &eol) == FAILURE) {
RETURN_THROWS();
}

Expand All @@ -2354,23 +2361,12 @@ PHP_METHOD(SplFileObject, fputcsv)
}
enclosure = enclo[0];
}
if (esc) {
if (esc_len > 1) {
zend_argument_value_error(4, "must be empty or a single character");
RETURN_THROWS();
}
if (esc_len == 0) {
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) esc[0];
}
int escape_char = spl_csv_enclosure_param_handling(escape_str, intern, 4);
if (escape_char == PHP_CSV_ESCAPE_ERROR) {
RETURN_THROWS();
}

ret = php_fputcsv(intern->u.file.stream, fields, delimiter, enclosure, escape, eol);
ret = php_fputcsv(intern->u.file.stream, fields, delimiter, enclosure, escape_char, eol);
if (ret < 0) {
RETURN_FALSE;
}
Expand All @@ -2383,11 +2379,11 @@ PHP_METHOD(SplFileObject, setCsvControl)
{
spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
char delimiter = ',', enclosure = '"';
int escape = (unsigned char) '\\';
char *delim = NULL, *enclo = NULL, *esc = NULL;
size_t d_len = 0, e_len = 0, esc_len = 0;
char *delim = NULL, *enclo = NULL;
size_t d_len = 0, e_len = 0;
zend_string *escape_str = NULL;

if (zend_parse_parameters(ZEND_NUM_ARGS(), "|sss", &delim, &d_len, &enclo, &e_len, &esc, &esc_len) == FAILURE) {
if (zend_parse_parameters(ZEND_NUM_ARGS(), "|ssS", &delim, &d_len, &enclo, &e_len, &escape_str) == FAILURE) {
RETURN_THROWS();
}

Expand All @@ -2405,25 +2401,17 @@ PHP_METHOD(SplFileObject, setCsvControl)
}
enclosure = enclo[0];
}
if (esc) {
if (esc_len > 1) {
zend_argument_value_error(3, "must be empty or a single character");
RETURN_THROWS();
}
if (esc_len == 0) {
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) esc[0];
}
int escape_char = php_csv_handle_escape_argument(escape_str, 3);
if (escape_char == PHP_CSV_ESCAPE_ERROR) {
RETURN_THROWS();
}
if (escape_str != NULL) {
intern->u.file.is_escape_default = false;
}

intern->u.file.delimiter = delimiter;
intern->u.file.enclosure = enclosure;
intern->u.file.escape = escape;
intern->u.file.escape = escape_char;
}
/* }}} */

Expand Down
1 change: 1 addition & 0 deletions ext/spl/spl_directory.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ struct _spl_filesystem_object {
char delimiter;
char enclosure;
int escape;
bool is_escape_default;
} file;
} u;
zend_object std;
Expand Down
17 changes: 11 additions & 6 deletions ext/spl/tests/SplFileObject/SplFileObject_fgetcsv_basic.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,20 @@ SplFileObject::fgetcsv default path
--FILE--
<?php
$fp = fopen('SplFileObject__fgetcsv1.csv', 'w+');
fputcsv($fp, array(
'field1',
'field2',
'field3',
5
));
fputcsv(
$fp,
[
'field1',
'field2',
'field3',
5,
],
escape: '',
);
fclose($fp);

$fo = new SplFileObject('SplFileObject__fgetcsv1.csv');
$fo->setCsvControl(escape: '');
var_dump($fo->fgetcsv());
?>
--CLEAN--
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
--TEST--
SplFileObject::fgetcsv with alternative delimiter
SplFileObject::fgetcsv with alternative separator
--FILE--
<?php
$fp = fopen('SplFileObject__fgetcsv2.csv', 'w+');
fputcsv($fp, array(
'field1',
'field2',
'field3',
5
), '|');
fputcsv(
$fp,
[
'field1',
'field2',
'field3',
5,
],
separator: '|',
escape: '',
);
fclose($fp);

$fo = new SplFileObject('SplFileObject__fgetcsv2.csv');
$fo->setCsvControl(escape: '');
var_dump($fo->fgetcsv('|'));
?>
--CLEAN--
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
--TEST--
SplFileObject::fgetcsv with alternative delimiter
SplFileObject::fgetcsv() delimiter error
--FILE--
<?php
$fp = fopen('SplFileObject__fgetcsv3.csv', 'w+');
fputcsv($fp, array(
'field1',
'field2',
'field3',
5
), '|');
fputcsv(
$fp,
[
'field1',
'field2',
'field3',
5,
],
escape: '',
);
fclose($fp);

$fo = new SplFileObject('SplFileObject__fgetcsv3.csv');
$fo->setCsvControl(escape: '');
try {
var_dump($fo->fgetcsv('invalid'));
} catch (ValueError $e) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
--TEST--
SplFileObject::fgetcsv with alternative delimiter
SplFileObject::fgetcsv with alternative enclosure
--FILE--
<?php
$fp = fopen('SplFileObject__fgetcsv4.csv', 'w+');
fputcsv($fp, array(
'field1',
'field2',
'field3',
5
), ',', '"');
fputcsv(
$fp,
[
'field1',
'field2',
'field3',
5,
],
enclosure: '"',
escape: '',
);
fclose($fp);

$fo = new SplFileObject('SplFileObject__fgetcsv4.csv');
var_dump($fo->fgetcsv(',', '"'));
$fo->setCsvControl(escape: '');
var_dump($fo->fgetcsv(enclosure: '"'));
?>
--CLEAN--
<?php
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,24 @@
--TEST--
SplFileObject::fgetcsv with alternative delimiter
SplFileObject::fgetcsv() enclosure error
--FILE--
<?php
$fp = fopen('SplFileObject__fgetcsv5.csv', 'w+');
fputcsv($fp, array(
'field1',
'field2',
'field3',
5
), ',', '"');
fputcsv(
$fp,
[
'field1',
'field2',
'field3',
5,
],
escape: '',
);
fclose($fp);

$fo = new SplFileObject('SplFileObject__fgetcsv5.csv');
$fo->setCsvControl(escape: '');
try {
var_dump($fo->fgetcsv(',', 'invalid'));
var_dump($fo->fgetcsv(enclosure: 'invalid'));
} catch (ValueError $e) {
echo $e->getMessage(), "\n";
}
Expand Down
Loading
Loading