From 32e478b9fc0c677ada30e9dc13b6983d7154550d Mon Sep 17 00:00:00 2001 From: Marcus Boerger Date: Sun, 26 Sep 2004 21:55:22 +0000 Subject: [PATCH] - Add fputcsv() (David Sklar) --- ext/standard/basic_functions.c | 1 + ext/standard/file.c | 103 ++++++++++++++++++++++++++ ext/standard/file.h | 1 + ext/standard/tests/file/fputcsv.phpt | 107 +++++++++++++++++++++++++++ 4 files changed, 212 insertions(+) create mode 100755 ext/standard/tests/file/fputcsv.phpt diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c index c9449ee492..dd4299a9a3 100644 --- a/ext/standard/basic_functions.c +++ b/ext/standard/basic_functions.c @@ -602,6 +602,7 @@ function_entry basic_functions[] = { PHP_FE(stream_copy_to_stream, NULL) PHP_FE(stream_get_contents, NULL) PHP_FE(fgetcsv, NULL) + PHP_FE(fputcsv, NULL) PHP_FE(flock, third_arg_force_ref) PHP_FE(get_meta_tags, NULL) PHP_FE(stream_set_write_buffer, NULL) diff --git a/ext/standard/file.c b/ext/standard/file.c index f8e08ade00..835f26893e 100644 --- a/ext/standard/file.c +++ b/ext/standard/file.c @@ -35,6 +35,7 @@ #include "php_open_temporary_file.h" #include "ext/standard/basic_functions.h" #include "php_ini.h" +#include "php_smart_str.h" #include #include @@ -1715,6 +1716,108 @@ quit_loop: return ptr; } +#define FPUTCSV_FLD_CHK(c) php_memnstr(Z_STRVAL_PP(field), c, 1, Z_STRVAL_PP(field) + Z_STRLEN_PP(field)) + +/* {{{ proto int fputcsv(resource fp, array fields [, string delimiter [, string enclosure]]) + Format line as CSV and write to file pointer */ +PHP_FUNCTION(fputcsv) +{ + char delimiter = ','; /* allow this to be set as parameter */ + char enclosure = '"'; /* allow this to be set as parameter */ + php_stream *stream; + int ret; + zval *fp = NULL, *fields = NULL, **field = NULL; + char *delimiter_str = NULL, *enclosure_str = NULL; + int delimiter_str_len, enclosure_str_len; + HashPosition pos; + int count, i = 0; + char enc_double[3]; + smart_str csvline = {0}; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|ass", + &fp, &fields, &delimiter_str, &delimiter_str_len, + &enclosure_str, &enclosure_str_len) == FAILURE) { + return; + } + + if (delimiter_str != NULL) { + /* Make sure that there is at least one character in string */ + if (delimiter_str_len < 1) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "delimiter must be a character"); + RETURN_FALSE; + } else if (delimiter_str_len > 1) { + php_error_docref(NULL TSRMLS_CC, E_NOTICE, "delimiter must be a single character"); + } + + /* use first character from string */ + delimiter = *delimiter_str; + } + + if (enclosure_str != NULL) { + if (enclosure_str_len < 1) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "enclosure must be a character"); + RETURN_FALSE; + } else if (enclosure_str_len > 1) { + php_error_docref(NULL TSRMLS_CC, E_NOTICE, "enclosure must be a single character"); + } + /* use first character from string */ + enclosure = *enclosure_str; + } + + PHP_STREAM_TO_ZVAL(stream, &fp); + + enc_double[0] = enclosure; + enc_double[1] = enclosure; + enc_double[2] = '\0'; + count = zend_hash_num_elements(Z_ARRVAL_P(fields)); + zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(fields), &pos); + while (zend_hash_get_current_data_ex(Z_ARRVAL_P(fields), (void **) &field, &pos) == SUCCESS) { + if (Z_TYPE_PP(field) != IS_STRING) { + SEPARATE_ZVAL(field); + convert_to_string(*field); + } + /* 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("\n") || + FPUTCSV_FLD_CHK("\r") || FPUTCSV_FLD_CHK(" ") || FPUTCSV_FLD_CHK("\t") + ) { + zval enclosed_field; + smart_str_appendl(&csvline, &enclosure, 1); + + php_char_to_str_ex(Z_STRVAL_PP(field), Z_STRLEN_PP(field), + enclosure, enc_double, 2, &enclosed_field, 0, NULL); + smart_str_appendl(&csvline, Z_STRVAL(enclosed_field), Z_STRLEN(enclosed_field)); + zval_dtor(&enclosed_field); + + smart_str_appendl(&csvline, &enclosure, 1); + } else { + smart_str_appendl(&csvline, Z_STRVAL_PP(field), Z_STRLEN_PP(field)); + } + + if (++i != count) { + smart_str_appendl(&csvline, &delimiter, 1); + } + zend_hash_move_forward_ex(Z_ARRVAL_P(fields), &pos); + } + + smart_str_appendc(&csvline, '\n'); + smart_str_0(&csvline); + + if (!PG(magic_quotes_runtime)) { + ret = php_stream_write(stream, csvline.c, csvline.len); + } else { + char *buffer = estrndup(csvline.c, csvline.len); + int len = csvline.len; + php_stripslashes(buffer, &len TSRMLS_CC); + ret = php_stream_write(stream, buffer, len); + efree(buffer); + } + + smart_str_free(&csvline); + + RETURN_LONG(ret); +} +/* }}} */ + /* {{{ proto array fgetcsv(resource fp [,int length [, string delimiter [, string enclosure]]]) Get line from file pointer and parse for CSV fields */ PHP_FUNCTION(fgetcsv) diff --git a/ext/standard/file.h b/ext/standard/file.h index dfcf79561c..3f76cbf211 100644 --- a/ext/standard/file.h +++ b/ext/standard/file.h @@ -39,6 +39,7 @@ PHPAPI PHP_FUNCTION(fgets); PHP_FUNCTION(fscanf); PHPAPI PHP_FUNCTION(fgetss); PHP_FUNCTION(fgetcsv); +PHP_FUNCTION(fputcsv); PHPAPI PHP_FUNCTION(fwrite); PHPAPI PHP_FUNCTION(fflush); PHPAPI PHP_FUNCTION(rewind); diff --git a/ext/standard/tests/file/fputcsv.phpt b/ext/standard/tests/file/fputcsv.phpt new file mode 100755 index 0000000000..6d919563e9 --- /dev/null +++ b/ext/standard/tests/file/fputcsv.phpt @@ -0,0 +1,107 @@ +--TEST-- +various fputcsv() functionality tests +--INI-- +magic_quotes_runtime=0 +--FILE-- + 'aaa,bbb', + 1 => 'aaa,"bbb"', + 2 => '"aaa","bbb"', + 3 => 'aaa,bbb', + 4 => '"aaa",bbb', + 5 => '"aaa", "bbb"', + 6 => ',', + 7 => 'aaa,', + 8 => ',"aaa"', + 9 => '"",""', + 10 => '"""""",', + 11 => '""""",aaa', + 12 => 'aaa,bbb ', + 13 => 'aaa,"bbb "', + 14 => 'aaa"aaa","bbb"bbb', + 15 => 'aaa"aaa""",bbb', + 16 => 'aaa,"\\"bbb,ccc', + 17 => 'aaa"\\"a","bbb"', + 18 => '"\\"","aaa"', + 19 => '"\\""",aaa', +); + +$file = dirname(__FILE__) . 'fgetcsv.csv'; +@unlink($file); + +$fp = fopen($file, "w"); +foreach ($list as $v) { + fputcsv($fp, split(',', $v)); +} +fclose($fp); + +$res = file($file); +foreach($res as &$val) +{ + $val = substr($val, 0, -1); +} +echo '$list = ';var_export($res);echo ";\n"; + +$fp = fopen($file, "r"); +$res = array(); +while($l=fgetcsv($fp)) +{ + $res[] = join(',',$l); +} +fclose($fp); + +echo '$list = ';var_export($res);echo ";\n"; + +@unlink($file); + +?> +===DONE=== + +--EXPECT-- +$list = array ( + 0 => 'aaa,bbb', + 1 => 'aaa,"""bbb"""', + 2 => '"""aaa""","""bbb"""', + 3 => 'aaa,bbb', + 4 => '"""aaa""",bbb', + 5 => '"""aaa"""," ""bbb"""', + 6 => ',', + 7 => 'aaa,', + 8 => ',"""aaa"""', + 9 => '"""""",""""""', + 10 => '"""""""""""""",', + 11 => '"""""""""""",aaa', + 12 => 'aaa,"bbb "', + 13 => 'aaa,"""bbb """', + 14 => '"aaa""aaa""","""bbb""bbb"', + 15 => '"aaa""aaa""""""",bbb', + 16 => 'aaa,"""\\""bbb",ccc', + 17 => '"aaa""\\""a""","""bbb"""', + 18 => '"""\\""""","""aaa"""', + 19 => '"""\\""""""",aaa', +); +$list = array ( + 0 => 'aaa,bbb', + 1 => 'aaa,"bbb"', + 2 => '"aaa","bbb"', + 3 => 'aaa,bbb', + 4 => '"aaa",bbb', + 5 => '"aaa", "bbb"', + 6 => ',', + 7 => 'aaa,', + 8 => ',"aaa"', + 9 => '"",""', + 10 => '"""""",', + 11 => '""""",aaa', + 12 => 'aaa,bbb ', + 13 => 'aaa,"bbb "', + 14 => 'aaa"aaa","bbb"bbb', + 15 => 'aaa"aaa""",bbb', + 16 => 'aaa,"\\"bbb,ccc', + 17 => 'aaa"\\"a","bbb"', + 18 => '"\\"","aaa"', + 19 => '"\\""",aaa', +); +===DONE=== -- 2.50.1