FAQ
Attached is a patch that implements fputcsv() as a complement to fgetcsv().

There are two things that still need improvement:

- It adds "\n" as a newline onto the end of each line. I think it would
be better to add a platform-specific line ending.

- It is not mbstring-aware.

Any suggestions for fixing these things (or other issues) would be
appreciated.

Thanks,
David

Search Discussions

  • Andi Gutmans at Apr 11, 2004 at 5:07 pm
    How about using PHP_EOL?

    At 12:33 PM 4/11/2004 -0400, David Sklar wrote:
    Attached is a patch that implements fputcsv() as a complement to fgetcsv().

    There are two things that still need improvement:

    - It adds "\n" as a newline onto the end of each line. I think it would be
    better to add a platform-specific line ending.

    - It is not mbstring-aware.

    Any suggestions for fixing these things (or other issues) would be
    appreciated.

    Thanks,
    David


    Index: ext/standard/basic_functions.c
    ===================================================================
    RCS file: /repository/php-src/ext/standard/basic_functions.c,v
    retrieving revision 1.662
    diff -u -B -b -r1.662 basic_functions.c
    --- ext/standard/basic_functions.c 3 Apr 2004 09:51:57 -0000 1.662
    +++ ext/standard/basic_functions.c 11 Apr 2004 16:31:33 -0000
    @@ -596,6 +596,7 @@
    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)
    Index: ext/standard/file.h
    ===================================================================
    RCS file: /repository/php-src/ext/standard/file.h,v
    retrieving revision 1.88
    diff -u -B -b -r1.88 file.h
    --- ext/standard/file.h 8 Jan 2004 17:32:51 -0000 1.88
    +++ ext/standard/file.h 11 Apr 2004 16:31:33 -0000
    @@ -39,6 +39,7 @@
    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);
    Index: ext/standard/file.c
    ===================================================================
    RCS file: /repository/php-src/ext/standard/file.c,v
    retrieving revision 1.380
    diff -u -B -b -r1.380 file.c
    --- ext/standard/file.c 25 Feb 2004 20:16:26 -0000 1.380
    +++ ext/standard/file.c 11 Apr 2004 16:31:35 -0000
    @@ -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>
    @@ -1704,6 +1705,112 @@
    return ptr;
    }

    +/* {{{ 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;
    + int delimiter_str_len = 0;
    + char *enclosure_str = NULL;
    + int enclosure_str_len = 0;
    + char *buffer = NULL;
    + int csvline_len = 0;
    + HashPosition pos;
    + int count = 0, 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;
    + }
    +
    + /* use first character from string */
    + delimiter[0] = delimiter_str[0];
    + }
    +
    + if (enclosure_str != NULL) {
    + if (enclosure_str_len < 1) {
    + php_error_docref(NULL TSRMLS_CC, E_WARNING, "enclosure must
    be a character");
    + RETURN_FALSE;
    + }
    + /* use first character from string */
    + enclosure[0] = enclosure_str[0];
    + }
    +
    + PHP_STREAM_TO_ZVAL(stream, &fp);
    +
    + enc_double[0] = enc_double[1] = enclosure[0];
    + 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 ((*field)->type != IS_STRING) {
    + SEPARATE_ZVAL(field);
    + convert_to_string(*field);
    + }
    + /* enclose a field that contains a delimiter, an enclosure
    + character, or a newline */
    + if (php_memnstr(Z_STRVAL_PP(field), delimiter, 1,
    Z_STRVAL_PP(field) + Z_STRLEN_PP(field)) ||
    + php_memnstr(Z_STRVAL_PP(field), enclosure, 1,
    Z_STRVAL_PP(field) + Z_STRLEN_PP(field)) ||
    + php_memnstr(Z_STRVAL_PP(field), "\n", 1, Z_STRVAL_PP(field) +
    Z_STRLEN_PP(field)) ||
    + php_memnstr(Z_STRVAL_PP(field), "\r", 1, Z_STRVAL_PP(field) +
    Z_STRLEN_PP(field))) {
    +
    + smart_str_appendl(&csvline, enclosure, 1);
    +
    + {
    + zval enclosed_field;
    + php_char_to_str_ex(Z_STRVAL_PP(field),
    Z_STRLEN_PP(field), enclosure[0],
    + 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);
    + }
    +
    + /* XXX: this should be platform-specific */
    + smart_str_appendc(&csvline, '\n');
    +
    + smart_str_0(&csvline);
    +
    + if (PG(magic_quotes_runtime)) {
    + buffer = estrndup(csvline.c, csvline.len);
    + php_stripslashes(buffer, &csvline_len TSRMLS_CC);
    + } else {
    + csvline_len = csvline.len;
    + }
    +
    + ret = php_stream_write(stream, buffer ? buffer : csvline.c,
    csvline_len);
    +
    + if (buffer) {
    + 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)

    --
    PHP Internals - PHP Runtime Development Mailing List
    To unsubscribe, visit: http://www.php.net/unsub.php
  • David Sklar at Apr 11, 2004 at 5:30 pm
    Perfect, thanks. I knew there was a #define lurking around somewhere
    that was \r\n, \r, or \n, as appropriate, I just didn't know what it was
    called.

    David

    Andi Gutmans wrote:
    How about using PHP_EOL?

    At 12:33 PM 4/11/2004 -0400, David Sklar wrote:

    Attached is a patch that implements fputcsv() as a complement to
    fgetcsv().

    There are two things that still need improvement:

    - It adds "\n" as a newline onto the end of each line. I think it
    would be better to add a platform-specific line ending.

    - It is not mbstring-aware.

    Any suggestions for fixing these things (or other issues) would be
    appreciated.

    Thanks,
    David
  • Derick Rethans at Apr 12, 2004 at 10:06 am

    On Sun, 11 Apr 2004, David Sklar wrote:

    Perfect, thanks. I knew there was a #define lurking around somewhere
    that was \r\n, \r, or \n, as appropriate, I just didn't know what it was
    called.
    I don't think it's a good idea to do this as it causes different output
    on different systems. This means that writing test casesis harder, and
    that users will have to take care of those issues themselves (if they
    don't use fgetcsv() to read the data in of course).

    I'd say we should stick to \r\n like Ilia proposed.

    Derick
  • David Sklar at Apr 12, 2004 at 5:56 pm
    Thanks for the line-ending feedback everyone, and Ilia for the code
    cleanup. Attached is a diff that implements the (cleaned up) function
    and a test file for tests/basic.

    If someone with appropriate karma could commit these, that'd be great.

    Thanks,

    David
  • Ilia Alshanetsky at Apr 11, 2004 at 5:56 pm
    Hi David,

    I've made a slight revision to your proposed patch with adds the following
    changes:

    1) Raise notice when delimeter or enclosure are >1 character long.
    2) Fixed a crash with custom delimeters & enclosures.
    3) Made fields with spaces and tabs be enclosed.
    4) Simplify the code & made it abide by PHP's CS.

    As far as the line terminators, I think your initial usage of '\n' is the best
    approach. Most applications capable of reading csv files will support \n
    without further input from the user regardless of the system's EOL. Although,
    \r\n is equally well supported, the only one which is not terribly well
    supported is \r especially on some Win32 applications. Since the idea would
    be to generate a universally usable csv file, \n seems (to me) like the best
    choice.

    Ilia
    On April 11, 2004 12:33 pm, David Sklar wrote:
    Attached is a patch that implements fputcsv() as a complement to fgetcsv().

    There are two things that still need improvement:

    - It adds "\n" as a newline onto the end of each line. I think it would
    be better to add a platform-specific line ending.

    - It is not mbstring-aware.

    Any suggestions for fixing these things (or other issues) would be
    appreciated.

    Thanks,
    David
  • Moriyoshi Koizumi at Apr 12, 2004 at 12:53 am

    On 2004/04/12, at 1:33, David Sklar wrote:

    Attached is a patch that implements fputcsv() as a complement to
    fgetcsv().

    There are two things that still need improvement:

    - It adds "\n" as a newline onto the end of each line. I think it
    would be better to add a platform-specific line ending.

    - It is not mbstring-aware.
    As for writing stuff, we don't have to care about in which encoding
    strings
    are encoded as long as it is 8-bit compatible. UTF-16 / UTF-32 / UCS-2 /
    UCS-4 are not 8-bit compatible and I've never seen a case where one of
    these is utilised for CSV files, so I think your code is actually
    "multibyte safe" :)

    Moriyoshi
    Any suggestions for fixing these things (or other issues) would be
    appreciated.

    Thanks,
    David

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupphp-internals @
categoriesphp
postedApr 11, '04 at 4:33p
activeApr 12, '04 at 5:56p
posts7
users5
websitephp.net

People

Translate

site design / logo © 2022 Grokbase