Update fputcsv() to escape all characters equally.
authorAdam Harvey <aharvey@php.net>
Tue, 15 Jan 2013 07:17:45 +0000 (15:17 +0800)
committerAdam Harvey <aharvey@php.net>
Tue, 15 Jan 2013 07:17:45 +0000 (15:17 +0800)
At present, backslashes have special case handling within fputcsv(): when one
is encountered within a field that's being escaped, escaping stops until the
next instance of the enclosure character is hit.  This can result in malformed
CSV.

Fixes bug #43225 (fputcsv incorrectly handles cells ending in \ followed by ").

NEWS
ext/standard/file.c
ext/standard/tests/file/fputcsv.phpt
ext/standard/tests/file/fputcsv_bug43225.phpt [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index e78af2339d82cd3fcdcc45ad6e16b6e1ea42860d..a7c2fa47e9c21602515024b562266e3d7e03ad2e 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -12,6 +12,8 @@ PHP                                                                        NEWS
 - Core
   . Fixed bug #63943 (Bad warning text from strpos() on empty needle).
     (Laruence)
+  . Fixed bug #43225 (fputcsv incorrectly handles cells ending in \ followed
+    by "). (Adam)
 
 - cURL extension:
   . Fixed bug (segfault due to libcurl connection caching). (Pierrick)
index 8b18155cf89d8b8007081c01db1ee12e88e0dd39..fa85bf1b3a9235463742b03b02b8c77e56b5d974 100644 (file)
@@ -1953,7 +1953,6 @@ PHP_FUNCTION(fputcsv)
 {
        char delimiter = ',';   /* allow this to be set as parameter */
        char enclosure = '"';   /* allow this to be set as parameter */
-       const char escape_char = '\\';
        php_stream *stream;
        int ret;
        zval *fp = NULL, *fields = NULL, **field_tmp = NULL, field;
@@ -2008,24 +2007,19 @@ PHP_FUNCTION(fputcsv)
                /* enclose a field that contains a delimiter, an enclosure character, or a newline */
                if (FPUTCSV_FLD_CHK(delimiter) ||
                        FPUTCSV_FLD_CHK(enclosure) ||
-                       FPUTCSV_FLD_CHK(escape_char) ||
                        FPUTCSV_FLD_CHK('\n') ||
                        FPUTCSV_FLD_CHK('\r') ||
                        FPUTCSV_FLD_CHK('\t') ||
+                       FPUTCSV_FLD_CHK('\\') ||
                        FPUTCSV_FLD_CHK(' ')
                ) {
                        char *ch = Z_STRVAL(field);
                        char *end = ch + Z_STRLEN(field);
-                       int escaped = 0;
 
                        smart_str_appendc(&csvline, enclosure);
                        while (ch < end) {
-                               if (*ch == escape_char) {
-                                       escaped = 1;
-                               } else if (!escaped && *ch == enclosure) {
+                               if (*ch == enclosure) {
                                        smart_str_appendc(&csvline, enclosure);
-                               } else {
-                                       escaped = 0;
                                }
                                smart_str_appendc(&csvline, *ch);
                                ch++;
index 63c41509bdd90c4ab532ad99f162924b937ccf10..d71f777143c40624dd268818d2f4749dc94197d2 100644 (file)
@@ -44,7 +44,7 @@ echo '$list = ';var_export($res);echo ";\n";
 
 $fp = fopen($file, "r");
 $res = array();
-while($l=fgetcsv($fp))
+while($l=fgetcsv($fp, 0, ',', '"', '"'))
 {
        $res[] = join(',',$l);
 }
@@ -75,10 +75,10 @@ $list = array (
   13 => 'aaa,"""bbb   """',
   14 => '"aaa""aaa""","""bbb""bbb"',
   15 => '"aaa""aaa""""""",bbb',
-  16 => 'aaa,"""\\"bbb",ccc',
-  17 => '"aaa""\\"a""","""bbb"""',
-  18 => '"""\\"""","""aaa"""',
-  19 => '"""\\"""""",aaa',
+  16 => 'aaa,"""\\""bbb",ccc',
+  17 => '"aaa""\\""a""","""bbb"""',
+  18 => '"""\\""""","""aaa"""',
+  19 => '"""\\""""""",aaa',
 );
 $list = array (
   0 => 'aaa,bbb',
diff --git a/ext/standard/tests/file/fputcsv_bug43225.phpt b/ext/standard/tests/file/fputcsv_bug43225.phpt
new file mode 100644 (file)
index 0000000..1de3b5f
--- /dev/null
@@ -0,0 +1,20 @@
+--TEST--
+fputcsv(): bug #43225 (fputcsv incorrectly handles cells ending in \ followed by ")
+--FILE--
+<?php
+
+$row = array(
+    'a\\"',
+    'bbb',
+);
+
+$file = dirname(__FILE__) . 'fgetcsv_bug43225.csv';
+$fp = fopen($file, 'w');
+fputcsv($fp, $row);
+fclose($fp);
+readfile($file);
+unlink($file);
+
+?>
+--EXPECT--
+"a\""",bbb