From 5d4561240a95a7cbea5ad5b6aca00b8ca95e135e Mon Sep 17 00:00:00 2001 From: Mike Jolley Date: Tue, 10 Apr 2018 18:08:56 +0100 Subject: [PATCH] Handle escape characters for fputcsv --- includes/export/abstract-wc-csv-exporter.php | 33 +++++++++++++++++-- .../import/class-wc-product-csv-importer.php | 5 +-- 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/includes/export/abstract-wc-csv-exporter.php b/includes/export/abstract-wc-csv-exporter.php index c629dd509cd..496a71aed60 100644 --- a/includes/export/abstract-wc-csv-exporter.php +++ b/includes/export/abstract-wc-csv-exporter.php @@ -245,7 +245,7 @@ abstract class WC_CSV_Exporter { $export_row[] = $this->format_data( $column_name ); } - fputcsv( $buffer, $export_row ); // @codingStandardsIgnoreLine + $this->fputcsv( $buffer, $export_row ); return ob_get_clean(); } @@ -299,7 +299,8 @@ abstract class WC_CSV_Exporter { } } - fputcsv( $buffer, $export_row ); // @codingStandardsIgnoreLine + $this->fputcsv( $buffer, $export_row ); + ++ $this->exported_row_count; } @@ -456,4 +457,32 @@ abstract class WC_CSV_Exporter { return implode( ', ', $values_to_implode ); } + + /** + * Write to the CSV file, ensuring escaping works across versions of + * PHP. + * + * PHP 5.5.4 uses '\' as the default escape character. This is not RFC-4180 compliant. + * \0 disables the escape character. + * + * @see https://bugs.php.net/bug.php?id=43225 + * @see https://bugs.php.net/bug.php?id=50686 + * @see https://github.com/woocommerce/woocommerce/issues/19514 + * @since 3.4.0 + * @param resource $buffer Resource we are writing to. + * @param array $export_row Row to export. + */ + protected function fputcsv( $buffer, $export_row ) { + if ( version_compare( PHP_VERSION, '5.5.4', '<' ) ) { + ob_start(); + $temp = fopen( 'php://output', 'w' ); // @codingStandardsIgnoreLine + fputcsv( $temp, $export_row, ",", '"' ); // @codingStandardsIgnoreLine + fclose( $temp ); // @codingStandardsIgnoreLine + $row = ob_get_clean(); + $row = str_replace( '\\"', '\\""', $row ); + fwrite( $buffer, $row ); // @codingStandardsIgnoreLine + } else { + fputcsv( $buffer, $export_row, ",", '"', "\0" ); // @codingStandardsIgnoreLine + } + } } diff --git a/includes/import/class-wc-product-csv-importer.php b/includes/import/class-wc-product-csv-importer.php index 8e3c646cdd8..622c7c6d07e 100644 --- a/includes/import/class-wc-product-csv-importer.php +++ b/includes/import/class-wc-product-csv-importer.php @@ -46,6 +46,7 @@ class WC_Product_CSV_Importer extends WC_Product_Importer { 'delimiter' => ',', // CSV delimiter. 'prevent_timeouts' => true, // Check memory and time usage and abort if reaching limit. 'enclosure' => '"', // The character used to wrap text in the CSV. + 'escape' => "\0", // PHP uses '\' as the default escape character. This is not RFC-4180 compliant. This disables the escape character. ); $this->params = wp_parse_args( $params, $default_args ); @@ -65,7 +66,7 @@ class WC_Product_CSV_Importer extends WC_Product_Importer { $handle = fopen( $this->file, 'r' ); // @codingStandardsIgnoreLine. if ( false !== $handle ) { - $this->raw_keys = fgetcsv( $handle, 0, $this->params['delimiter'], $this->params['enclosure'] ); + $this->raw_keys = version_compare( PHP_VERSION, '5.3', '>=' ) ? fgetcsv( $handle, 0, $this->params['delimiter'], $this->params['enclosure'], $this->params['escape'] ) : fgetcsv( $handle, 0, $this->params['delimiter'], $this->params['enclosure'] ); // @codingStandardsIgnoreLine // Remove BOM signature from the first item. if ( isset( $this->raw_keys[0] ) ) { @@ -77,7 +78,7 @@ class WC_Product_CSV_Importer extends WC_Product_Importer { } while ( 1 ) { - $row = fgetcsv( $handle, 0, $this->params['delimiter'], $this->params['enclosure'] ); + $row = version_compare( PHP_VERSION, '5.3', '>=' ) ? fgetcsv( $handle, 0, $this->params['delimiter'], $this->params['enclosure'], $this->params['escape'] ) : fgetcsv( $handle, 0, $this->params['delimiter'], $this->params['enclosure'] ); // @codingStandardsIgnoreLine if ( false !== $row ) { $this->raw_data[] = $row;