- Add fputcsv() (David Sklar)

This commit is contained in:
Marcus Boerger 2004-09-26 21:55:22 +00:00
parent 5177691e4a
commit 32e478b9fc
4 changed files with 212 additions and 0 deletions

View file

@ -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)

View file

@ -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 <stdio.h>
#include <stdlib.h>
@ -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)

View file

@ -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);

View file

@ -0,0 +1,107 @@
--TEST--
various fputcsv() functionality tests
--INI--
magic_quotes_runtime=0
--FILE--
<?php
$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',
);
$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===
<?php exit(0); ?>
--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===