summaryrefslogtreecommitdiff
path: root/ext
diff options
context:
space:
mode:
authorDavid Soria Parra <dsp@php.net>2007-10-03 10:44:32 +0000
committerDavid Soria Parra <dsp@php.net>2007-10-03 10:44:32 +0000
commitd4e8fa62c6db480f5926661302b71e7f0a8dca3c (patch)
treebcc4f44c3c4d6b08c732c1d2173325859c2b76d3 /ext
parenteb0c56ada1e2d6f4155c32c23cea56502de7751e (diff)
downloadphp-git-d4e8fa62c6db480f5926661302b71e7f0a8dca3c.tar.gz
MFH: Add an escape parameter to fgetcsv to satisfy rfc4180 and bug #40501.
[DOC] 5th parameter available since PHP 5.3+
Diffstat (limited to 'ext')
-rwxr-xr-xext/spl/spl_directory.c43
-rwxr-xr-xext/spl/spl_directory.h1
-rw-r--r--ext/standard/file.c32
-rw-r--r--ext/standard/file.h2
-rw-r--r--ext/standard/tests/file/bug40501.csv2
-rw-r--r--ext/standard/tests/file/bug40501.phpt20
-rw-r--r--ext/standard/tests/file/fgetcsv_error.phpt9
7 files changed, 82 insertions, 27 deletions
diff --git a/ext/spl/spl_directory.c b/ext/spl/spl_directory.c
index ccf69e2409..beef441c02 100755
--- a/ext/spl/spl_directory.c
+++ b/ext/spl/spl_directory.c
@@ -1589,7 +1589,7 @@ static int spl_filesystem_file_call(spl_filesystem_object *intern, zend_function
spl_filesystem_file_call(intern, func_ptr, pass_num_args, return_value, arg2 TSRMLS_CC); \
}
-static int spl_filesystem_file_read_csv(spl_filesystem_object *intern, char delimiter, char enclosure, zval *return_value TSRMLS_DC) /* {{{ */
+static int spl_filesystem_file_read_csv(spl_filesystem_object *intern, char delimiter, char enclosure, char escape, zval *return_value TSRMLS_DC) /* {{{ */
{
int ret = SUCCESS;
@@ -1606,7 +1606,7 @@ static int spl_filesystem_file_read_csv(spl_filesystem_object *intern, char deli
}
ALLOC_INIT_ZVAL(intern->u.file.current_zval);
- php_fgetcsv(intern->u.file.stream, delimiter, enclosure, buf_len, buf, intern->u.file.current_zval TSRMLS_CC);
+ php_fgetcsv(intern->u.file.stream, delimiter, enclosure, escape, buf_len, buf, intern->u.file.current_zval TSRMLS_CC);
if (return_value) {
if (Z_TYPE_P(return_value) != IS_NULL) {
zval_dtor(return_value);
@@ -1632,7 +1632,7 @@ static int spl_filesystem_file_read_line_ex(zval * this_ptr, spl_filesystem_obje
return FAILURE;
}
if (intern->flags & SPL_FILE_OBJECT_READ_CSV) {
- return spl_filesystem_file_read_csv(intern, intern->u.file.delimiter, intern->u.file.enclosure, NULL TSRMLS_CC);
+ return spl_filesystem_file_read_csv(intern, intern->u.file.delimiter, intern->u.file.enclosure, intern->u.file.escape, NULL TSRMLS_CC);
} else {
zend_call_method_with_0_params(&this_ptr, Z_OBJCE_P(getThis()), &intern->u.file.func_getCurr, "getCurrentLine", &retval);
}
@@ -1943,18 +1943,25 @@ SPL_METHOD(SplFileObject, func_name) \
}
/* }}} */
-/* {{{ proto array SplFileObject::fgetcsv([string delimiter [, string enclosure]])
+/* {{{ proto array SplFileObject::fgetcsv([string delimiter [, string enclosure [, escape = '\\']]])
Return current line as csv */
SPL_METHOD(SplFileObject, fgetcsv)
{
spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
- char delimiter = intern->u.file.delimiter, enclosure = intern->u.file.enclosure;
- char *delim, *enclo;
- int d_len, e_len;
+ char delimiter = intern->u.file.delimiter, enclosure = intern->u.file.enclosure, escape = intern->u.file.escape;
+ char *delim, *enclo, *esc;
+ int d_len, e_len, esc_len;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|ss", &delim, &d_len, &enclo, &e_len) == SUCCESS) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sss", &delim, &d_len, &enclo, &e_len, &esc, &esc_len) == SUCCESS) {
switch(ZEND_NUM_ARGS())
{
+ case 3:
+ if (esc_len != 1) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "escape must be a character");
+ RETURN_FALSE;
+ }
+ escape = esc[0];
+ /* no break */
case 2:
if (e_len != 1) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "enclosure must be a character");
@@ -1972,23 +1979,30 @@ SPL_METHOD(SplFileObject, fgetcsv)
case 0:
break;
}
- spl_filesystem_file_read_csv(intern, delimiter, enclosure, return_value TSRMLS_CC);
+ spl_filesystem_file_read_csv(intern, delimiter, enclosure, escape, return_value TSRMLS_CC);
}
}
/* }}} */
-/* {{{ proto void SplFileObject::setCsvControl([string delimiter = ',' [, string enclosure = '"']])
+/* {{{ proto void SplFileObject::setCsvControl([string delimiter = ',' [, string enclosure = '"' [, string escape = '\\']]])
Set the delimiter and enclosure character used in fgetcsv */
SPL_METHOD(SplFileObject, setCsvControl)
{
spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
- char delimiter = ',', enclosure = '"';
- char *delim, *enclo;
- int d_len, e_len;
+ char delimiter = ',', enclosure = '"', escape='\\';
+ char *delim, *enclo, *esc;
+ int d_len, e_len, esc_len;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|ss", &delim, &d_len, &enclo, &e_len) == SUCCESS) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sss", &delim, &d_len, &enclo, &e_len, &esc, &esc_len) == SUCCESS) {
switch(ZEND_NUM_ARGS())
{
+ case 3:
+ if (esc_len != 1) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "escape must be a character");
+ RETURN_FALSE;
+ }
+ escape = esc[0];
+ /* no break */
case 2:
if (e_len != 1) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "enclosure must be a character");
@@ -2008,6 +2022,7 @@ SPL_METHOD(SplFileObject, setCsvControl)
}
intern->u.file.delimiter = delimiter;
intern->u.file.enclosure = enclosure;
+ intern->u.file.escape = escape;
}
}
/* }}} */
diff --git a/ext/spl/spl_directory.h b/ext/spl/spl_directory.h
index 172c400ce1..caf3a18167 100755
--- a/ext/spl/spl_directory.h
+++ b/ext/spl/spl_directory.h
@@ -84,6 +84,7 @@ struct _spl_filesystem_object {
zend_function *func_getCurr;
char delimiter;
char enclosure;
+ char escape;
} file;
} u;
};
diff --git a/ext/standard/file.c b/ext/standard/file.c
index c54ce62313..ce4e854d7f 100644
--- a/ext/standard/file.c
+++ b/ext/standard/file.c
@@ -2013,12 +2013,14 @@ PHP_FUNCTION(fputcsv)
}
/* }}} */
-/* {{{ proto array fgetcsv(resource fp [,int length [, string delimiter [, string enclosure]]])
+/* {{{ proto array fgetcsv(resource fp [,int length [, string delimiter [, string enclosure [, string escape]]]])
Get line from file pointer and parse for CSV fields */
PHP_FUNCTION(fgetcsv)
{
char delimiter = ','; /* allow this to be set as parameter */
char enclosure = '"'; /* allow this to be set as parameter */
+ char escape = '\\';
+
/* first section exactly as php_fgetss */
long len = 0;
@@ -2032,10 +2034,13 @@ PHP_FUNCTION(fgetcsv)
int delimiter_str_len = 0;
char *enclosure_str = NULL;
int enclosure_str_len = 0;
+ char *escape_str = NULL;
+ int escape_str_len = 0;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|Zss",
- &fd, &len_zv, &delimiter_str, &delimiter_str_len,
- &enclosure_str, &enclosure_str_len) == FAILURE) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|Zsss",
+ &fd, &len_zv, &delimiter_str, &delimiter_str_len,
+ &enclosure_str, &enclosure_str_len,
+ &escape_str, &escape_str_len) == FAILURE) {
return;
}
@@ -2064,6 +2069,17 @@ PHP_FUNCTION(fgetcsv)
enclosure = enclosure_str[0];
}
+ if (escape_str != NULL) {
+ if (escape_str_len < 1) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "escape must be character");
+ RETURN_FALSE;
+ } else if (escape_str_len > 1) {
+ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "escape must be a single character");
+ }
+
+ escape = escape_str[0];
+ }
+
if (len_zv != NULL && Z_TYPE_PP(len_zv) != IS_NULL) {
convert_to_long_ex(len_zv);
len = Z_LVAL_PP(len_zv);
@@ -2092,14 +2108,13 @@ PHP_FUNCTION(fgetcsv)
}
}
- php_fgetcsv(stream, delimiter, enclosure, buf_len, buf, return_value TSRMLS_CC);
+ php_fgetcsv(stream, delimiter, enclosure, escape, buf_len, buf, return_value TSRMLS_CC);
}
/* }}} */
-PHPAPI void php_fgetcsv(php_stream *stream, char delimiter, char enclosure, size_t buf_len, char *buf, zval *return_value TSRMLS_DC) /* {{{ */
+PHPAPI void php_fgetcsv(php_stream *stream, char delimiter, char enclosure, char escape_char, size_t buf_len, char *buf, zval *return_value TSRMLS_DC) /* {{{ */
{
char *temp, *tptr, *bptr, *line_end, *limit;
- const char escape_char = '\\';
size_t temp_len, line_end_len;
int inc_len;
@@ -2250,7 +2265,8 @@ PHPAPI void php_fgetcsv(php_stream *stream, char delimiter, char enclosure, size
state = 0;
break;
default:
- if (*bptr == escape_char) {
+ if ((escape_char == enclosure && *bptr == escape_char && *(bptr+1) == escape_char)
+ || (escape_char != enclosure && *bptr == escape_char)) {
state = 1;
} else if (*bptr == enclosure) {
state = 2;
diff --git a/ext/standard/file.h b/ext/standard/file.h
index 2b6fe2f2d1..38cdca8a7f 100644
--- a/ext/standard/file.h
+++ b/ext/standard/file.h
@@ -78,7 +78,7 @@ PHPAPI int php_copy_file(char *src, char *dest TSRMLS_DC);
PHPAPI int php_copy_file_ex(char *src, char *dest, int src_chk TSRMLS_DC);
PHPAPI int php_mkdir_ex(char *dir, long mode, int options TSRMLS_DC);
PHPAPI int php_mkdir(char *dir, long mode TSRMLS_DC);
-PHPAPI void php_fgetcsv(php_stream *stream, char delimiter, char enclosure, size_t buf_len, char *buf, zval *return_value TSRMLS_DC);
+PHPAPI void php_fgetcsv(php_stream *stream, char delimiter, char enclosure, char escape_char, size_t buf_len, char *buf, zval *return_value TSRMLS_DC);
#define META_DEF_BUFSIZE 8192
diff --git a/ext/standard/tests/file/bug40501.csv b/ext/standard/tests/file/bug40501.csv
new file mode 100644
index 0000000000..c786ed98e8
--- /dev/null
+++ b/ext/standard/tests/file/bug40501.csv
@@ -0,0 +1,2 @@
+"this element contains the delimiter, and ends with an odd number of
+backslashes (ex: 1)\",and it isn't the last element$ \ No newline at end of file
diff --git a/ext/standard/tests/file/bug40501.phpt b/ext/standard/tests/file/bug40501.phpt
new file mode 100644
index 0000000000..110533fb82
--- /dev/null
+++ b/ext/standard/tests/file/bug40501.phpt
@@ -0,0 +1,20 @@
+--TEST--
+Bug #40501 (fgetcsv() can't handle trailing odd number of backslashes)
+--FILE--
+<?php
+$file = dirname(__FILE__).'/bug40501.csv';
+
+$h = fopen($file, 'r');
+$data = fgetcsv($h, NULL, ',', '"', '"');
+fclose($h);
+
+var_dump($data);
+?>
+--EXPECT--
+array(2) {
+ [0]=>
+ string(88) "this element contains the delimiter, and ends with an odd number of
+backslashes (ex: 1)\"
+ [1]=>
+ string(30) "and it isn't the last element$"
+} \ No newline at end of file
diff --git a/ext/standard/tests/file/fgetcsv_error.phpt b/ext/standard/tests/file/fgetcsv_error.phpt
index c3ace9ab87..e2db9f8730 100644
--- a/ext/standard/tests/file/fgetcsv_error.phpt
+++ b/ext/standard/tests/file/fgetcsv_error.phpt
@@ -3,7 +3,7 @@ Test fgetcsv() function : error conditions
--FILE--
<?php
/*
- Prototype: array fgetcsv ( resource $handle [, int $length [, string $delimiter [, string $enclosure]]] );
+ Prototype: array fgetcsv ( resource $handle [, int $length [, string $delimiter [, string $enclosure [, string $escape]]]] );
Description: Gets line from file pointer and parse for CSV fields
*/
@@ -18,7 +18,8 @@ $fp = fopen(__FILE__, "r");
$len = 1024;
$delim = ";";
$enclosure ="\"";
-var_dump( fgetcsv($fp, $len, $delim, $enclosure, $fp) );
+$escape = '"';
+var_dump( fgetcsv($fp, $len, $delim, $enclosure, $escape, $fp) );
fclose($fp);
// test invalid arguments : non-resources
@@ -35,7 +36,7 @@ $invalid_args = array (
for($loop_counter = 1; $loop_counter <= count($invalid_args); $loop_counter++) {
echo "-- Iteration $loop_counter --\n";
var_dump( fgetcsv($invalid_args[$loop_counter - 1]) ); // with default args
- var_dump( fgetcsv($invalid_args[$loop_counter - 1], $len, $delim, $enclosure) ); // all args specified
+ var_dump( fgetcsv($invalid_args[$loop_counter - 1], $len, $delim, $enclosure, $escape) ); // all args specified
}
echo "Done\n";
@@ -47,7 +48,7 @@ Warning: fgetcsv() expects at least 1 parameter, 0 given in %s on line %d
NULL
-- Testing fgetcsv() with more than expected number of arguments --
-Warning: fgetcsv() expects at most 4 parameters, 5 given in %s on line %d
+Warning: fgetcsv() expects at most 5 parameters, 6 given in %s on line %d
NULL
-- Testing fgetcsv() with invalid arguments --
-- Iteration 1 --