<?php
/**
 * CSV parsing Class.
 * 
 * Parsing CSV files with possible detection of first line column names 
 * or own column name templates.
 * 
 * @author Julius Beckmann
 * @link http://juliusbeckmann.de/
 * @license GPL
 */


/**
 * Interface for Parsing CSV Files.
 */
interface CSV_Interface {
  
  
/**
   * Constructor with initialisations for CSV parsing.
   * 
   * @param delim Delimiter Char
   * @param eclosure Enclosure Char
   * @param escape Escape Char
   */
  
public function __construct($delim=null$enclosure=null$escape=null);
  
  
/**
   * Sets CSV line template.
   * May be overwritten if FirstLineIsHeading(true).
   * 
   * @param bool Flag
   * @return this
   */
  
public function setTemplate(array $tpl_array);
  
  
/**
   * Sets if the first line is defining the CSV line template.
   * 
   * @param bool Flag
   * @return this
   */
  
public function setFirstLineIsHeading($bool);
  
  
/**
   * Parses a CSV file and returns the line in an array.
   * 
   * @param filename Filename
   * @return Array
   */
  
public function parseFile($filename);
}


/**
 * Class for Parsing CSV Files.
 */
class CSV implements CSV_Interface {
  
  
/*--- Attributes ---*/
  
  /**
   * Delimiter char.
   */
  
protected $delimiter ';';

  
/**
   * Enclosure char.
   */
  
protected $enclosure '\'';

  
/**
   * Escape char.
   */
  
protected $escape '\\';

  
/**
   * If first line defines the template.
   */
  
private $first_line_is_heading true;
  
  
/**
   * Template for the CSV lines.
   */
  
private $template = array();
  
  
  
/*--- Interface Implementation ---*/
  
  
public function __construct($delim=null$enclosure=null$escape=null) {
    if(
$delim) {
      
$this->delimiter $delim;
    }
    if(
$enclosure) {
      
$this->enclosure $enclosure;
    }
    if(
$escape) {
      
$this->escape $escape;
    }
  }
  
  public function 
setTemplate(array $tpl_array) {
    
$this->template $tpl_array;
    return 
$this;
  }
  
  public function 
setFirstLineIsHeading($bool) {
    
$this->first_line_is_heading = (bool)$bool;
    return 
$this;
  }
  
  public function 
parseFile($filename) {

    
$ret = array();    

    if(
$handle fopen($filename'r')) {

      
$first_line $this->first_line_is_heading;

      while((
$data $this->nextCSVLine($handle)) !== false) {

        if(
$first_line) {
          
$first_line false;
          
// Save template
          
$this->setTemplate($data);                
        }else{
          
// Save values using key names
          
$i 0;
          
$line = array();
          foreach(
$data as $value) {
            
// Save with numeric index
            
$line[$i] = $value;
            
// Save with template name
            
if(isset($this->template[$i])) {
              
$line[$this->template[$i]] = $value;
            }
            
$i++;
          }
          
$ret[] = $line;
        }
      }

      
fclose($handle);
    }
    return 
$ret;
  }
  
  
  
/*--- Private Implementation ---*/

  /**
   * Returns next line for a filehandle as a array.
   * 
   * @param filehandle Filehandle to use.
   * @return array of CSV Line or false.
   */
   
protected function nextCSVLine($filehandle) {
     return 
fgetcsv($filehandle4096$this->delimiter
                                
$this->enclosure$this->escape);
   }
  
}

/*

// Some example code:

$csv = new CSV();

$csv->setFirstLineIsHeading(true);
//$csv->setFirstLineIsHeading(false);

$tpl = range('a', 'z');
$csv->setTemplate($tpl);

$data = $csv->parseFile('test.csv');

var_dump($data);
*/