123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266 |
- <?php
- /**
- * Class for parsing XLS files
- *
- * @author Martins Pilsetnieks
- */
- class SpreadsheetReader_XLS implements Iterator, Countable
- {
- /**
- * @var array Options array, pre-populated with the default values.
- */
- private $Options = array(
- );
- /**
- * @var resource File handle
- */
- private $Handle = false;
- private $Index = 0;
- private $Error = false;
- /**
- * @var array Sheet information
- */
- private $Sheets = false;
- private $SheetIndexes = array();
- /**
- * @var int Current sheet index
- */
- private $CurrentSheet = 0;
- /**
- * @var array Content of the current row
- */
- private $CurrentRow = array();
- /**
- * @var int Column count in the sheet
- */
- private $ColumnCount = 0;
- /**
- * @var int Row count in the sheet
- */
- private $RowCount = 0;
- /**
- * @var array Template to use for empty rows. Retrieved rows are merged
- * with this so that empty cells are added, too
- */
- private $EmptyRow = array();
- /**
- * @param string Path to file
- * @param array Options
- */
- public function __construct($Filepath, array $Options = null)
- {
- if (!is_readable($Filepath))
- {
- throw new Exception('SpreadsheetReader_XLS: File not readable ('.$Filepath.')');
- }
- if (!class_exists('Spreadsheet_Excel_Reader'))
- {
- throw new Exception('SpreadsheetReader_XLS: Spreadsheet_Excel_Reader class not available');
- }
- $this -> Handle = new Spreadsheet_Excel_Reader($Filepath, false, 'UTF-8');
- if (function_exists('mb_convert_encoding'))
- {
- $this -> Handle -> setUTFEncoder('mb');
- }
- if (empty($this -> Handle -> sheets))
- {
- $this -> Error = true;
- return null;
- }
- $this -> ChangeSheet(0);
- }
- public function __destruct()
- {
- unset($this -> Handle);
- }
- /**
- * Retrieves an array with information about sheets in the current file
- *
- * @return array List of sheets (key is sheet index, value is name)
- */
- public function Sheets()
- {
- if ($this -> Sheets === false)
- {
- $this -> Sheets = array();
- $this -> SheetIndexes = array_keys($this -> Handle -> sheets);
- foreach ($this -> SheetIndexes as $SheetIndex)
- {
- $this -> Sheets[] = $this -> Handle -> boundsheets[$SheetIndex]['name'];
- }
- }
- return $this -> Sheets;
- }
- /**
- * Changes the current sheet in the file to another
- *
- * @param int Sheet index
- *
- * @return bool True if sheet was successfully changed, false otherwise.
- */
- public function ChangeSheet($Index)
- {
- $Index = (int)$Index;
- $Sheets = $this -> Sheets();
- if (isset($this -> Sheets[$Index]))
- {
- $this -> rewind();
- $this -> CurrentSheet = $this -> SheetIndexes[$Index];
- $this -> ColumnCount = $this -> Handle -> sheets[$this -> CurrentSheet]['numCols'];
- $this -> RowCount = $this -> Handle -> sheets[$this -> CurrentSheet]['numRows'];
- // For the case when Spreadsheet_Excel_Reader doesn't have the row count set correctly.
- if (!$this -> RowCount && count($this -> Handle -> sheets[$this -> CurrentSheet]['cells']))
- {
- end($this -> Handle -> sheets[$this -> CurrentSheet]['cells']);
- $this -> RowCount = (int)key($this -> Handle -> sheets[$this -> CurrentSheet]['cells']);
- }
- if ($this -> ColumnCount)
- {
- $this -> EmptyRow = array_fill(1, $this -> ColumnCount, '');
- }
- else
- {
- $this -> EmptyRow = array();
- }
- }
- return false;
- }
- public function __get($Name)
- {
- switch ($Name)
- {
- case 'Error':
- return $this -> Error;
- break;
- }
- return null;
- }
- // !Iterator interface methods
- /**
- * Rewind the Iterator to the first element.
- * Similar to the reset() function for arrays in PHP
- */
- public function rewind()
- {
- $this -> Index = 0;
- }
- /**
- * Return the current element.
- * Similar to the current() function for arrays in PHP
- *
- * @return mixed current element from the collection
- */
- public function current()
- {
- if ($this -> Index == 0)
- {
- $this -> next();
- }
- return $this -> CurrentRow;
- }
- /**
- * Move forward to next element.
- * Similar to the next() function for arrays in PHP
- */
- public function next()
- {
- // Internal counter is advanced here instead of the if statement
- // because apparently it's fully possible that an empty row will not be
- // present at all
- $this -> Index++;
- if ($this -> Error)
- {
- return array();
- }
- elseif (isset($this -> Handle -> sheets[$this -> CurrentSheet]['cells'][$this -> Index]))
- {
- $this -> CurrentRow = $this -> Handle -> sheets[$this -> CurrentSheet]['cells'][$this -> Index];
- if (!$this -> CurrentRow)
- {
- return array();
- }
- $this -> CurrentRow = $this -> CurrentRow + $this -> EmptyRow;
- ksort($this -> CurrentRow);
- $this -> CurrentRow = array_values($this -> CurrentRow);
- return $this -> CurrentRow;
- }
- else
- {
- $this -> CurrentRow = $this -> EmptyRow;
- return $this -> CurrentRow;
- }
- }
- /**
- * Return the identifying key of the current element.
- * Similar to the key() function for arrays in PHP
- *
- * @return mixed either an integer or a string
- */
- public function key()
- {
- return $this -> Index;
- }
- /**
- * Check if there is a current element after calls to rewind() or next().
- * Used to check if we've iterated to the end of the collection
- *
- * @return boolean FALSE if there's nothing more to iterate over
- */
- public function valid()
- {
- if ($this -> Error)
- {
- return false;
- }
- return ($this -> Index <= $this -> RowCount);
- }
- // !Countable interface method
- /**
- * Ostensibly should return the count of the contained items but this just returns the number
- * of rows read so far. It's not really correct but at least coherent.
- */
- public function count()
- {
- if ($this -> Error)
- {
- return 0;
- }
- return $this -> RowCount;
- }
- }
- ?>
|