CSV Files, Comma Separated Values

This is the latest version of the CSV class, but renamed to work with CakePHP.

The main change is the addition of a feature that will let you save the headings into the object, then parse lines and return them as associated arrays rather than numerically indexed arrays.

Here's some sample code showing how to use it, followed by the class:

$csv = new csvComponent();
$fh = fopen($filename, 'r');
// First, detect the headings -- this feature allows us to put some
// information above the actual data.
while( $data = fgets( $fh ) )
{
    $line = $csv->textToArray( $data );
    if (preg_match('/name/i',$line[0])) break;
}
// tell the csv object about our headings
$csv->setHeadings($line);
// print out the data
while( $data = fgets( $fh ) )
{
    $line = $csv->textToAssoc( $data );
    print_r($line);
    echo "<p>";
}
<?php
define('CSV_TAB',"\t");

class csvComponent {
        var $template;

        /**
         * @param array $template
         *
         * The $template is an array used to selectively quote fields.
         * If the Nth element is 'quote', the Nth field will be quoted.
         * For example, array('','','quote') causes the 3rd field to be
         * quoted.
         */
        function CSV( $template = NULL )
        {
                $this->template = $template;
        }

        function arrayToText( $ar, $separator=',' )
        {
                $row = array();
                reset($ar);
                $count=0;
                foreach($ar as $field)
                {
                        if ($this->template[$count] != 'quote')
                        {
                                $field = '"'.$this->quote($field).'"';
                        }
                        $row[] = $field;
                        $count++;
                }
                return join($separator,$row);
        }

        /**
         * Parses one line of a csv file.
         */
        function &textToArray( $str, $separator=',' )
        {
                $out = array();
                while($str)
                {
                        if (preg_match('/^"/', $str))
                        {
                                if (preg_match("/\"(.+?)\"$separator(.+)$/", $str, $matches))
                                {
                                        $head = $this->dequote($matches[1]);
                                        $str = $matches[2];
                                }
                                else // assume it's the last element
                                {
                                        $head = $this->dequote($str);
                                        $str = '';
                                }
                        }
                        else
                        {
                                if (preg_match("/^$separator/",$str))
                                {
                                        // this is a special case of a null field
                                        // it's exceptional, because the . metachar matches
                                        // non-whitespace, and our separator might be whitespace
                                        $head = '';
                                        $str = substr($str,1);
                                }
                                else if (preg_match("/(.+?)$separator(.+)$/", $str, $matches))
                                {
                                        $head = $matches[1];
                                        $str = $matches[2];
                                }
                                else // assume it's the last element
                                {
                                        $head = $str;
                                        $str = '';
                                }
                        }
                        $out[] = $head;
                }
                return $out;
        }
    function textToAssoc( $text, $separator=',' )
    {
        $arr = $this->textToArray( $text, $separator );
        reset($arr);
        for($i=0; $i < count($arr); $i++)
            $output[ $this->headings[$i] ] = $arr[$i];
        return $output;
    }
    function setHeadings( $arr )
    {
        reset($arr);
        $i=0;
        foreach($arr as $heading)
            $this->headings[$i++] = $heading;
    }

        function quote( $s )
        {
                $s = preg_replace('/"/','""', $s);
                return $s;
        }

        function dequote( $s )
        {
                $s = preg_replace('/""/','"', $s);
                return $s;
        }
}
?>