11

I need to put all strings and number with double quotes in CSV file using PHP.

How can I create CSV file from PHP in all data within double quotes ?

I am using this code to generate CSV - I am using codeigniter framework

$array = array(
    array(
     (string)'XXX XX XX',
     (string)'3',
     (string)'68878353',
     (string)'',
     (string)'xxxx@xxxx.xxx.xx',
    ),
);

$this->load->helper('csv');
array_to_csv($array, 'blueform.csv'); 

Output I am getting:

"XXX XX XX",3,68878353,,xxxx@xxxx.xxx.xx

Expected Output:

"XXX XX XX","3","68878353","","xxxx@xxxx.xxx.xx"

Code of array_to_csv

if (!function_exists('array_to_csv')) {
    function array_to_csv($array, $download = "") {
        if ($download != "") {   
            header('Content-Type: application/csv');
            header('Content-Disposition: attachement; filename="' . $download . '"');
        }

        ob_start();
        $f = fopen('php://output', 'w') or show_error("Can't open php://output");
        $n = 0;
        foreach ($array as $line) {
            $n++;
            if (!fputcsv($f, $line)) {
                show_error("Can't write line $n: $line");
            }
        }
        fclose($f) or show_error("Can't close php://output");
        $str = ob_get_contents();
        ob_end_clean();

        if ($download == "") {
            return $str;
        } else {
            echo $str;
        }
    }
}

Thank you in advance

eloibm
  • 899
  • 2
  • 11
  • 27
Anudeep GI
  • 931
  • 3
  • 14
  • 45
  • Post the code related to this `---->` `array_to_csv` function too – Narendrasingh Sisodia Jul 22 '15 at 09:47
  • standard practice with CSV files is to only wrap fields in quotes if the data contains a comma or a quote. That's what PHP's `fputcsv` function does, and it's what's expected by pretty much every CSV-reading software I've ever come across. Is there a specific reason you need something different? (I'm guessing you're importing the data into some crusty old software that enforces it's own strict requirements?) – Simba Jul 22 '15 at 10:45
  • @Simba I have specific reason for this ... I am generating this CSV file to upload to Singapore government website, I can't able to upload file to site generated using PHP ... after I have compared files - one file which I can upload and other file which I am generating using php .. I have find out that main difference is file in which I can upload have double quotes in all values – Anudeep GI Jul 23 '15 at 03:47
  • @Uchiha please check I have added array_to_csv code now – Anudeep GI Jul 23 '15 at 06:14
  • http://stackoverflow.com/questions/2489553/forcing-fputcsv-to-use-enclosure-for-all-fields – Bogdan Burym Jul 27 '15 at 11:58
  • Some fields may contain `\r` or `\n` - I needed all fields to be quote-enclosed to protect against inappropriately perceived line breaks (should only occur at end of line). – ptrcao Dec 25 '19 at 18:35

10 Answers10

7

When building a CSV in PHP, you should use the fputcsv function available from PHP 5

From the documentation, there's the following parameters:

int fputcsv ( resource $handle , array $fields [, string $delimiter = "," [, string $enclosure = '"' [, string $escape_char = "\" ]]] )

In that you have:

  • the file resource you're writing to
  • The data to put into the CSV
  • The delimiter (the commas usually)
  • The string enclosure (this is the bit you want for your quotes)
  • Escape string (so if your data contains the enclosure character, you can escape it to avoid it looking like a new field)

As the defaults for that are , for the delimiter, and " for the enclosure, you'll not need to add more. That will correctly cover the strings. The numbers are a different matter. There's a work around on this SO question which I found after typing most of this and then having issues with numbers still :

Not happy with this solution but it is what I did and worked. The idea is to set an empty char as enclosure character on fputcsv and add some quotes on every element of your array.

function encodeFunc($value) {
    return "\"$value\"";
}

fputcsv($handler, array_map(encodeFunc, $array), ',', chr(0));
Community
  • 1
  • 1
gabe3886
  • 4,235
  • 3
  • 27
  • 31
  • I have changed code function test_fun(){ $array = array( array( $this->encodeFunc('xx x x'), $this->encodeFunc('3'), $this->encodeFunc('68878353'), $this->encodeFunc(''), $this->encodeFunc('xx@xx.xx.xx'), ), ); //fputcsv($handler, array_map(encodeFunc, $array), ',', chr(0)); //print_r($array); $this->load->helper('csv'); array_to_csv($array, 'blueform.csv'); }function encodeFunc($value) { return "\"$value\""; } output : """xxxx xx xxx""","""3""","""68878353""","""""","""xx@xx.xx.x""" – Anudeep GI Jul 23 '15 at 05:37
  • Adding chr(0) for fputcsv enclosure will actually generate ASCII 0 Garbled when there is a value that needs to be enclosed. – Nick Tsai Sep 02 '21 at 13:03
2

Concat the string with this '"""';

Example: '"""' . {{String}} . '"""';

This should work, it worked for me. This is a way to enclose the string.

GrumpyCrouton
  • 8,486
  • 7
  • 32
  • 71
raja
  • 21
  • 2
1

I m using CSV helper here.

For Generating result from db query for ex.

$sTable = "MY_TABLE_NAME";

$query = $this->db->get($sTable);

$this->load->helper('csv');

query_to_csv($query, TRUE, 'records.csv');

In CSV Helper onLine number 65 There is the code for query_to_csv.

here is csv_helper.php.

I made a small edit there if you want everything with double inverted comma.

    <?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');

// ------------------------------------------------------------------------

/**
 * CSV Helpers
 * Inspiration from PHP Cookbook by David Sklar and Adam Trachtenberg
 * 
 * @author      Jérôme Jaglale
 * @link        http://maestric.com/en/doc/php/codeigniter_csv
 */

// ------------------------------------------------------------------------

/**
 * Array to CSV
 *
 * download == "" -> return CSV string
 * download == "toto.csv" -> download file toto.csv
 */
if ( ! function_exists('array_to_csv'))
{
    function array_to_csv($array, $download = "")
    {
        if ($download != "")
        {   
            header('Content-Type: application/csv');
            header('Content-Disposition: attachement; filename="' . $download . '"');
        }       

        ob_start();
        $f = fopen('php://output', 'w') or show_error("Can't open php://output");
        $n = 0;     
        foreach ($array as $line)
        {
            $n++;
            if ( ! fputcsv($f, $line))
            {
                show_error("Can't write line $n: $line");
            }
        }
        fclose($f) or show_error("Can't close php://output");
        $str = ob_get_contents();
        ob_end_clean();

        if ($download == "")
        {
            return $str;    
        }
        else
        {   
            echo $str;
        }       
    }
}

// ------------------------------------------------------------------------

/**
 * Query to CSV
 *
 * download == "" -> return CSV string
 * download == "toto.csv" -> download file toto.csv
 */
if ( ! function_exists('query_to_csv'))
{
    function query_to_csv($query, $headers = TRUE, $download = "")
    {
        if ( ! is_object($query) OR ! method_exists($query, 'list_fields'))
        {
            show_error('invalid query');
        }

        $array = array();

        if ($headers)
        {
            $line = array();
            foreach ($query->list_fields() as $name)
            {
                $line[] = '"'.$name.'"';
            }
            $array[] = $line;
        }

        foreach ($query->result_array() as $row)
        {
            $line = array();
            foreach ($row as $item)
            {
                $line[] = '"'.$item.'"';
            }
            $array[] = $line;
        }

        echo array_to_csv($array, $download);
    }
}

/* End of file csv_helper.php */
/* Location: ./system/helpers/csv_helper.php */

This will give Insert double inverted comma in column name as well as rows. You can also remove "" this from column name.

enter image description here

Bugfixer
  • 2,547
  • 2
  • 26
  • 42
  • I need double quotes when you open CSV file in text editor ...if you open this file in text editor it will show ""UI"" like this @bugfixer – Anudeep GI Jul 27 '15 at 12:56
  • @Anudeep - But where did u mention that you want to open this file in text editor – Bugfixer Jul 28 '15 at 10:05
  • Read this [link](http://superuser.com/a/349900) to better understand behavior of CSV file. – Bugfixer Jul 28 '15 at 10:19
1

You could use the implode() function to make the code above even more simple:

$delimiter = ';';
$enclosure = '"';
$linefeed  = "\n";

$lines = array();
// traversing data, one row at a time
foreach ($data as $row) {
    $arr = array();
    // traversing row, col after col
    foreach ($row as $col => $val) {
        // MySQL-style escaping double quotes
        $val = str_replace('"','""',$val);
        // wrapping each value in double quotes
        $arr[] = sprintf('%s%s%s',$enclosure,$val,$enclosure);
    }
    // generating formatted line and storing it
    $lines[] = implode($delimiter,$arr);
}
// join each lines to have the final output
$output = implode($linefeed,$lines);
echo $output;
Yannoff
  • 367
  • 2
  • 9
0

Change your code little bit.

fputcsv($f, $line)

To

fputcsv($f,array_map('strval', $line), ',', '"')

Hope this will help you.

FYI: its in array_to_csv

Chetak
  • 3
  • 4
0

I would probably just replace fputcsv with a home grown version. Now I'm taking your data-structure to always be a grid like traditional spreadshees and CSV-files.

function getQuotedString($arr){
    $buffer = "";
    foreach($arr as $line){
        $string = "";
        foreach($line as $data){
            // See if $string is no longer empty, meaning we need a comma to separate data
            if($string !== "") $string .= ',';
            $string .= '"' . $data . '"';
        }
        $buffer .= $string . PHP_EOL;
    }
    return $buffer;
}

Now use that in your code:

...
ob_start();
$f = fopen('php://output', 'w') or show_error("Can't open php://output");
$quotedData = getQuotedString($arr);

for ($written = 0; $written < strlen($data); $written += $fwrite) {
    $fwrite = fwrite($f, substr($data, $written));
    if ($fwrite === false) {
        return $written;
    }
}

fclose($f) or show_error("Can't close php://output");
$str = ob_get_contents();
ob_end_clean();
...

You can then use $written to see how many bytes were written, or if you want to know how many lines there were you can just use sizeof($arr).

Hope this helps!

Canis
  • 4,130
  • 1
  • 23
  • 27
0

Wouldn't the implode function work beautifully for this?

$array = [ 
 (string)'XXX XX XX',
 (string)'3',
 (string)'68878353',
 (string)'',
 (string)'xxxx@xxxx.xxx.xx'
];
$csvData = '"' . implode('","', $array) . '"';

and then you can just write $csvData out to your file?

0

Ofcourse there are other ways to handle it, but by using fputcsv and works for most scenarios.

if(!function_exists('array_to_csv')) {
    function array_to_csv($array, $download = "") {
        ob_start();
        $f = fopen('php://output', 'w') or die("Can't open php://output");
        $counter = count($array);
        for ($i = 0; $i < $counter; $i++) { 
            if(!fputcsv($f, array_map(function($value) {  return '"'.$value.'"';  }, $array[$i]), ",", "\"")) {
                die("Can't write line $i: ".print_r($array[$i], true));
            }
        }
        fclose($f) or die("Can't close php://output");
        $str = str_replace('"""', '"', ob_get_contents());
        ob_end_clean();

        if(strlen($download) > 0) {
            header('Content-Type: application/csv');
            header('Content-Disposition: attachment; filename="'.$download.'"');
            echo $str;
        } else {
            return $str;
        }
    }
}
Nitesh Oswal
  • 118
  • 8
0

Don't take the effort of properly enclosing every filed with double quotes. There are in-build php functions available to do the job without error.

Not only double quotes, you will be in need for single quote ('), double quote ("), backslash (\) and NULL (the NULL byte).

Use fputcsv() to write, and fgetcsv() to read, which will take care of all.

Angelin Nadar
  • 8,944
  • 10
  • 43
  • 53
-1

I have got solution this function convert multi dimension array into CSV with double quote and

function arr_to_csv($arr)
  {
        $filePointer="export.csv";
        $delimiter=",";
        $enclosure='"';
        $dataArray =$arr;

        $string = "";

        // No leading delimiter
        $writeDelimiter = FALSE;
        //foreach($dataArray as $dataElement)
        foreach ($dataArray as $key1 => $value){
        foreach ($value as $key => $dataElement) 

         {
          // Replaces a double quote with two double quotes
          $dataElement=str_replace("\"", "\"\"", $dataElement);
          // Adds a delimiter before each field (except the first)
          // Encloses each field with $enclosure and adds it to the string
          if($writeDelimiter) $string .= $delimiter;
          // $new_string = $enclosure . $dataElement . $enclosure;
          $string .= $enclosure . $dataElement . $enclosure;
         // Delimiters are used every time except the first.
          $writeDelimiter = TRUE;
         } // end foreach($dataArray as $dataElement)

                $string .= "\n";

         }      
        // Append new line
        $string .= "\n";    
         //$string = "An infinite number of monkeys";
        print($newstring);
       // Write the string to the file
      // fwrite($filePointer,$string);
       header('Content-Type: application/csv');
      header('Content-Disposition: attachment; filename="'.$filePointer.'";');
  }
Anudeep GI
  • 931
  • 3
  • 14
  • 45
  • I really dont see why you need to add the clutter you do to your strings and then remove it again later... Why not just add `PHP_EOL` after the end of the inner `foreach` instead of adding `|||`? And the way you have set up your code you should never see `|||,` so why do you try to replace it with newline? You also set $writeDelimiter to true for every pass of the function, why not just see if the string is blank? – Canis Jul 29 '15 at 18:17
  • @Canis I have made code change ... please check I have remove '|||' this – Anudeep GI Jul 31 '15 at 03:59