23

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.

Community
  • 1
  • 1
Pritom
  • 1,294
  • 8
  • 19
  • 37
  • 2
    That's the problem with using other people's wheels. – Ben May 03 '13 at 06: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 ;) – SBI May 03 '13 at 06:04
  • Can you give an example of how your array looks like? – bestprogrammerintheworld May 03 '13 at 06:06
  • 4
    You should be using PHP's built in CSV functions like http://php.net/manual/en/function.fputcsv.php – kittycat May 03 '13 at 06:07
  • 1
    Some second-hand advice: If you're not going to do arithmetic on it, store it as a string. [The Daily WTF](http://thedailywtf.com/) contains examples of many a phone number printed in scientific notation, which ultimately stems from someone storing it as an integer. – michaelb958--GoFundMonica May 03 '13 at 06:11
  • @Steve, all here we are other people, so why we are here? If anyone can not find his answer himself, then need to use other people's wheels. – Pritom May 03 '13 at 06:12
  • 1
    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"` – Mark Baker May 03 '13 at 06:30

10 Answers10

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.

Ravi Dhoriya ツ
  • 4,435
  • 8
  • 37
  • 48
alexcristea
  • 2,316
  • 16
  • 18
  • 1
    It's a minor thing but i think you meant $csvString .= str_putcsv($fp, $fields);. Missing the $ ;) – Mr. Concolato Jul 11 '14 at 16:14
  • 7
    shouldn't it be ```str_putcsv($fields);``` instead of ```str_putcsv($fp, $fields);``` – bamboofighter Apr 11 '17 at 14:27
  • 2
    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. – Ghost8472 Nov 28 '17 at 00:00
  • Why not the original function by someone called Dave [who posted it **years** earlier](https://www.php.net/manual/en/function.str-getcsv.php#88773) with `$data = fgets($fp);` (thus avoiding hardcoding 1048576)? But does anyone know why he got -1 points even though it seems to work well? – LWC Jul 12 '23 at 19:14
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 ",".

Abel Callejo
  • 13,779
  • 10
  • 69
  • 84
Daniel Mensing
  • 956
  • 5
  • 13
  • Is this what I want? Please read my question and if you are not clear please ask me. – Pritom May 03 '13 at 06:29
  • It should be, i dont see why you wouldnt:) Give it a shot, and see if it meets your expectations. – Daniel Mensing May 03 '13 at 06:29
  • 12
    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. – jbo5112 Apr 23 '14 at 21:32
  • 1
    OP should maybe try to examine the contents of $out – billrichards Jun 26 '15 at 20:08
  • 1
    Does not even attempt to escape output properly. Expect corrupted data from this. – Walf May 04 '22 at 06:34
6

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));
trank
  • 952
  • 11
  • 8
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.

James Holderness
  • 22,721
  • 2
  • 40
  • 52
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; 
}
wgp
  • 1,147
  • 15
  • 15
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;
}
Dion Truter
  • 7,592
  • 1
  • 19
  • 9
0

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;
rockstardev
  • 13,479
  • 39
  • 164
  • 296
-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.

Walf
  • 8,535
  • 2
  • 44
  • 59
-2

I'm using this function to convert php array to csv. It's working also for multidimensional array.

public function array_2_csv($array) {
$csv = array();
foreach ($array as $item=>$val) {
if (is_array($val)) { 
    $csv[] = $this->array_2_csv($val);
    $csv[] = "\n";
} else {
    $csv[] = $val;
  }
 }
return implode(';', $csv);
}
Julien
  • 14
  • 7
-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);
}