24

I have several method to transform php array to csv string both from stackoverflow and google. But I am in trouble that if I want to store mobile number such as 01727499452, it saves as without first 0 value. I am currently using this piece of code: Convert array into csv

Can anyone please help me.

Array   

[1] => Array
    (
        [0] => Lalu ' " ; \\ Kumar
        [1] => Mondal
        [2] => 01934298345
        [3] => 
    )

[2] => Array
    (
        [0] => Pritom
        [1] => Kumar Mondal
        [2] => 01727499452
        [3] => Bit Mascot
    )

[3] => Array
    (
        [0] => Pritom
        [1] => Kumar Mondal
        [2] => 01711511149
        [3] => 
    )

[4] => Array
    (
        [0] => Raaz
        [1] => Mukherzee
        [2] => 01911224589
        [3] => Khulna University 06
    )

)

My code block:

function arrayToCsv( array $fields, $delimiter = ';', $enclosure = '"', $encloseAll = false, $nullToMysqlNull = false ) {
$delimiter_esc = preg_quote($delimiter, '/');
$enclosure_esc = preg_quote($enclosure, '/');

$outputString = "";
foreach($fields as $tempFields) {
    $output = array();
    foreach ( $tempFields as $field ) {
        if ($field === null && $nullToMysqlNull) {
            $output[] = 'NULL';
            continue;
        }

        // Enclose fields containing $delimiter, $enclosure or whitespace
        if ( $encloseAll || preg_match( "/(?:${delimiter_esc}|${enclosure_esc}|\s)/", $field ) ) {
            $field = $enclosure . str_replace($enclosure, $enclosure . $enclosure, $field) . $enclosure;
        }
        $output[] = $field." ";
    }
    $outputString .= implode( $delimiter, $output )."\r\n";
}
return $outputString; }

Thanks,

Pritom.

7
  • 2
    That's the problem with using other people's wheels. Commented May 3, 2013 at 6:03
  • 3
    Save it as a string. I'd recommend that for phone numbers anyway, because you're just going to want to save that + as well ;) Commented May 3, 2013 at 6:04
  • 4
    You should be using PHP's built in CSV functions like php.net/manual/en/function.fputcsv.php Commented May 3, 2013 at 6:07
  • 1
    Some second-hand advice: If you're not going to do arithmetic on it, store it as a string. The Daily WTF contains examples of many a phone number printed in scientific notation, which ultimately stems from someone storing it as an integer. Commented May 3, 2013 at 6:11
  • 2
    The number will be stored correctly in the CSV, with a leading zero; but when opened in MS Excel, then Excel will reformat it - either use a file format that supports format information already (not CSV) so that Excel doesn't apply its standard behaviour, or force it to be a formula string when saving ="01911224589" Commented May 3, 2013 at 6:30

10 Answers 10

41

You could use str_putcsv function:

if(!function_exists('str_putcsv'))
{
    function str_putcsv($input, $delimiter = ',', $enclosure = '"')
    {
        // Open a memory "file" for read/write...
        $fp = fopen('php://temp', 'r+');
        // ... write the $input array to the "file" using fputcsv()...
        fputcsv($fp, $input, $delimiter, $enclosure);
        // ... rewind the "file" so we can read what we just wrote...
        rewind($fp);
        // ... read the entire line into a variable...
        $data = fread($fp, 1048576);
        // ... close the "file"...
        fclose($fp);
        // ... and return the $data to the caller, with the trailing newline from fgets() removed.
        return rtrim($data, "\n");
    }
 }

 $csvString = '';
 foreach ($list as $fields) {
     $csvString .= str_putcsv($fields);
 }

More about this on GitHub, a function created by @johanmeiring.

Sign up to request clarification or add additional context in comments.

4 Comments

It's a minor thing but i think you meant $csvString .= str_putcsv($fp, $fields);. Missing the $ ;)
shouldn't it be str_putcsv($fields); instead of str_putcsv($fp, $fields);
I liked this solution. I made one small modification when I "borrowed" it: ... $len = ftell($fp)+1; rewind($fp); $data = fread($fp,$len); ... and it seems to work. I didn't know what 1048576 represents, so I didn't want to use it directly.
Why not the original function by someone called Dave who posted it years earlier with $data = fgets($fp); (thus avoiding hardcoding 1048576)? But does anyone know why he got -1 points even though it seems to work well?
26

This is what you need

$out = "";
foreach($array as $arr) {
    $out .= implode(",", $arr) . PHP_EOL;

}

It runs through your array creating a new line on each loop seperating the array values with a ",".

5 Comments

Is this what I want? Please read my question and if you are not clear please ask me.
It should be, i dont see why you wouldnt:) Give it a shot, and see if it meets your expectations.
I have used something similar in a number of situations, and it works well with a warning (or two). This breaks if some value in $arr has a ',' character in it. The csv format has ways to handle it that aren't being addressed addressed by this solution. Also, you are coding a Windows specific newline with "\r\n", which may cause problems in some situations. Using the constant PHP_EOL will result in more portable code.
OP should maybe try to examine the contents of $out
Does not even attempt to escape output properly. Expect corrupted data from this.
7

Inspired by @alexcristea's answer:

function array2csv($data, $delimiter = ',', $enclosure = '"', $escape_char = "\\")
{
    $f = fopen('php://memory', 'r+');
    foreach ($data as $item) {
        fputcsv($f, $item, $delimiter, $enclosure, $escape_char);
    }
    rewind($f);
    return stream_get_contents($f);
}

$list = array (
    array('aaa', 'bbb', 'ccc', 'dddd'),
    array('123', '456', '789'),
    array('"aaa"', '"bbb"')
);
var_dump(array2csv($list));

Comments

3

Are you sure the numbers are actually being saved without the leading zero? Have you looked at the actual CSV output in a text editor?

If you've just opened up the CSV file in a spreadsheet application, it is most likely the spreadsheet that is interpreting your telephone numbers as numeric values and dropping the zeros when displaying them. You can usually fix that in the spreadsheet by changing the formatting options on that particular column.

Comments

3

This works for me and it piggy backs off PHP's built-in CSV functions. The nifty part about that is that it automatically correctly adds inverted commas around the relevant fields.

// Create an array of elements
$list = array(
    ['Name', 'age', 'Gender'],
    ['Bob', 20, 'Male'],
    ['John', 25, 'Male'],
    ['Jessica', 30, 'Female']
);

// Create an output buffer
$outputBuffer = fopen('php://temp', 'w');

// Loop through the array and write to the output buffer
foreach ($list as $fields) {
    fputcsv($outputBuffer, $fields);
}

// Rewind the output buffer
rewind($outputBuffer);

// Read the contents of the output buffer
$csvString = stream_get_contents($outputBuffer);

// Close the output buffer
fclose($outputBuffer);

// Output the CSV string
echo $csvString;

Comments

1

Just add and call the function below:

function FromCells($cells, $delimiter = ',', $enclosure = '"', $eol = "\n") :string {
        if(empty($cells)) return "";
        $fstream = fopen('php://temp', 'r+b');
        foreach ($cells as $fields) fputcsv($fstream, $fields, $delimiter, $enclosure, "\\", $eol);
        rewind($fstream);
        $data = rtrim(stream_get_contents($fstream), $eol);
        fclose($fstream);
        return $data;
}

Enjoy...

Comments

0

Since it's a CSV and not something like JSON, everything is going to be read as a string anyway so just convert your number to a string with:

  • (string)$variable
  • strval($variable) (which I would prefer here)
  • concatenate with an empty string like $variable . ''

PHP's gettype() would also be an option. You can type cast every field to a string (even if it already is one) by using one of the methods I described or you can call out just the number field you're after by doing this:

if (gettype($field) == 'integer' || gettype($field) == 'double') {
    $field = strval($field); // Change $field to string if it's a numeric type
}

Here's the full code with it added

function arrayToCsv( array $fields, $delimiter = ';', $enclosure = '"', $encloseAll = false, $nullToMysqlNull = false ) {
    $delimiter_esc = preg_quote($delimiter, '/');
    $enclosure_esc = preg_quote($enclosure, '/');

    $outputString = "";
    foreach($fields as $tempFields) {
        $output = array();
        foreach ( $tempFields as $field ) {
            // ADDITIONS BEGIN HERE
            if (gettype($field) == 'integer' || gettype($field) == 'double') {
                $field = strval($field); // Change $field to string if it's a numeric type
            }
            // ADDITIONS END HERE
            if ($field === null && $nullToMysqlNull) {
                $output[] = 'NULL';
                continue;
            }

            // Enclose fields containing $delimiter, $enclosure or whitespace
            if ( $encloseAll || preg_match( "/(?:${delimiter_esc}|${enclosure_esc}|\s)/", $field ) ) {
                $field = $enclosure . str_replace($enclosure, $enclosure . $enclosure, $field) . $enclosure;
            }
            $output[] = $field." ";
        }
        $outputString .= implode( $delimiter, $output )."\r\n";
    }
    return $outputString; 
}

Comments

0

Here is a solution that is a little more general purpose. I was actually looking for a way to make string lists for SQL bulk inserts. The code would look like this:

foreach ($rows as $row) {
    $string = toDelimitedString($row);
    // Now append it to a file, add line break, whatever the need may be
}

And here is the useful function that I ended up adding to my tookit:

/**
 * Convert an array of strings to a delimited string. This function supports CSV as well as SQL output since
 * the quote character is customisable and the escaping behaviour is the same for CSV and SQL.
 *
 * Tests:
 *  echo toDelimitedString([], ',', '\'', true) . "\n";
 *  echo toDelimitedString(['A'], ',', '\'', true) . "\n";
 *  echo toDelimitedString(['A', 'B'], ',', '\'', true) . "\n";
 *  echo toDelimitedString(['A', 'B\'C'], ',', '\'', true) . "\n";
 *  echo toDelimitedString([], ',', '\'', true) . "\n";
 *  echo toDelimitedString(['A'], ',', '"', true) . "\n";
 *  echo toDelimitedString(['A', 'B'], ',', '"', true) . "\n";
 *  echo toDelimitedString(['A', 'B"C'], ',', '"', true) . "\n";
 *
 * Outputs:
 *  <Empty String>
 *  'A'
 *  'A','B'
 *  'A','B''C'
 *  <Empty String>
 *  "A"
 *  "A","B"
 *  "A","B""C"
 *
 * @param array $array A one-dimensional array of string literals
 * @param string $delimiter The character to separate string parts
 * @param string $quoteChar The optional quote character to surround strings with
 * @param bool $escape Flag to indicate whether instances of the quote character should be escaped
 * @return string
 */
function toDelimitedString(array $array, string $delimiter = ',', string $quoteChar = '"', bool $escape = true)
{
    // Escape the quote character, since it is somewhat expensive it can be suppressed
    if ($escape && !empty($quoteChar)) {
        $array = str_replace($quoteChar, $quoteChar . $quoteChar, $array);
    }

    // Put quotes and commas between all the values
    $values = implode($array, $quoteChar . $delimiter . $quoteChar);

    // Put first and last quote around the list, but only if it is not empty
    if (strlen($values) > 0) {
        $values = $quoteChar . $values . $quoteChar;
    }

    return $values;
}

Comments

-1

This implementation does not use file pointers, shouldn't inadvertently modify any data passed to it, and only escapes as required, analogous to fputcsv() (but without the $escape_char nonsense):

function str_putcsv(array $fields, string $delimiter = ',', string $enclosure = '"') {
    $escs = [];
    foreach ($fields as $field) {
        $esc = (string) $field;
        if (
            false !== strpos($esc, $delimiter)
            || false !== strpos($esc, $enclosure)
        ) {
            $esc = $enclosure . strtr($esc, ["$enclosure" => "$enclosure$enclosure"]) . $enclosure;
        }
        $escs[] = $esc;
    }
    return implode($delimiter, $escs) . PHP_EOL;
}

Drop the string type declarations if your PHP version doesn't support them.

Comments

-2

The function above is not exactly right cause it considers \n like an element, which is not what we want as each line must be only separated by \n. So a more efficient code would be:

function array2csv($array, $delimiter = "\n") {
    $csv = array();
    foreach ($array as $item=>$val) 
    {
        if (is_array($val)) 
        { 
            $csv[] = $this->array2csv($val, ";");
        } 
        else 
        {
            $csv[] = $val;
        }
    }
    return implode($delimiter, $csv);
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.