Delicious Bookmark this on Delicious Share on Facebook SlashdotSlashdot It! Digg! Digg



PHP : Function Reference : Filesystem Functions : fgetcsv

fgetcsv

Gets line from file pointer and parse for CSV fields (PHP 4, PHP 5)
array fgetcsv ( resource handle [, int length [, string delimiter [, string enclosure [, string escape]]]] )

Example 627. Read and print the entire contents of a CSV file

<?php
$row
= 1;
$handle = fopen("test.csv", "r");
while ((
$data = fgetcsv($handle, 1000, ",")) !== FALSE) {
   
$num = count($data);
   echo
"<p> $num fields in line $row: <br /></p>\n";
   
$row++;
   for (
$c=0; $c < $num; $c++) {
       echo
$data[$c] . "<br />\n";
   }
}
fclose($handle);
?>

Related Examples ( Source code ) » fgetcsv



Code Examples / Notes » fgetcsv

kurtnorgaz

You should pay attention to the fact that "fgetcsv" does remove leading TAB-chars "chr(9)" while reading the file.
This means if you have a chr(9) as the first char in the file and you use fgetcsv this char is automaticaly deleted.
Example:
file content:
chr(9)first#second#third#fourth
source:
$line = fgetcsv($handle,500,"#");
The array $line looks like:
$line[0] = first
$line[1] = second
$line[2] = third
$line[3] = fourth
and not
$line[0] = chr(9)first
$line[1] = second
$line[2] = third
$line[3] = fourth
All chr(9) after another char is not deleted!
Example:
file content:
Achr(9)first#second#third#fourth
source:
$line = fgetcsv($handle,500,"#");
The array $line looks like:
$line[0] = Achr(9)first
$line[1] = second
$line[2] = third
$line[3] = fourth


ohira atto web dotto de

Yet another tool to parse CSV data into a associated 2d array. However, when within quotes, newline characters are treated as data instead of syntax.
<?php
define('LF', "\n");
// Parse a CSV data to a associated 2D array
function csvToArray($data)
{
   // output
   $csv = array();
   $line = array();
$fieldnames = array();
$got_fieldnames = false;
   $escaped = false; // Flag: escape char
   $quoted = false; // Flag: quoted string
   $buffer = ''; // Buffer (quoted values)
   $junk = ''; // Junk buffer (unquoted values)
$fieldname_index = 0;
   for($i = 0; $i < strlen($data); $i++)
   {
       $char = $data[$i];
       if($quoted)
       {
           if(($char == '\\') && ($escaped === false))
           {
               // Set flags
               $escaped = true;
           }
           elseif(($char == '"') && ($escaped === false))
           {
               // Set flags
               $quoted = false;
               $escaped = false;
           }
           else
           {
               // Add char to buffer
               $buffer .= $char;
               // Set flags
               $escaped = false;
           }
       }
       else
       {
           if($char == LF) // Start a new line
           {
               if(strlen($buffer) > 0)
               {
                   // Add buffer to line
                   if($got_fieldnames)
                   {
                    $line[$fieldnames[$fieldname_index]] = $buffer;
                    $fieldname_index++;
                   }
                   else
                   {
                    $fieldnames[] = $buffer;
                   }
                   // Clear buffer
                   $buffer = '';
               }
               else
               {
                   $junk = trim($junk);
                   // Add junk to line (possible unquoted values?)
                   if($got_fieldnames)
                   {
                    $line[$fieldnames[$fieldname_index]] = $junk;
                    $fieldname_index++;
                   }
                   else
                   {
                    $fieldnames[] = $junk;
                   }
               }
               // Clear junk
               $junk = '';
               // Add line to CSV
               if($got_fieldnames)
               {
                $csv[] = $line;
               }
$got_fieldnames = true;
               // Clear line
               $line = array();
               $fieldname_index = 0;
           }
           elseif($char == '"') // Start new value
           {
               // Set flags
               $quoted = true;
           }
           elseif($char == ';')
           {
               if(strlen($buffer) > 0)
               {
                   // Add buffer to line
                   if($got_fieldnames)
                   {
                    $line[$fieldnames[$fieldname_index]] = $buffer;
                    $fieldname_index++;
                   }
                   else
                   {
                    $fieldnames[] = $buffer;
                   }
                   // Clear buffer
                   $buffer = '';
               }
               else
               {
                   $junk = trim($junk);
                   // Add junk to line (possible unquoted values?)
                   if($got_fieldnames)
                   {
                    $line[$fieldnames[$fieldname_index]] = $junk;
                    $fieldname_index++;
                   }
                   else
                   {
                    $fieldnames[] = $junk;
                   }
              }
               // Clear junk
               $junk = '';
           }
           else // Add to junk char
           {
               $junk .= $char;
           }
       }
   }
   return $csv;
}
?>


me dot wieringa

Yet another tool to parse CSV data into a 2d array. However, when within quotes, newline characters are treated as data instead of syntax.
<?php
define('LF', "\n");
// Parse a CSV data to a 2D array
function csvToArray($data)
{
// output
$csv = array();
$line = array();
$escaped = false; // Flag: escape char
$quoted = false; // Flag: quoted string
$buffer = ''; // Buffer (quoted values)
$junk = ''; // Junk buffer (unquoted values)
for($i = 0; $i < strlen($data); $i++)
{
$char = $data[$i];
if($quoted)
{
if(($char == '\\') && ($escaped === false))
{
// Set flags
$escaped = true;
}
elseif(($char == '"') && ($escaped === false))
{
// Set flags
$quoted = false;
$escaped = false;
}
else
{
// Add char to buffer
$buffer .= $char;
// Set flags
$escaped = false;
}
}
else
{
if($char == LF) // Start a new line
{
if(strlen($buffer) > 0)
{
// Add buffer to line
$line[] = $buffer;
// Clear buffer
$buffer = '';
}
else
{
$junk = trim($junk);
// Add junk to line (possible unquoted values?)
$line[] = $junk;
}
// Clear junk
$junk = '';
// Add line to CSV
$csv[] = $line;
// Clear line
$line = array();
}
elseif($char == '"') // Start new value
{
// Set flags
$quoted = true;
}
elseif($char == ',')
{
if(strlen($buffer) > 0)
{
// Add buffer to line
$line[] = $buffer;
// Clear buffer
$buffer = '';
}
else
{
$junk = trim($junk);
// Add junk to line (possible unquoted values?)
$line[] = $junk;
}
// Clear junk
$junk = '';
}
else // Add to junk char
{
$junk .= $char;
}
}
}
// Clean up
if(strlen($buffer) > 0)
{
// Add buffer to line
$line[] = $buffer;
// Clear buffer
$buffer = '';
}
else
{
$junk = trim($junk);
// Add junk to line (possible unquoted values?)
$line[] = $junk;
}
$csv[] = $line;
return $csv;
}
?>


martin dot goldinger

With MAC, use: Save As - CSV for Windows. Then fgetcsv works as expected.

aruggirello, at, tiscali, d0t it

Whenever you have to parse CSV data that isn't stored in a file, or should you need to encode your data as CSV, you may use my set of functions, featuring:
- bi-directional conversion, meaning you may read as well as write CSV data, to or from your arrays.
- Support for customizable field separator, newline character (also auto-detects and converts Win/Mac/*nix newlines).
- separators, newlines (auto-converted), properly handled within fields enclosed in quotation marks. Last line may or may not be terminated by a newline.
- checks for possibly corrupt data (whenever last field in last row starts, but is not terminated, with a quotation mark).
- Top speed guaranteed by use of strpos(), substr() etc.; room yet for some optimization (especially with associative arrays).
- Clean (no data stored or retrieved from outside function scope, except for CSVstruct array).
Requires PHP 4.3 or newer.
Enjoy!
Andrea Ruggirello
souce available at:
http://web.tiscali.it/caelisoft/provacsv.txt


dave meiners

using the example above with a length of 1000 will truncate any csv rows longer than 1000 bytes, the remainder of that line will be represented next time you call $data = fgetcsv(). one solution i have seen to this is to use filesize("test.csv") as the length argument, however sometimes with large csv files you may encounter errors for exceeding the memory limit. to remedy this, i have read the csv file into an array, looping through that array to find the longest line in the csv, and then using that value as my length argument, unset($array) to free up the memory. im open to better solutions.
<?php
   $length = 1000;
   $array = file("test.csv");
   for($i=0;$i<count($array);$i++)
   {
       if ($length < strlen($array[$i]))
       {
           $length = strlen($array[$i]);
       }
   }
   unset($array);
   $handle = fopen("test.csv", "r");
   while ($data = fgetcsv($handle, $length, ","))
   {
       // do what you want with your array here.
   }
   fclose($handle);
?>


simone.sanfratello

to get an array with data from the MS Excel csv format (separated by ; and with string wich contains ; or " optionally delimited by " )
function getcsvxls($buffer)
{
$buffer = str_replace('""', '"', $buffer);
$n = strlen($buffer);
$i = $line = 0;
$del = false;
while($i < $n)
{
$part = substr($buffer, $i);
if(
(substr($part, 0, 1) == ';' && !$del) ||
(substr($part, 0, 2) == '";' && $del)
)
{
$i ++;
if($del)
{
$str = substr($str, 1, strlen($str) - 1);
$i ++;
}
$data[$line][] = $str;
$del = false;
$str = '';
} else if(substr($part, 0, 2) == "\r\n")
{
$data[$line][] = $str;
$str = '';
$del = false;
$line ++;
$i += 2;
} else
{
if($part[0] == '"')
$del = true;
$str .= $part[0];
$i ++;
}
}
return $data;
}


dave146

To convert .dbf files (dBase/xBase/FoxPro/Clipper/etc.) files
to .csv, so that you can read them with fgetcsv, get dbf2csv.zip
from http://www.burtonsys.com/downloads.html
(It seems odd to me that php has fgetcsv but no splitcsv.)
-Dave


kmlinac/nospam/

This is the solution to Microsoft Excel csv file - this function add last delimiter in line.
<?php
function delimiter()
{
if (is_file("file.csv"))
{
$fp = fopen($file.csv,"r");
while (false!=($line = fgets($fp)))
{
             $line = "$line;";
                 putf($line);
                }
fclose($fp);
}
}
//puts dedlimited line in new file
function putf($line)
{
$fp = fopen($file,"a");
fputs($fp,$line);
fclose($fp);
}
/* this readsl line at the time and adds ; as delimiter on line end. Its easy and helpfull*/
delimiter();
?>


marcus

This is a minor fix to mortanon@gmail.com's CSVIterator. The original version would die if the last line of a file did not end in a line break and you called valid() inside the iterator loop because the file would have already been closed and thus feof() would have an invalid file pointer param.
<?php
/**
* @author mortanon@gmail.com
* @link http://uk.php.net/manual/en/function.fgetcsv.php
*/
class CsvIterator implements Iterator {
const ROW_SIZE = 4096;
/**
* The pointer to the cvs file.
* @var resource
* @access private
*/
private $filePointer = NULL;
/**
* The current element, which will
* be returned on each iteration.
* @var array
* @access private
*/
private $currentElement = NULL;
/**
* The row counter.
* @var int
* @access private
*/
private $rowCounter = NULL;
/**
* The delimiter for the csv file.
* @var str
* @access private
*/
private $delimiter = NULL;
/**
* This is the constructor.It try to open the csv file.The method throws an exception
* on failure.
*
* @access public
* @param str $file The csv file.
* @param str $delimiter The delimiter.
*
* @throws Exception
*/
public function __construct($file, $delimiter=',') {
try {
$this->filePointer = fopen($file, 'r');
$this->delimiter = $delimiter;
}
catch (Exception $e) {
throw new Exception('The file "'.$file.'" cannot be read.');
}
}
/**
* This method resets the file pointer.
*
* @access public
*/
public function rewind() {
$this->rowCounter = 0;
rewind($this->filePointer);
}
/**
* This method returns the current csv row as a 2 dimensional array
*
* @access public
* @return array The current csv row as a 2 dimensional array
*/
public function current() {
$this->currentElement = fgetcsv($this->filePointer, self::ROW_SIZE, $this->delimiter);
$this->rowCounter++;
return $this->currentElement;
}

/**
* This method returns the current row number.
*
* @access public
* @return int The current row number
*/
public function key() {
return $this->rowCounter;
}

/**
* This method checks if the end of file is reached.
*
* @access public
* @return boolean Returns true on EOF reached, false otherwise.
*/
public function next() {
if (is_resource($this->filePointer)) {
return !feof($this->filePointer);
}
return false;
}

/**
* This method checks if the next row is a valid row.
*
* @access public
* @return boolean If the next row is a valid row.
*/
public function valid() {
if (!$this->next()) {
if (is_resource($this->filePointer)) {
fclose($this->filePointer);
}
return false;
}
return true;
}
}
?>


daffy

This is a little sniplet for all users who has problems with Excel csv files. This functions does almost the same like the linux shell program dos2unix.
/* ------------------8<------------------------*/
function dos2unix ($filename) {
       //open original file
       $fp = fopen($filename,'r');
       //open original file
       $fptmp = fopen($filename.'_tmp','w');
       while(!feof($fp)){
               $line = chop(fgets($fp,4096));
               $ret = ereg_replace(chr(13) . chr(10),"\n",$line);
               $ret = ereg_replace(chr(13),"\n",$ret);
               fwrite($fptmp,$ret);
       }
       fclose($fp);
       fclose($fptmp);
       //remove original file
       unlink($filename);
       //move converted file to old filename
       copy($filename.'_tmp', $filename);
       //remove temp file
       unlink($filename.'_tmp');
}
/* ------------------8<------------------------*/


php

This function takes a csv line and splits it into an array, much like fgetcsv does but you can use it on data that isn't coming in from a file, or you can read data from a file some other way (like if your Mac files aren't being read correctly) and use this to split it.  If you have any corrections, comments (good or bad), etc. I would appreciate an email to the above address.
<?php
function csv_split($line,$delim=',',$removeQuotes=true) {
#$line: the csv line to be split
#$delim: the delimiter to split by
#$removeQuotes: if this is false, the quotation marks won't be removed from the fields
   $fields = array();
   $fldCount = 0;
   $inQuotes = false;
   for ($i = 0; $i < strlen($line); $i++) {
       if (!isset($fields[$fldCount])) $fields[$fldCount] = "";
       $tmp = substr($line,$i,strlen($delim));
       if ($tmp === $delim && !$inQuotes) {
           $fldCount++;
           $i += strlen($delim)-1;
       } else if ($fields[$fldCount] == "" && $line[$i] == '"' && !$inQuotes) {
           if (!$removeQuotes) $fields[$fldCount] .= $line[$i];
           $inQuotes = true;
       } else if ($line[$i] == '"') {
           if ($line[$i+1] == '"') {
               $i++;
               $fields[$fldCount] .= $line[$i];
           } else {
               if (!$removeQuotes) $fields[$fldCount] .= $line[$i];
               $inQuotes = false;
           }
       } else {
           $fields[$fldCount] .= $line[$i];
       }
   }
   return $fields;
}
?>


jszatmary

This function appears to assume that \" is an escaped quote - similar to "" - which may lead to incorrect results while reading some files. Found while running under PHP 5.1.6.

lj

There was a bug with the column headings
function parse_csv_file($file, $columnheadings = false, $delimiter = ',', $enclosure = "\"") {

$row = 1;
$rows = array();
$handle = fopen($file, 'r');

while (($data = fgetcsv($handle, 1000, $delimiter, $enclosure )) !== FALSE) {

if (!($columnheadings == "false") && ($row == 1)) {
$headingTexts = $data;
} elseif (!($columnheadings == "false")) {
foreach ($data as $key => $value) {
unset($data[$key]);
$data[$headingTexts[$key]] = $value;
}
$rows[] = $data;
} else {
$rows[] = $data;
}
$row++;
}

fclose($handle);
return $rows;
}


mr n.

There is still a bug with column headings ( "false" != false )
<?php
   function parse_csv_file($file, $columnheadings = false, $delimiter = ',', $enclosure = "\"") {

      $row = 1;
      $rows = array();
      $handle = fopen($file, 'r');

      while (($data = fgetcsv($handle, 1000, $delimiter, $enclosure )) !== FALSE) {

          if (!($columnheadings == false) && ($row == 1)) {
              $headingTexts = $data;
          } elseif (!($columnheadings == false)) {
              foreach ($data as $key => $value) {
                  unset($data[$key]);
                  $data[$headingTexts[$key]] = $value;
              }
              $rows[] = $data;
          } else {
              $rows[] = $data;
          }
          $row++;
      }

      fclose($handle);
      return $rows;
   }
?>


andychr17

The man below suggested this to avoid and endless loop from using "!== FALSE":
while (($data = fgetcsv($handle, 1000, ",")) != FALSE) {
This is redundant, if you want to do it with the != you may as well do:
while ($data = fgetcsv($handle, 1000, ",")) {


dawa

The following modification will hide the unnecessary delimiter in the array
that is returned when fgetcsvfromline is called.
<?php
function fgetcsvfromline ($line, $columnCount, $delimiterChar = ',',
               $enclosureChar = '"') {
       global $regExpSpecialChars;
       $matches = array();
       $delimiterChar = strtr($delimiterChar, $regExpSpecialChars);
       $enclosureChar = strtr($enclosureChar, $regExpSpecialChars);
       $cutpoint = strlen($delimiterChar)+1;
       $regExp = "/^";
       for ($i = 0; $i < $columnCount; $i++) {
               $regExp .= $enclosureChar.'?(.*?)'.$enclosureChar.'?'.$delimiterChar;
       }
       $regExp = substr($regExp,0,-$cutpoint).'/';
       if (preg_match($regExp, $line, $matches)) {
               return $matches;
       }
       return 0;
}
?>
=== If you were getting
[0] => "Ma"rk","Bergeron","rocks","12345,"times"
[1] => "
[2] => Ma"rk
[3] => "
..etc
You will now get
[0] => "Ma"rk","Bergeron","rocks","12345,"times"
[1] => Ma"rk
...etc


bart

The file function reads the file in an array with the EOL still attached, so the +1 is not necessary.

junk

The fgetcsv function seems to follow the MS excel conventions, which means:
- The quoting character is escaped by itself and not the back slash.
(i.e.Let's use the double quote (") as the quoting character:

  Two double quotes  "" will give a single " once parsed, if they are inside a quoted field (otherwise neither of them will be removed).
  \" will give \" whether it is in a quoted field or not (same for \\) , and
  if a single double quote is inside a quoted field it will be removed. If it is not inside a quoted field it will stay).
- leading and trailing spaces (\s or \t) are never removed, regardless of whether they are in quoted fields or not.
- Line breaks within fields are dealt with correctly if they are in quoted fields. (So previous comments stating the opposite are wrong, unless they are using a different PHP version.... I am using 4.4.0.)
So fgetcsv if actually very complete and can deal with every possible situation. (It does need help for macintosh line breaks though, as mentioned in the help files.)
I wish I knew all this from the start. From my own benchmarks fgetcsv strikes a very good compromise between memory consumption and speed.
-------------------------
Note: If back slashes are used to escape quotes they can easily be removed afterwards. Same for leading and trailing spaces.


stinkyj

the enclosure param defaulting to " and giving a warning if it's an empty string makes this function nearly worthless. csv files do not always have the fields enclosed, and in those cases it doesn't work.

bob

Thank you to the mystery contributor of csv_string_to_array function:
http://uk3.php.net/manual/en/function.fgetcsv.php#62524
This works great when your CSV data has literal commas inside enclosures that you want to preserve, fgetcsv fails at this & interprets comma as end of item even without ending enclosure.


br0derbund

Thank you donnoman and ramdac, that's exactly the kind of function I needed!
For my use, assigning metadata to images, I actually want the first dimension array key to be a string pulled from the CSV; the unique filename, instead of a number.
Easy, just insert the second dim's key...
Change: $return[]=$row;
To: $return[$data[0]]=$row;
(You may indeed wish to confirm unique values first!)
Also, if you find the fields getting out of sync, increase the $len byte count for the largest cell of data.


lesha

Some time it is not very good to be dependent on system locale :(  The hosting provider will not change locale for everyone. It is possible that correct locale is not installed at all. So there are lots of reimplementation of fgetscv ;)

at lapstore doot de the webmaster

Some of you might need this:
CSV-Parser optimized for -speed- which can handle linebreaks in quoted strings
This parser can not handle unquoted data containing quotes ("), i.e. apple, ban"ana, cherry
<?php
// csv.inc.php
//
// Usage:
// use argument chopnl=true to autoconvert linebreaks in strings to spaces
$csv_data = "apple; banana; \"multi-\nline\";\"string with \"\" quoted quotes\";\n";
$csv_data .= "second;line;with;trailing;colon\n";
$csv_data .= "third;line;without;trailing;colon;";
$prepared = csv_prepare($csv_data);
while ($myrow = csv_getrow(&$prepared, false)) {
 echo "Row ".csv_rownumber(&$prepared).": ";
 for ($i = 0;$i < $myrow["c"]; $i++) echo "[".htmlspecialchars($myrow[$i])."]";
 echo "
\n";
}
// ******** public functions ********
function csv_prepare($data) {
$rc = array();
$rc[0] = strtr($data,array("\r\n" => "\n"));
$rc[0] = strtr($rc[0],array("\r" => "\n"));
$rc[1] = 0;
$rc[2] = strlen($rc[0]);
$rc[3] = 0;
return $rc;
}
// data[0] = csv-data
// data[1] = startindex
// data[2] = total length csv
// data[3] = currentrow starting from 1 (only for informational purposes)
function csv_rownumber(&$data) {
return $data[3];
}
function csv_getrow(&$data, $chopnl) {
$data[3] += 1;
$rc = array();
$line = csv__getline(&$data);
$line = trim($line);
$len = strlen($line);
$start = 0;
if ($len == 0 && $data[1] >= $data[2]) {
return false;
}

$iter = 0;
while ($iter < 500) {
$item = csv__getitem(&$line, $chopnl, &$start, $len);
$rc[$iter] = $item;
$iter += 1;
if ($start >= $len) break;
}
$rc["c"] = $iter;
return $rc;
}
// ************ Internals *********
function csv__getline(&$data) {
$sep = csv__extract(&$data[0], "\n", $data[1], $data[2]);
$oi = $data[1];
$data[1] = $sep + 1;
return substr($data[0],$oi,$sep - $oi);
}
function csv__getitem(&$data, $chopnl, &$start, $len) {
$sep = csv__extract(&$data, ";",$start, $len);
$rc = trim(substr($data,$start,$sep - $start));
$start = $sep + 1;
if (substr($rc,0,1) == "\"") {
if (substr($rc,strlen($rc) - 1,1) == "\"") {
$rc = substr($rc,1,strlen($rc) - 2);
}
}
$rc = strtr($rc,array("\"\"" => "\""));
if ($chopnl) {
$rc = strtr($rc,array("\n" => " "));
}
return trim($rc);
}
function csv__extract(&$data, $sep, $startidx, $len) {
$instr = false;
for ($i=$startidx;$i < $len; $i+=1) {
$c = $data[$i];
if ($c == "\"") {
if ($instr) {
$c2 = ($i < $len - 1) ? $data[$i + 1] : "";
if ($c2 == "\"") {
$i += 1;
continue;
} else {
$instr = false;
}
} else {
$instr = true;
}
} elseif ($c == $sep) {
if ($instr) {
continue;
} else {
return $i;
}
}
}
return $len;
}
?>


ariel asphp

Should you need it, here is a nice and simple function for escaping csv fields properly.
This version is conditional - it only adds quotes if needed:
<?
function csv_escape($str) {
   $str = str_replace(array('"', ',', "\n", "\r"), array('""', ',', "\n", "\r"), $str, &$count);
   if($count) {
       return '"' . $str . '"';
   } else {
       return $str;
   }
}
?>
This version is even simpler, but adds quotes even if not needed.
<?
function csv_escape($str) {
   return = '"' . str_replace('"','""', $str) . '"';
}
?>


php

Re: LEON _AT_ TIM-ONLINE _DOT_ NL
12-Oct-2006 09:47
Very Handy Function, thanks! However I needed to tweak it a bit: (remove the var_dump, store the info in the big array when using columnheadings and forward $enclosure to the fgetcsv)
<?php
function parse_csv_file($file, $columnheadings = false, $delimiter = ',', $enclosure = null) {
  $row = 1;
  $rows = array();
  $handle = fopen($file, 'r');
 
  while (($data = fgetcsv($handle, 1000, $delimiter, $enclosure )) !== FALSE) {
      if ($columnheadings == true && $row == 1) {
          $headingTexts = $data;
      }
      elseif ($columnheadings == true) {
          foreach ($data as $key => $value) {
              unset($data[$key]);
              $data[$headingTexts[$key]] = $value;
          }
          $rows[] = $data;
      }
      else {
          $rows[] = $data;
      }
      $row++;
  }
 
  fclose($handle);
  return $rows;
} ?>


myrddin

RE post by:-  stinkyj at gmail dot com
02-Aug-2006 10:15
the enclosure param defaulting to " and giving a warning if it's an empty string makes this function nearly worthless. csv files do not always have the fields enclosed, and in those cases it doesn't work.
---------
I had the same problem with this as well, enclosure really should be possible to be made null.
However, perhaps a solution to the problem is to use "\n" as the enclosure character in fgetcsv. As far as I tested it seems to work out just fine. I was thinking of using "\0" but that may cause problems with some data files. If anyone knows of any issues that might crop up when using "\n" as enclosure, please post away. Thanks.


c dot greennosp

Quoting csv is pretty simple, and there are two steps..I note in previous comments only the second step has been explained.
First fields with double quotes need to double up the quotes, ie _He said "Timmy"..._ should become _He said ""Timmy""..._
Secondly as mentioned above, fields with commas need double quotes.
Here is a simple function to achieve this, that I pass to array walk, if you want to use it somewhere else, prob get rid of reference and return the value.
function check_csv_field_ref(&$item) {
  $item = str_replace('"', '""', $item);
  if (strpos($item, ",") !== FALSE) {
    $item = '"' . $item . '"';
  }
}


kyle

Quick and dirty script to take a csv file and turn it into a multidimensional associative array structure using the first line of the csv as the hash key names.
<?
$i = 0;
$handle = fopen ("file.csv","r");
while($data = fgetcsv ($handle, 1000, ",")) {
if ($i == 0) { $key_arr = $data; }
reset($key_arr);
while(list($index,$name) = each($key_arr)) { $temp_arr[$name] = $data[$index]; }
$result_arr[$i] = $temp_arr;
$i++;
}
fclose ($handle);
?>


tim henderson

Only problem with fgetcsv(), at least in PHP 4.x -- any stray slash in the data that happens to come before a double-quote delimiter will break it -- ie, cause the field delimiter to be escaped. I can't find a direct way to deal with it, since fgetcsv() doesn't give you a chance to manipulate the line before it reads it and parses it...I've had to change all occurrences of '\"' to '" in the file first before feeding ot to fgetcsv(). Otherwise this is perfect for that Microsoft-CSV formula, deals gracefully with all the issues.

daniel

Note that fgetcsv() uses the system locale setting to make assumptions about character encoding.
So if you are trying to process a UTF-8 CSV file on an EUC-JP server (for example),
you will need to do something like this before you call fgetcsv():
setlocale(LC_ALL, 'ja_JP.UTF8');
[Also not that setlocale() doesn't *permanently* affect the system locale setting]


tokai

Newer PHP versions handle cvs files slightly different than older versions.
"Max Mustermann"|"Muster Road 34b"|"Berlin"    |"Germany"
"Sophie Master" |"Riverstreet"    |"Washington"|"USA"
The extra spaces behind a few fields in the example (which are useful, when you manually manage a small csv database to align the columns) were ignored by fgetcsv from PHP 4.3. With the new 4.4.1 release they get appended to the string, so you end up with "Riverstreet    " instead the expected "Riverstreet".
Easy workaround is to just trim all fields after reading them in.
while ( $data = fgetcsv($database, 32768, "|") )
{
   $i = 0;
   
   while(isset($data[$i]))
   {
       $data[$i] = rtrim($data[$i]);
       $i++;
   }
   ....
}


31-jan-2007 04:23

just another csv file parse function
<?php
define('CSV_BOTH', 1);
define('CSV_ASSOC', 2);
define('CSV_NUM', 3);
function parse_csv($filename, $result_type = CSV_BOTH) {
if(!file_exists($filename)) {
die("file (" . $filename . ") does not exist\n");
}

$lines = file($filename);

$title_line = trim(array_shift($lines));
$titles = split(",", $title_line);

$records = array();
foreach($lines as $line_num => $line) {
$subject = trim($line);
$fields = array();
for($field_num = 0; $field_num < count($titles); $field_num++) {
if($subject{0} == '"') {
preg_match('/^"(([^"]|\\")*)",?(.*)$/', $subject, $matches);

$value = $matches[1];
$subject = $matches[3];

if($result_type == CSV_BOTH || $result_type == CSV_ASSOC) {
$fields[$titles[$field_num]] = $value;
}

if($result_type == CSV_BOTH || $result_type == CSV_NUM) {
$fields[$field_num] = $value;
}
} else {
preg_match('/^([^,]*),?(.*)$/', $subject, $matches);

$value = $matches[1];
$subject = $matches[2];

if($result_type == CSV_BOTH || $result_type == CSV_ASSOC) {
$fields[$titles[$field_num]] = $value;
}

if($result_type == CSV_BOTH || $result_type == CSV_NUM) {
$fields[$field_num] = $value;
}
}
}

$records[] = $fields;
}
return $records;
}
?>


anykey

just a little change to avoid eternal cycle with unenclosed last column value
<?php
function parseCsvLine($str) {
$delimier = ';';
$qualifier = '"';
$qualifierEscape = '\\';
$fields = array();
while (strlen($str) > 0) {
if ($str{0} == $delimier)
$str = substr($str, 1);
if ($str{0} == $qualifier) {
$value = '';
for ($i = 1; $i < strlen($str); $i++) {
if (($str{$i} == $qualifier) && ($str{$i-1} != $qualifierEscape)) {
$str = substr($str, (strlen($value) + 2));
$value = str_replace(($qualifierEscape.$qualifier), $qualifier, $value);
break;
}
$value .= $str{$i};
}
} else {
$end = strpos($str, $delimier);
$value = ($end > -1) ? substr($str, 0, $end) : $str;
$str = substr($str, strlen($value));
}
$fields[] = $value;
}
return $fields;
}
?>


chery79

inserting IP-to-Country Database into mysql
<?
//CREATE TABLE `ip2country` (
// `id` int(25) NOT NULL default '0',
//  `ipFrom` int(15) NOT NULL default '0',
//  `ipTo` int(15) NOT NULL default '0',
//  `country2` char(2) NOT NULL default '',
//  `country3` char(3) NOT NULL default '',
//  `country` varchar(25) NOT NULL default ''
//) TYPE=MyISAM;
$link = mysql_connect("localhost", "username", "password") or die("Could not connect: ".mysql_error());
// username = user account name
// password = password to user acc
$db = mysql_select_db("ip2country") or die(mysql_error());
// ip2country table is define on top
$row = 1;
$handle = fopen ("ip-to-country.csv","r");
// ip-to-country.csv must be in the same directory with this php file
while ($data = fgetcsv ($handle, 1000, ",")) {
$query = "INSERT INTO ip2country(`id`, `ipFrom`, `ipTo`, `country2`, `country3`, `country`) VALUES('".
$row."', '".$data[0]."', '".$data[1]."', '".$data[2]."', '".$data[3]."', '".$data[4]."')";
$result = mysql_query($query) or die("Invalid query: " . mysql_error().__LINE__.__FILE__);
   $row++;
}
fclose ($handle);
?>


mickoz

In "php at dogpoop dot cjb dot net" post, I would change in his function:
function csv_split($line,$delim=',',$removeQuotes=true)
this code:
if ($line[$i+1] == '"') {
to:
if ($i+1 < strlen($line) && $line[$i+1] == '"') {
The reason is that if the quote (") is at the last line of the string, then it will try to reach an undefined space in the string, therefore giving a PHP error.
Of course his function is great if your line is a true compatible csv line, but I leave that to you to judge if you can do this assumption ;-)


ng4rrjanbiah

Important note about the CSV format:
There should *not* be any space in between the fields. For example,
field1, field2, field3 [Wrong!]
field1,field2,field3 [Correct-No space between fields]
If you add space between the fields, MS Excel won't recognize the fields (especially date and multi-line text fields).
HTH,
R. Rajesh Jeba Anbiah


justin

If you're working in Excel on a Mac and are exporting a spreadsheet as a CSV, PHP won't recognise the line breaks, and interprets the file as one really long line.  It borders on a bug really.  For me, I just open the file in BBEdit or BBEdit Lite, convert the file from Mac to Unix, and all is well.  But if you're dealing with user-contributed files, you'll need to convert the line-endings first... replacing all \r's with \n's should do it.

aidan

If you're looking to parse CSV files but find fgetcvs insufficient, check out http://pear.php.net/package/File

skakunov alexander
If you need to import a huge CSV file into a database, use the bulk insert technique instead of many line-by-line inserts:
- MSSQL: bcp tool and "BULK INSERT" SQL
- MySQL: mysqlimport tool and "LOAD DATA INFILE" SQL
As for MySQL, you can use the ready "Quick CSV import" class at http://a4.users.phpclasses.org/browse/package/2917.html


r

If you had a problem with fgetcsv and multibyte characters, you have to set the correct local setting:
<?php
setlocale(LC_ALL, 'en_US.UTF-8');
?>
Change it to your local settings and/or charset.


brian

If anyone else is taking on the task of converting from FileMaker Pro to MySQL, you might find this useful:
Here's a collection of simple functions that take a CSV file, re-formats the data and writes to a file with MySQL INSERTs.  
ORIGINAL DATA:
"1", "foo", "2"
"3", "bar", "4"
OUTPUT
INSERT info mysql_table VALUES('', '1', 'foo', '2');
INSERT info mysql_table VALUES('', '3', 'bar', '4');
For simple data it works alright, but I could not find a way to escape the contents before assembling the INSERT statements - kept getting "bad argument for implode()"...
<?php
/*************************************
*                  main              *
*************************************/
$file = "path/to/your/file.txt";
$tbl = "your_MySQL_table";
$CSVarray = get_csv($file);
$CSVarray = makeINSERTS($CSVarray, "$tbl");

$filetowrite = $_POST["file"]."_sql.txt";
$fp = fopen($filetowrite, "w");
while (list($key, $val) = @each($CSVarray)) {
     fwrite($fp, $val);
}
fclose($fp);
chmod($filetowrite, 0777);
echo "File written Successfully";

}
/*************************************
*                  functions         *
*************************************/
// This function courtesy of drudge@phpcoders.net
function get_csv($filename, $delim =","){
$row = 0;
$dump = array();

$f = fopen ($filename,"r");
$size = filesize($filename)+1;
while ($data = fgetcsv($f, $size, $delim)) {
$dump[$row] = $data;
//echo $data[1]."
";
$row++;
}
fclose ($f);

return $dump;
}
function makeINSERT($text, $table){
$insert = array();
$i = 0;

while (list($key, $val) = @each($text)){
// We'll start off the INSERT with '', for an
// auto-incremented key.  Remove if not needed.

$insert[$i] = "INSERT into ".$table." VALUES('','";
$insert[$i] .= implode("','", $val);
$insert[$i] .= "');\n";

$i++;
}

return $insert;
}
?>


mendi dot susanto

I've tried the code above but doesn't work, so I tried to modify it... this is the code to get the first line of csv fle, puti it into TABLE 1, while the rest line of csv file will be put at TABLE 2
<?php
$openfile = "tes2.csv";
$row = 0;
$handle = fopen ($openfile,"r");
while ($data = fgetcsv ($handle, 1000, ","))
{
   if($row == '0')
{
$num = count ($data);
print "

$num fields in line $row:
\n";
echo "This belong to TABLE 1
";
for ($c=0; $c < $num; $c++)
{
print $data[$c] . "
\n";
}
$row = '32';
}
else
{
$num = count ($data);
print "

$num fields in line $row:
\n";
$row++;
echo "This belong to TABLE 2
";
for ($c=0; $c < $num; $c++)
{
print $data[$c] . "
\n";
}
}
}
fclose ($handle);
?>


shaun

I've seen alot of people talking about ways to convert from mac to unix or from dos to unix.
For DOS to UNIX I use dos2unix in the "tofrodos Ver 1.4" package.
http://www.thefreecountry.com/tofrodos/index.shtml
For Mac to UNIX I have the follwing in my .bashrc
alias mac2unix="perl -pi -e 'tr/\015/\012/'"
Just run dos2unix or mac2unix <filename> and it will convert.  My life has been easier ever since I started installing these utilities.


jc

I've had alot of projects recently dealing with csv files, so I created the following class to read a csv file and return an array of arrays with the column names as keys. The only requirement is that the 1st row contain the column headings.
I only wrote it today, so I'll probably expand on it in the near future.
<?php
class CSVparse
 {
 var $mappings = array();
 function parse_file($filename)
   {
   $id = fopen($filename, "r"); //open the file
   $data = fgetcsv($id, filesize($filename)); /*This will get us the */
                                              /*main column names */
   if(!$this->mappings)
      $this->mappings = $data;
   while($data = fgetcsv($id, filesize($filename)))
       {
        if($data[0])
          {
           foreach($data as $key => $value)
              $converted_data[$this->mappings[$key]] = addslashes($value);
           $table[] = $converted_data; /* put each line into */
            }                                 /* its own entry in    */
        }                                     /* the $table array    */
   fclose($id); //close file
   return $table;
   }
 }
?>


elainy

I wrote this little thingy to allow the customer to upload csv-files to his page which will then automatically be converted to a php-include-file with a html-table for inclusion in his homepage.
Its a little buggy since it can't handle rowspan and such, but otherwise it works well.
<?php
function csv2php($filename, $delim=';',$path)
{
   $row = 0;
   $dump = array();
   $once = 0;
   $max_cols = 0;
   // open file - get number of columns - make data Array
   $f = fopen ($filename,"r");
   $size = filesize($filename)+1;
   while ($data = fgetcsv($f,$size,$delim,''))
   {
       for($o=0;$o<sizeof($data);$o++)
       {
            if($once==0)
                $max_cols++;
       }
       $dump[$row] = $data;
       if($once==0)
           $once=1;
       $row++;
   }
   fclose ($f);
   /////// make text for php-include file
   $printtext="<table border='0' cellspacing='0' cellpadding='0'>\n";
   /////// walk the rows
   for($x=0;$x<sizeof($dump);$x++)
   {
        $printtext.="<tr>\n";
        /////// !!!! Table is built with as many columns as the first row has !!!!!!
        for($y=0,$limiter=0;(($y<sizeof($dump[$x])) || ($limiter<$max_cols));$y++,$limiter++)
        {
             $printtext.="\t<td>";
             if($dump[$x][$y]!='')
                 $printtext.=$dump[$x][$y];
             else
                 $printtext.=" ";
             $printtext.="</td>\n";
        }
        $printtext.="</tr>\n";
   }
   $printtext.="</table>\n";
   $ident = write_dammit($printtext,$path);
   return $ident;
}
function write_dammit($printtext,$path)
{
        $ident=time();
        $filename=$ident;
        $filename .= ".inc.php";
        $filecontents = $printtext;
        $fp = fopen("$path/$filename","w"); // if in windows you have to chace the / to \\
        fwrite($fp,$filecontents);
        fclose($fp);
        return $ident;
}
$ident = csv2php("table.csv",";","C:/your_include_folder/");
require($ident.".inc.php");
?>


leon _at_ tim-online _dot_ nl

I wrote this function for myself. I think it's handy:
function parse_csv_file($file, $columnheadings = false, $delimiter = ',', $enclosure = null) {
$row = 1;
$rows = array();
$handle = fopen($file, 'r');

while (($data = fgetcsv($handle, 1000, $delimiter)) !== FALSE) {
if ($columnheadings == true && $row == 1) {
$headingTexts = $data;
}
elseif ($columnheadings == true) {
var_dump($data);
foreach ($data as $key => $value) {
unset($data[$key]);
$data[$headingTexts[$key]] = $value;
}
}
else {
$rows[] = $data;
}
$row++;
}

fclose($handle);
return $rows;
}


abu1980

I was using the function to import a csv file that had some values with "\" included this confused the import function to ignore the End of line and hence an incorrect number of rows is returned to me.
Suggest you try to replace that \ and { brackets as well since they have the same function of an escape character before u import the function
thanks


spam

I needed a fast/robust csv parser in PHP that could handle unix-, windows- and mac-style linebreaks.
i takes a csv-string as input and outputs a multidimensional array with lines and fields.
<?php
function parse_csv_php(&$data,$delim=',',$enclosure='"')
{
$enclosed=false;
$fldcount=0;
$linecount=0;
$fldval='';
for($i=0;$i<strlen($data);$i++)
{
 $chr=$data{$i};
 switch($chr)
 {
  case $enclosure:
   if($enclosed&&$data{$i+1}==$enclosure)
   {
    $fldval.=$chr;
    ++$i; //skip next char
   }
   else
    $enclosed=!$enclosed;
   break;
  case $delim:
   if(!$enclosed)
   {
    $ret_array[$linecount][$fldcount++]=$fldval;
    $fldval='';
   }
   else
    $fldval.=$chr;
   break;
  case "\\r":
   if(!$enclosed&&$data{$i+1}=="\\n")
    continue;
  case "\\n":
   if(!$enclosed)
   {
    $ret_array[$linecount++][$fldcount]=$fldval;
    $fldcount=0;
    $fldval='';
   }
   else
    $fldval.=$chr;
   break;
  default:
   $fldval.=$chr;
 }
}
if($fldval)
 $ret_array[$linecount][$fldcount]=$fldval;
return $ret_array;
}
?>


jon

I modified the code for my own purposes, to return an array with named keys for each field. I tried various alternatives, and this seems to work well with exported Excel data.
<pre><?php
//Move through a CSV file, and output an associative array for each line
ini_set("auto_detect_line_endings", 1);
$current_row = 1;
$handle = fopen("testdatasource.csv", "r");
while ( ($data = fgetcsv($handle, 10000, ",") ) !== FALSE )
{
$number_of_fields = count($data);
if ($current_row == 1)
{
//Header line
for ($c=0; $c < $number_of_fields; $c++)
{
$header_array[$c] = $data[$c];
}
}
else
{
//Data line
for ($c=0; $c < $number_of_fields; $c++)
{
$data_array[$header_array[$c]] = $data[$c];
}
print_r($data_array);
}
$current_row++;
}
fclose($handle);
//Look at my photos www.jonhassall.com !
?></pre>
Jon Hassall


eoj

I had a problem with fgetcsv and multibyte characters so i used one of functions below (16-Nov-2002 04:01 to be specific) and modified it to be (hopefully) multibyte safe.
<?php
/**
* @param the csv line to be split
* @param the delimiter to split by (default ';' )
* @param if this is false, the quotation marks won't be removed from the fields (default true)
*/
function mb_csv_split($line, $delim = ';', $removeQuotes = true) {
$fields = array();
$fldCount = 0;
$inQuotes = false;
for ($i = 0; $i < mb_strlen($line); $i++) {
if (!isset($fields[$fldCount])) $fields[$fldCount] = "";
$tmp = mb_substr($line, $i, mb_strlen($delim));
if ($tmp === $delim && !$inQuotes) {
$fldCount++;
$i+= mb_strlen($delim) - 1;
}
else if ($fields[$fldCount] == "" && mb_substr($line, $i, 1) == '"' && !$inQuotes) {
if (!$removeQuotes) $fields[$fldCount] .= mb_substr($line, $i, 1);
$inQuotes = true;
}
else if (mb_substr($line, $i, 1) == '"') {
if (mb_substr($line, $i+1, 1) == '"') {
$i++;
$fields[$fldCount] .= mb_substr($line, $i, 1);
} else {
if (!$removeQuotes) $fields[$fldCount] .= mb_substr($line, $i, 1);
$inQuotes = false;
}
}
else {
$fields[$fldCount] .= mb_substr($line, $i, 1);
}
}
return $fields;
}
?>


bu

I found a way to parse CSVs with Perl RegExps and it's a lot faster and more efficient than the conventional fgetcsv() way.
The fgetcsv() took more than 2 minutes to parse a 15,000 lined file while my function takes 6 to 7 secs on a Celeron 366 MHz prehistoric machine.
Here's a link to the source of my function.
fgetcsvfromline() source
http://bu.orbitel.bg/fgetcsvfromline.php
fgetcsvfromline() in action
http://bu.orbitel.bg/csv.php
Please let me know if you use it or if you've found a better solution.


pinkgothic

I find the documentation mildly misleading:
fgetcsv() does not - as this documentation seemingly claims in the descriptive line - get a line out of the file (via the file pointer) and then parses this for CSV fields, but instead retrieves a CSV row out of the file, which it then splits into an array.
The difference may seem trivial, but reading the description of this function I feared it might not support linebreaks in individual CSV values. Testing, however, revealed that fgetcsv() [fortunately!] works as one would expect from a CSV parser, and my fears were without cause.
In fact, fgetcsv() is remarkably hard to break. It's not confused by the value """,""" for example (three quotation marks followed by a comma followed by three quotation marks - which represents the value "quotation mark, comma, quotation mark" in case it's not immediately obvious).
I hope this extra documentation is helpful for someone.


mortanon

Hier is an example for a CSV Iterator.
<?php
class CsvIterator implements Iterator
{
const ROW_SIZE = 4096;
/**
* The pointer to the cvs file.
* @var resource
* @access private
*/
private $filePointer = null;
/**
* The current element, which will
* be returned on each iteration.
* @var array
* @access private
*/
private $currentElement = null;
/**
* The row counter.
* @var int
* @access private
*/
private $rowCounter = null;
/**
* The delimiter for the csv file.
* @var str
* @access private
*/
private $delimiter = null;
/**
* This is the constructor.It try to open the csv file.The method throws an exception
* on failure.
*
* @access public
* @param str $file The csv file.
* @param str $delimiter The delimiter.
*
* @throws Exception
*/
public function __construct($file, $delimiter=',')
{
try {
$this->filePointer = fopen($file, 'r');
$this->delimiter = $delimiter;
}
catch (Exception $e) {
throw new Exception('The file "'.$file.'" cannot be read.');
}
}
/**
* This method resets the file pointer.
*
* @access public
*/
public function rewind() {
$this->rowCounter = 0;
rewind($this->filePointer);
}
/**
* This method returns the current csv row as a 2 dimensional array
*
* @access public
* @return array The current csv row as a 2 dimensional array
*/
public function current() {
$this->currentElement = fgetcsv($this->filePointer, self::ROW_SIZE, $this->delimiter);
$this->rowCounter++;
return $this->currentElement;
}
/**
* This method returns the current row number.
*
* @access public
* @return int The current row number
*/
public function key() {
return $this->rowCounter;
}
/**
* This method checks if the end of file is reached.
*
* @access public
* @return boolean Returns true on EOF reached, false otherwise.
*/
public function next() {
return !feof($this->filePointer);
}
/**
* This method checks if the next row is a valid row.
*
* @access public
* @return boolean If the next row is a valid row.
*/
public function valid() {
if (!$this->next()) {
fclose($this->filePointer);
return false;
}
return true;
}
}
?>
Usage :
<?php
$csvIterator = new CsvIterator('/path/to/csvfile.csv');
foreach ($csvIterator as $row => $data) {
// do somthing with $data
}
?>


slyi

heres a version that take a bugzilla url and spits the results as rss
<?php
$bugzillaurl="http://www.reactos.com/bugzilla/";
$bugquery= $bugzillaurl . "buglist.cgi?query_format=&bug_severity=blocker&ctype=csv";
header('Content-type: text/xml');
echo "<?xml version=\"1.0\" ?>\n";
?>
<rss version="2.0">
 <channel>
   <title>bugzilla csv2rss</title>
   <link><?=$bugzillaurl?></link>
   <description>bugzilla csv2rss</description>
   <language>en-us</language>
<?php
$row = 0;
$handle = fopen($bugquery, "r");
while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {
  if($row == '0') { $row = '8';} //skip title stuff
  else{ // display all bugs
  $row++;
  echo "<item>\n";
  echo "<title>" . htmlspecialchars($data[7], ENT_QUOTES) . "</title>\n";
  echo "<description>" . htmlspecialchars($data[7], ENT_QUOTES) . "</description>\n";
  echo "<link>" . $bugzillaurl . "show_bug.cgi?id=" . $data[0] . "</link>\n";
  echo "</item>\n";
  }
}
fclose($handle);
?>
</channel>
</rss>


essaym.net

Heres a function i wrote because all the other functions on here didnt work quiet as easy as I wanted them to:
It opens the CSV file, and reads it into a 3d array.  If you set $columnsOnly, you will only get the first line.
<?php
function CSV2Array($openFile, $columnsOnly = false)
{
$handle = fopen ($openFile,"r");
$rows = 0;
while (!feof($handle)) {
$columns[] = explode(",", fgets($handle, 4096));
if ($rows++ == 0 && $columnsOnly)
break;
}
fclose ($handle);
return $columns;
}
?>


17-feb-2003 07:23

Here's piece of code I wrote that reads the first line of a CSV file, creates an array based the field's name, and then reads the rest of the contents of the CSV file into the approate arrays.  Great for quick and dirty access to a CSV file.
<?php
// Name of the file to read/
// $openFile is the only varible you will have change to for this to work.
$openFile = "test.csv";
$row = 0;
$handle = fopen ($openFile,"r");
while ($data = fgetcsv ($handle, 1000, ",")) {
if($row == 0){
// set the varible array
$num = count ($data);
$csvNames = array();
for ($c=0; $c < $num; $c++) {
$csvNames[$c] = $data[$c];
eval("$" . $data[$c] . " = array();");
}
$row = 1;
}else{
$num = count ($data);
$row++;
for ($c=0; $c < $num; $c++) {
$buildEval = "$" . $csvNames[$c] . "[" . ($row - 1) . "] = \"" . $data[$c] . "\";";
eval($buildEval );
}
}
}
fclose ($handle);
?>


mjwilco

Here's one way to convert the data in a csv file to an html table:
<?php
$filename = "book1.csv"; //here's the filename
$id = fopen($filename, "r"); //open the file
while ($data = fgetcsv($id, filesize($filename))) //start a loop
$table[] = $data; //put each line into its own entry in the $table array
fclose($id); //close file
echo "<table>\n";
foreach($table as $row)
{
echo "<tr>";
foreach($row as $data)
echo "<td>$data</td>";
echo "</tr>\n";
}
echo "</table>\n";
?>
You may need to change the parameters for fgetcsv() to suit your needs and probably change the table style.


d steer

Here is a simple to include the field names in the array. Altough this is very simple, it does the job fantastically
<?php
print_r(buildStock('stock.csv'));
function buildStock($File) {
$handle = fopen($File, "r");
$fields = fgetcsv($handle, 1000, ",");

while($data = fgetcsv($handle, 1000, ",")) {
$detail[] = $data;
}

$x = 0;
$y = 0;

foreach($detail as $i) {
foreach($fields as $z) {
$stock[$x][$z] = $i[$y];
$y++;
}
$y = 0;
$x++;
}
return $stock;
}
?>


myrddin

Here is a OOP based importer similar to the one posted earlier. However, this is slightly more flexible in that you can import huge files without running out of memory, you just have to use a limit on the get() method
Sample usage for small files:-
-------------------------------------
$importer = new CsvImporter("small.txt",true);
$data = $importer->get();
print_r($data);
Sample usage for large files:-
-------------------------------------
$importer = new CsvImporter("large.txt",true);
while($data = $importer->get(2000))
{
print_r($data);
}
And heres the class:-
-------------------------------------
class CsvImporter
{
   private $fp;
   private $parse_header;
   private $header;
   private $delimiter;
   private $length;
   //--------------------------------------------------------------------
   function __construct($file_name, $parse_header=false, $delimiter="\t", $length=8000)
   {
       $this->fp = fopen($file_name, "r");
       $this->parse_header = $parse_header;
       $this->delimiter = $delimiter;
       $this->length = $length;
       $this->lines = $lines;
       if ($this->parse_header)
       {
          $this->header = fgetcsv($this->fp, $this->length, $this->delimiter);
       }
   }
   //--------------------------------------------------------------------
   function __destruct()
   {
       if ($this->fp)
       {
           fclose($this->fp);
       }
   }
   //--------------------------------------------------------------------
   function get($max_lines=0)
   {
       //if $max_lines is set to 0, then get all the data
       $data = array();
       if ($max_lines > 0)
           $line_count = 0;
       else
           $line_count = -1; // so loop limit is ignored
       while ($line_count < $max_lines && ($row = fgetcsv($this->fp, $this->length, $this->delimiter)) !== FALSE)
       {
           if ($this->parse_header)
           {
               foreach ($this->header as $i => $heading_i)
               {
                   $row_new[$heading_i] = $row[$i];
               }
               $data[] = $row_new;
           }
           else
           {
               $data[] = $row;
           }
           if ($max_lines > 0)
               $line_count++;
       }
       return $data;
   }
   //--------------------------------------------------------------------
}


drudge

Here is a function to read a whole csv file into an array:
<?php
function get_csv($filename, $delim=',')
{
   $row = 0;
   $dump = array();
   
   $f = fopen ($filename,"r");
   $size = filesize($filename)+1;
   while ($data = fgetcsv($f, $size, $delim)) {
       $dump[$row] = $data;
       $row++;
   }
   fclose ($f);
   
   return $dump;
}
?>


blair

Here is a function that takes an array and adds a CSV line to the passed file pointer.
<?php
function fputcsv ($fp, $array, $deliminator=",") {
 $line = "";
 foreach($array as $val) {
   # remove any windows new lines,
# as they interfere with the parsing at the other end
   $val = str_replace("\r\n", "\n", $val);
   # if a deliminator char, a double quote char or a newline
   # are in the field, add quotes
   if(ereg("[$deliminator\"\n\r]", $val)) {
     $val = '"'.str_replace('"', '""', $val).'"';
   }#end if
   $line .= $val.$deliminator;
 }#end foreach
 # strip the last deliminator
 $line = substr($line, 0, (strlen($deliminator) * -1));
 # add the newline
 $line .= "\n";
 # we don't care if the file pointer is invalid,
 # let fputs take care of it
 return fputs($fp, $line);
}#end fputcsv()
?>


joeldegan-at-yahoo.com

function to parse multi arrays into csv data
array in... array of array(datasets); first dataset = field names.
usage:
$toparse[0][0] = "field1";
$toparse[0][1] = "field2";
$toparse[1][0] = "value1";
$toparse[1][1] = "123123123"; // to see
echo export_to_csv($toparse);
<?php
function export_to_csv($inarray){
 while (list ($key1, $val1) = each ($inarray)) {
   while (list ($key, $val) = each ($val1)) {
     if (is_numeric($val)){
$sendback .= $val.",";
      }else{
    $sendback .= "\"". $val ."\",";
     }//fi
   }//wend
   $sendback = substr($sendback, 0, -1); //chop last ,
   $sendback .= "\n";
 }//wend
   return ($sendback);
}// end function
?>
send the file to the client.. pretty simple.
usage: send_file_to_client("data.csv",export_to_csv($data));
<?php
function send_file_to_client($filename, $data){
header("Content-type: application/ofx");
header("Content-Disposition: attachment; filename=$filename");
echo $data;
};
?>


02-mar-2006 02:16

For those of you who need to get CSV data from a single line of quoted CSV (comma delimited) values (that may have commas in the data), use this:
<?
function csv_string_to_array($str){
  $expr="/,(?=(?:[^\"]*\"[^\"]*\")*(?![^\"]*\"))/";
$results=preg_split($expr,trim($str));
return preg_replace("/^\"(.*)\"$/","$1",$results);
}
$str=<<<EOF
"testing, stuff, here","is testing ok",200,456
EOF;
print_r(csv_string_to_array($str));
?>


php

For those of you having problems with Excel's version of CSV file exports (which include the infamous ^M characters in *NIX editors, such as VIM) here is a simple script to remove them and replace them in the normal UNIX newline character (\n).
<?
$fp = fopen('/dev/stdin','r');
while(!feof($fp)){
   $line = chop(fgets($fp,4096));
   $ret = ereg_replace(chr(13) . chr(10),"\n",$line);
   $ret = ereg_replace(chr(13),"\n",$ret);
   echo $ret."\n";
}
fclose($fp);
?>
Usage: cat file_with_windows_newlines | php -q strip_newlines.php > outfile
(this works for other stuff too, like PHP "coders" who use Notepad and upload to a UNIX environment).


marc

for excel-csv-sheets like:
test1;test2;test3;test4;"test5
test5b
test5c";test6
(optionally enclosed by " including line-breaks)
.. i wrote a little function to solve this problem.
<?php
function CSV2Array($content, $delim = ';', $encl = '"', $optional = 1)
{
$reg = '/(('.$encl.')'.($optional?'?(?(2)':'(').
'[^'.$encl.']*'.$encl.'|[^'.
$delim.'\r\n]*))('.$delim.'|\r\n)/smi';
preg_match_all($reg, $content, $treffer);
$linecount = 0;
for ($i = 0; $i<=count($treffer[3]);$i++)
{
$liste[$linecount][] = $treffer[1][$i];
if ($treffer[3][$i] != $delim)
$linecount++;
}
return $liste;
}
// usage for example:
$content = join('',file('test.csv'));
$liste = CSV2Array($content);
print_r($liste);
?>


guntars

For all those people struggling with Macintosh conversions, since PHP 4.3 there is a new runtime setting available:
auto_detect_line_endings boolean
When turned on, PHP will examine the data read by fgets() and file() to see if it is using Unix, MS-Dos or Macintosh line-ending conventions.
This enables PHP to interoperate with Macintosh systems, but defaults to Off, as there is a very small performance penalty when detecting the EOL conventions for the first line, and also because people using carriage-returns as item separators under Unix systems would experience non-backwards-compatible behaviour.


anykey

final version...
<?php
private function parseCsvLine($str) {
$delimier = ';';
$qualifier = '"';
$qualifierEscape = '\\';
$fields = array();
while (strlen($str) > 0) {
if ($str{0} == $delimier)
$str = substr($str, 1);
if ($str{0} == $qualifier) {
$value = '';
for ($i = 1; $i < strlen($str); $i++) {
if (($str{$i} == $qualifier) && ($str{$i-1} != $qualifierEscape)) {
$str = substr($str, (strlen($value) + 2));
$value = str_replace(($qualifierEscape.$qualifier), $qualifier, $value);
break;
}
$value .= $str{$i};
}
} else {
$end = strpos($str, $delimier);
$value = ($end !== false) ? substr($str, 0, $end) : $str;
$str = substr($str, strlen($value));
}
$fields[] = $value;
}
return $fields;
}
?>


anthony dot thomas

fgetcsv stops reading your file?
I had to write a script to validate and import a large amount of data to MySQL and it would stop running. I've noticed, after trawling the internet for a solution, quite a few people have had similar problems.
Solution? Like a dope I had forgotten to put in
set_time_limit()
within a loop. Otherwise the script would time out before it finished importing all the data.
Moral of the story? Only suppress errors after your script works with a large amount of test data!


18-nov-2004 06:47

example 1 above goes into an infinte loop if the file name is bad because fgetcsv return a false result not identical to false but equl to false
to fix this use != instead of !== in the test as shown below it will still work correctly for the case when the file exists.
while (($data = fgetcsv($handle, 1000, ",")) != FALSE) {


bob kolk

Dave Meiners above example is great, except that you need to need to add one to the final length to account for EOL.  So it'd be:
while ($data = fgetcsv($handle, ($length+1), ","))


reptilex

beware of using this function in two different php versions,
in php 4.3 the 4th parameter can be given altough empty
in php 4.2 you get just a warning but it is not able to read the csv file if you place an enclosure that is empty


27-feb-2006 11:05

beware of characters of binary value == 0, as they seem to make fgetcsv ignore the remaining part of a line where they appear.
Maybe this is normal under some convention I don't know, but a file exported from Excel had those as values for some cells *sometimes*, thus fgetcsv return variable cell counts for different lines.
i'm using php 4.3


ramdac

Be wary of Example #1 above.
If the file doesn't exist, the application will spit out data to STDOUT and could fill up /tmp space if you're not careful. The output might will look like this:
PHP Warning:  fgetcsv(): supplied argument is not a valid stream resource in...(your filename here)
To get around this, do the following:
<?
row = 1;
if(!$handle = fopen("test.csv", "r"))
{
    print 'could not open file. quitting';
     die;
}
while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {
  $num = count($data);
  echo "

$num fields in line $row: <br />\n";
  $row++;
  for ($c=0; $c < $num; $c++) {
      echo $data[$c] . "<br />\n";
  }
}
fclose($handle);
?>


junk

Based on my observations a few comments below I have written a class that incorporates all these features. Here is the class description:
----------
This class will parse a csv file in either standard or MS Excel format.
Two methods are provided to either process a line at a time or return the whole csv file as an array.
It can deal with:
- Line breaks within quoted fields
- Character seperator (usually a comma or semicolon) in quoted fields
- Can leave or remove leading and trailing spaces or tabs
- Can leave or skip empty rows.
- Windows and Unix line breaks dealt with automatically. (Care must be taken with Macintosh format.)
Also, the escape character is automatically removed.
-----------
So basically it should "just work". If it doesn't please send me an email ;-)
You can download it from: http://www.phpclasses.org/browse/package/2672.html
An example on how to use the class and a test.csv file are also provided.


phpnet

Another version [modified michael from mediaconcepts]
<?php
 function arrayFromCSV($file, $hasFieldNames = false, $delimiter = ',', $enclosure='') {
   $result = Array();
   $size = filesize($file) +1;
   $file = fopen($file, 'r');
   #TO DO: There must be a better way of finding out the size of the longest row... until then
   if ($hasFieldNames) $keys = fgetcsv($file, $size, $delimiter, $enclosure);
   while ($row = fgetcsv($file, $size, $delimiter, $enclosure)) {
       $n = count($row); $res=array();
       for($i = 0; $i < $n; $i++) {
           $idx = ($hasFieldNames) ? $keys[$i] : $i;
           $res[$idx] = $row[i];
       }
       $result[] = $res;
   }
   fclose($file);
   return $result;
 }
?>


gibson.a.paul

a simple script to output the contents of a CSV file as a nice table - should be totally dynamic and can use any seperator - it does not have to be a comma (,).
I don't perclaim my code is 100% perfect or correct, but it works.  useful if you back up your cell phone address book and it outputs CSV.
It works on the assumtion that the first line is the header row.
<?
//Define what you want the seperator to be, this could be new line, (\n) a tab (\t) or any other char, for obvious reasons avoid using chars that will be present in the string.  Id suggest a comma, or semicolon.
$sep = ",";
//define file to read
$file = "test.txt";
//read the file into an array
$lines = file($file);
//count the array
$numlines = count($lines);
//explode the first (0) line which will be the header line
$headers = explode($sep, $lines[0]);
//count the number of headers
$numheaders = count($headers);
$i = 0;
//start formatting output
echo "<table border = 1 cellpadding = 2><tr>";
//loop through the headers outputting them into their own <TD> cells
while($i<$numheaders){
       $headers = str_replace("\"", "", $headers);
       echo "<td>".$headers[$i]."</td>";
       $i++;
       }
echo "</tr>";
$y = 1;
//Output the data, looping through the number of lines of data and also looping through the number of cells in each line, as this is a dynamic number the header length has to be reread.
while($y<$numlines){
       $x=0;
       echo "<TR>";
               while($x<$numheaders){
               $fields = explode($sep, $lines[$y]);
               $fields = str_replace("\"", "", $fields);
               echo "<TD>&nbsp;".$fields[$x]." </TD>";
               $x++;
                       }
       $y++;
       echo "</TR>";
       }
//close the table.
echo "</table>";
?>


daevid

A much simpler way to map the heading/column names to the elements on each line. It also doesn't fill up one big array which could cause you to run out of memory on large datasets. This loads one at a time so you can process/insert to db/etc...
$handle = fopen('somefile.csv', 'r');
if ($handle)
{
set_time_limit(0);

//the top line is the field names
$fields = fgetcsv($handle, 4096, ',');

//loop through one row at a time
while (($data = fgetcsv($handle, 4096, ',')) !== FALSE)
{
$data = array_combine($fields, $data);
}
fclose($handle);
}


nospam-michael

A little contribution to make it more easy to use this function when working with a database. I noticed this function doesn't add logical keys to the array, so I made a small function which creates a 2dimensional array with the corresponding keys added to the rows.
<?php
// this function requires that the first line of your CSV file consists of the keys corresponding to the values of the other lines
function convertCSVtoAssocMArray($file, $delimiter)
{
$result = Array();
$size = filesize($file) +1;
$file = fopen($file, 'r');
$keys = fgetcsv($file, $size, $delimiter);
while ($row = fgetcsv($file, $size, $delimiter))
{
for($i = 0; $i < count($row); $i++)
{
if(array_key_exists($i, $keys))
{
$row[$keys[$i]] = $row[$i];
}
}
$result[] = $row;
}
fclose($file);
return $result;
}
?>


01-may-2007 10:07

a flexible parser that can be used for csv or tsv (or any delimited flatfile data source).
<?php
/* assumes a single line of input; automatically determines the number of fields */
function parse_line($input_text, $delimiter = ',', $text_qualifier = '"') {
$text = trim($input_text);

if(is_string($delimiter) && is_string($text_qualifier)) {
$re_d = '\x' . dechex(ord($delimiter)); //format for regexp
$re_tq = '\x' . dechex(ord($text_qualifier)); //format for regexp

$fields = array();
$field_num = 0;
while(strlen($text) > 0) {
if($text{0} == $text_qualifier) {
preg_match('/^' . $re_tq . '((?:[^' . $re_tq . ']|(?<=\x5c)' . $re_tq . ')*)' . $re_tq . $re_d . '?(.*)$/', $text, $matches);

$value = str_replace('\\' . $text_qualifier, $text_qualifier, $matches[1]);
$text = trim($matches[2]);

$fields[$field_num++] = $value;
} else {
preg_match('/^([^' . $re_d . ']*)' . $re_d . '?(.*)$/', $text, $matches);

$value = $matches[1];
$text = trim($matches[2]);

$fields[$field_num++] = $value;
}
}

return $fields;
} else {
return false;
}
}
?>


e

A 5.2 way to lazily parse a single CSV line
function parseCSV($str, $delimiter = ',', $enclosure = '"', $len = 4096)
{
 $fh = fopen('php://memory', 'rw');
 fwrite($fh, $str);
 rewind($fh);
 $result = fgetcsv( $fh, $len, $delimiter, $enclosure );
 fclose($fh);
 return $result;
}


donnoman

/**
* Based on an example by ramdac at ramdac dot org
* Returns a multi-dimensional array from a CSV file optionally using the
* first row as a header to create the underlying data as associative arrays.
* @param string $file Filepath including filename
* @param bool $head Use first row as header.
* @param string $delim Specify a delimiter other than a comma.
* @param int $len Line length to be passed to fgetcsv
* @return array or false on failure to retrieve any rows.
*/
function importcsv($file,$head=false,$delim=",",$len=1000) {
$return = false;
$handle = fopen($file, "r");
if ($head) {
$header = fgetcsv($handle, $len, $delim);
}
while (($data = fgetcsv($handle, $len, $delim)) !== FALSE) {
if ($head AND isset($header)) {
foreach ($header as $key=>$heading) {
$row[$heading]=(isset($data[$key])) ? $data[$key] : '';
}
$return[]=$row;
} else {
$return[]=$data;
}
}
fclose($handle);
return $return;
}


anykey

<?
function parseCsvLine($str) {
$delimier = ';';
$qualifier = '"';
$qualifierEscape = '\\';
$fields = array();
while (strlen($str) > 0) {
if ($str{0} == $delimier)
$str = substr($str, 1);
if ($str{0} == $qualifier) {
$value = '';
for ($i = 1; $i < strlen($str); $i++) {
if (($str{$i} == $qualifier) && ($str{$i-1} != $qualifierEscape)) {
$str = substr($str, (strlen($value) + 2));
break;
}
$value .= $str{$i};
}
} else {
$end = strpos($str, $delimier);
$value = ($end > -1) ? substr($str, 0, $end) : '';
$str = substr($str, strlen($value));
}
$fields[] = $value;
}
return $fields;
}
?>


cristian dot zuddas

"marc at henklein dot com" posted a cool function "CSV2Array", but there's an error. If the last char of the CSV file isn't a carriage return, the function can't take the last field of the last line in the CSV.
Fixed adding this check:
<?
if ($content[strlen($content)-1]!="\r" && $content[strlen($content)-1]!="\n")
$content .= "\r\n";
?>
The updated function:
<?
function CSV2Array($content, $delim = ';', $encl = '"', $optional = 1) {
if ($content[strlen($content)-1]!="\r" && $content[strlen($content)-1]!="\n")
$content .= "\r\n";

$reg = '/(('.$encl.')'.($optional?'?(?(2)':'(').
'[^'.$encl.']*'.$encl.'|[^'.$delim.'\r\n]*))('.$delim.
'|\r\n)/smi';

preg_match_all($reg, $content, $treffer);
$linecount = 0;

for ($i = 0; $i<=count($treffer[3]);$i++) {
$liste[$linecount][] = $treffer[1][$i];
if ($treffer[3][$i] != $delim)
$linecount++;
}
unset($linecount);
unset($i);
unset($reg);
unset($content);
unset($delim);
unset($encl);
unset($optional);
unset($treffer);

return $liste;
}
?>


vladimir gruzdev

"cristian DOT zuddas AT gmail DOT com" has posted the corrected function "CSV2Array", but all the same there's an error. For example, function incorrectly processes a simple csv-file from "MS Excel" (http://wsCat.ka.pp.ru/test.csv) in which fields any way contain quotes and CR/LF . I has written working  function which has successfully applied to import of the greater production catalog.
<?php
// --------- Test ---------------------------------------
$str=file_get_contents('http://wsCat.ka.pp.ru/test.csv');
$rows=CSV2Array($str);
echo '<table border="1" cellSpacing="2" cellPadding="2">';
for($i=0;$i<count($rows);$i++)
  {
   echo '<tr>';
   for ($j=0;$j<count($rows[$i]);$j++)
       {
        echo '<td>'.$rows[$i][$j]. '</td>';
       }
   echo '</tr>';
  }
echo '</table>';
// -----------------------------------------------------
/**
*function CSV2Array
*Convert CSV-text to 2d-array
*(delimeter = ';', line ending = '\r\n' - only for windows platform)
* @param string $query (query to database)
* @return array
*/
function CSV2Array($content)
   {
    if ($content{strlen($content)-1}!="\r" && $content{strlen($content)-1}!="\n")
        $content .= "\r\n";
    $arr=array();
    $temp=$content;
    $tma=array();
    while (strlen($temp)>0)
          {
           if ($temp{0}=='"')
              {
               $temp=substr($temp,1);
               $str='';
               while (1)
                  {
                   $matches=array();
                   if (!preg_match('/^(.*?)"("*?)(;|\r\n)(.*)$/is',$temp,$matches))
                     return $arr;
                   $temp=$matches[4];
                   if (fmod(strlen($matches[2]),2)>0)
                      {
                       $str.=$matches[1].$matches[2].'"'.$matches[3];
                       continue;
                      }
                    else
                      {
                       $tma[]=preg_replace('/""/','"',$str.$matches[1].$matches[2]);
                       if ($matches[3]!=';')
                          {
                           $arr[]=$tma;
                           $tma=array();
                          }
                       break;
                      }
                  }
              }
            else
              {
               $matches=array();
               if (!preg_match('/^([^;\r\n]*)(;|\r\n)(.*)$/is',$temp,$matches))
                  return $arr;
               $tma[]=$matches[1];
               $temp=$matches[3];
               if ($matches[2]!=';')
                  {
                   $arr[]=$tma;
                   $tma=array();
                  }
              }
          }
    return $arr;
   }
?>


Change Language


Follow Navioo On Twitter
basename
chgrp
chmod
chown
clearstatcache
copy
delete
dirname
disk_free_space
disk_total_space
diskfreespace
fclose
feof
fflush
fgetc
fgetcsv
fgets
fgetss
file_exists
file_get_contents
file_put_contents
file
fileatime
filectime
filegroup
fileinode
filemtime
fileowner
fileperms
filesize
filetype
flock
fnmatch
fopen
fpassthru
fputcsv
fputs
fread
fscanf
fseek
fstat
ftell
ftruncate
fwrite
glob
is_dir
is_executable
is_file
is_link
is_readable
is_uploaded_file
is_writable
is_writeable
lchgrp
lchown
link
linkinfo
lstat
mkdir
move_uploaded_file
parse_ini_file
pathinfo
pclose
popen
readfile
readlink
realpath
rename
rewind
rmdir
set_file_buffer
stat
symlink
tempnam
tmpfile
touch
umask
unlink
eXTReMe Tracker