AAAAimport/csv.php000066600000022363151401667440007404 0ustar00input; // Column headers are always the first line of the file // 1. Store current position $curpos = $this->getFilePos(); if ($curpos > 0) { // 2. Go to the beginning of the file $this->setFilePos(0); } // 3. Read the line $jinput->set('columnheaders', $this->ReadNextLine()); if ($curpos > 0) { // 4. Set the position back $this->setFilePos($curpos); } $this->linepointer++; return true; } /** * Get the file position * * @copyright * @author RolandD * @todo * @see * @access public * @param * @return int current position in the file * @since 3.0 */ public function getFilePos() { return ftell($this->fp); } /** * Set the file position * * @copyright * @author RolandD * @todo * @see * @access public * @param int $pos the position to move to * @return int 0 if success | -1 if not success * @since 3.0 */ public function setFilePos($pos) { return fseek($this->fp, $pos); } /** * Close the file * * @copyright * @author RolandD * @todo * @see * @access public * @param * @return * @since 3.0 */ public function closeFile($removefolder=true) { fclose($this->fp); $this->_closed = true; parent::closeFile($removefolder); } /** * Read the next line in the file * * @copyright * @author RolandD * @todo * @see * @access public * @param * @return array with the line of data read | false if data cannot be read * @since 3.0 */ public function readNextLine() { // Check if the file is still open if ($this->_closed) return; // Make sure we have delimiters if (is_null($this->_field_delimiter)) return false; // Load some settings $jinput = JFactory::getApplication()->input; $template = $jinput->get('template', null, null); $csvilog = $jinput->get('csvilog', null, null); $newdata = array(); // Ignore empty records $csvdata = array(0=>''); while (is_array($csvdata) && count($csvdata)==1 && $csvdata[0]=='') { if (!is_null($this->_text_enclosure)) $csvdata = fgetcsv($this->fp, 0, $this->_field_delimiter, $this->_text_enclosure); else $csvdata = fgetcsv($this->fp, 0, $this->_field_delimiter); } // Check if we can read the line correctly if (count($csvdata) == 1 && !$this->_checked_delimiter) { $current_field = $this->_field_delimiter; $current_text = $this->_text_enclosure; $this->_findDelimiters(true); if ($template->show_preview) { if ($current_field != $this->_field_delimiter) JError::raiseNotice(0, JText::sprintf('COM_CSVI_UNEQUAL_FIELD_DELIMITER', $current_field, $this->_field_delimiter)); if ($current_text != $this->_text_enclosure) JError::raiseNotice(0, JText::sprintf('COM_CSVI_UNEQUAL_TEXT_ENCLOSURE', $current_text, $this->_text_enclosure)); } else { if ($current_field != $this->_field_delimiter) $csvilog->AddStats('incorrect', JText::sprintf('COM_CSVI_UNEQUAL_FIELD_DELIMITER', $current_field, $this->_field_delimiter)); if ($current_text != $this->_text_enclosure) $csvilog->AddStats('incorrect', JText::sprintf('COM_CSVI_UNEQUAL_FIELD_DELIMITER', $current_field, $this->_field_delimiter)); } $this->_field_delimiter = $current_field; $this->_text_enclosure = $current_text; } if ($csvdata) { // Do BOM check if ($jinput->get('currentline', 0, 'int') == 1 || is_null($jinput->get('currentline', null, null))) { // Remove text delimiters as they are not recognized by fgetcsv $csvdata[0] = $this->_removeTextDelimiters($this->_checkBom($csvdata[0])); } $this->linepointer++; return $csvdata; } else return false; } /** * Process the file to import * * @copyright * @author RolandD * @todo * @see * @access public * @param * @return * @since 3.0 */ public function processFile() { // Open the csv file $this->fp = fopen($this->filename, "r"); $this->_closed = false; // Load the delimiters $this->_findDelimiters(); return true; } /** * Find the delimiters used * * @copyright * @author RolandD * @todo * @see * @access private * @param bool $force Force to read the delimiters from the imported file * @return bool true if delimiters found | false if delimiters not found * @since 3.0 */ private function _findDelimiters($force=false) { $jinput = JFactory::getApplication()->input; if (!$this->_checked_delimiter) { $csvilog = $jinput->get('csvilog', null, null); $template = $jinput->get('template', null, null); if (!$template->get('auto_detect_delimiters', 'general', true) && !$force) { // Set the field delimiter if (strtolower($template->get('field_delimiter', 'general')) == 't') $this->_field_delimiter = "\t"; else $this->_field_delimiter = $template->get('field_delimiter', 'general'); // Set the text enclosure $this->_text_enclosure = ($template->get('text_enclosure', 'general', '')) ? $template->get('text_enclosure', 'general') : null; } else { // Read the first line rewind($this->fp); $line = fgets($this->fp); // 1. Is the user using text enclosures $first_char = substr($line, 0, 1); $pattern = '/[a-zA-Z0-9_]/'; $matches = array(); preg_match($pattern, $first_char, $matches); if (count($matches) == 0) { // User is using text delimiter $this->_text_enclosure = $first_char; $csvilog->addDebug(JText::sprintf('COM_CSVI_FOUND_TEXT_ENCLOSURE', $first_char)); // 2. What field delimiter is being used $match_next_char = strpos($line, $this->_text_enclosure, 1); $second_char = substr($line, $match_next_char+1, 1); if ($first_char == $second_char) { $jinput->set('error_found', true); JError::raiseWarning(0, JText::_('COM_CSVI_CANNOT_FIND_TEXT_DELIMITER')); return false; } else { $this->_field_delimiter = $second_char; } } else { $totalchars = strlen($line); // 2. What field delimiter is being used for ($i = 0;$i <= $totalchars; $i++) { $current_char = substr($line, $i, 1); preg_match($pattern, $current_char, $matches); if (count($matches) == 0) { $this->_field_delimiter = $current_char; $i = $totalchars; } } } $csvilog->addDebug(JText::sprintf('COM_CSVI_FOUND_FIELD_DELIMITER', $this->_field_delimiter)); rewind($this->fp); } $this->_checked_delimiter = true; } return true; } /** * Checks if the uploaded file has a BOM * * If the uploaded file has a BOM, remove it since it only causes * problems on import. * * @copyright * @author RolandD * @todo * @see ReadNextLine() * @access private * @param string $data the string to check for a BOM * @return string return the cleaned string * @since 3.0 */ private function _checkBom($data) { // Check the first three characters if (strlen($data) > 3) { if (ord($data{0}) == 239 && ord($data{1}) == 187 && ord($data{2}) == 191) { return substr($data, 3, strlen($data)); } else return $data; } else return $data; } /** * Removes the text delimiters when fgetcsv() has failed to do so because the file contains a BOM. * This allows for the possibility that the data value contains embedded text enclosure characters * (which should be doubled up for correct csv file format). * The string [32" TV] (ignore brackets) should be encoded as ["32"" TV"] * This function correctly decodes ["32"" TV"] back to [32" TV] * * @copyright * @author doorknob * @todo * @see * @access private * @param string $data the string to clean * @return string the cleaned string * @since */ private function _removeTextDelimiters($data) { if( substr($data, 0, 1) == $this->_text_enclosure && substr($data, -1, 1) == $this->_text_enclosure ) { return str_replace($this->_text_enclosure.$this->_text_enclosure, $this->_text_enclosure, substr($data, 1, -1)); } else { return $data; } } /** * Sets the file pointer back to beginning * * @copyright * @author RolandD * @todo * @see * @access public * @param * @return * @since 3.0 */ public function rewind() { $this->setFilePos(0); } } ?> import/xls.php000066600000006641151401667440007420 0ustar00data[0]['numRows']; } /** * Load the column headers from a file * * @copyright * @author RolandD * @todo * @see * @access public * @param * @return bool true * @since 3.0 */ public function loadColumnHeaders() { $jinput = JFactory::getApplication()->input; // Make sure we include the empty fields for ($i=1; $i<=$this->data[0]['numCols']; $i++) { if (!isset($this->data[0]['cells'][1])) $this->data[0]['cells'][1][$i] = ''; } $headers = array_values($this->data[0]['cells'][1]); $jinput->set('columnheaders', $headers); $this->linepointer++; return true; } /** * Get the file position * * @copyright * @author RolandD * @todo * @see * @access public * @param * @return int current position in the file * @since 3.0 */ public function getFilePos() { return $this->linepointer; } /** * Set the file position * * @copyright * @author RolandD * @todo * @see * @access public * @param int $pos the position to move to * @return int current position in the file * @since 3.0 */ public function setFilePos($pos) { $this->linepointer = $pos; return $this->linepointer; } /** * Read the next line in the file * * @copyright * @author RolandD * @todo * @see * @access public * @param * @return array with the line of data read | false if data cannot be read * @since 3.0 */ public function readNextLine() { if ($this->data[0]['numRows'] >= $this->linepointer) { $newdata = array(); // Make sure we include the empty fields for ($i=1; $i <= $this->data[0]['numCols']; $i++) { if (!isset($this->data[0]['cells'][$this->linepointer][$i])) $newdata[] = ''; else $newdata[] = $this->data[0]['cells'][$this->linepointer][$i]; } $this->linepointer++; return $newdata; } else return false; } /** * Process the file to import * * @copyright * @author RolandD * @todo * @see * @access public * @param * @return * @since 3.0 */ public function processFile() { $jinput = JFactory::getApplication()->input; $template = $jinput->get('template', null, null); $this->fp = true; $this->data = new Spreadsheet_Excel_Reader($this->filename, false); $this->data = $this->data->sheets; return true; } /** * Sets the file pointer back to beginning * * @copyright * @author RolandD * @todo * @see * @access public * @param * @return * @since 3.0 */ public function rewind() { $this->setFilePos(1); } } ?> import/ods.php000066600000010304151401667440007366 0ustar00data->rows; } /** * Load the column headers from a file * * @copyright * @author RolandD * @todo * @see * @access public * @param * @return bool true * @since 3.0 */ public function loadColumnHeaders() { $jinput = JFactory::getApplication()->input; $jinput->set('columnheaders', $this->data->_data[1]); $this->linepointer++; return true; } /** * Get the file position * * @copyright * @author RolandD * @todo * @see * @access public * @param * @return int current position in the file * @since 3.0 */ public function getFilePos() { return $this->linepointer; } /** * Set the file position * * @copyright * @author RolandD * @todo * @see * @access public * @param int $pos the position to move to * @return int current position in the file * @since 3.0 */ public function setFilePos($pos) { $this->linepointer = $pos; return $this->linepointer; } /** * Read the next line in the file * * @copyright * @author RolandD * @todo * @see * @access public * @param * @return array with the line of data read | false if data cannot be read * @since 3.0 */ public function readNextLine() { if ($this->data->rows >= $this->linepointer) { $newdata = array(); $newdata = $this->data->_data[$this->linepointer]; $this->linepointer++; return $newdata; } else return false; } /** * Process the file to import * * @copyright * @author RolandD * @todo * @see * @access public * @param * @return * @since 3.0 */ public function processFile() { if (!$this->_unpacked) { $jinput = JFactory::getApplication()->input; $csvilog = $jinput->get('csvilog', null, null); jimport('joomla.filesystem.file'); jimport('joomla.filesystem.archive'); $this->fp = true; $this->linepointer = 1; $this->data = new ODSParser(); // First we need to unpack the zipfile $unpackfile = $this->_unpackpath.'/ods/'.basename($this->filename).'.zip'; $importfile = $this->_unpackpath.'/ods/content.xml'; // Check the unpack folder JFolder::create($this->_unpackpath.'/ods'); // Delete the destination file if it already exists if (JFile::exists($unpackfile)) JFile::delete($unpackfile); if (JFile::exists($importfile)) JFile::delete($importfile); // Now copy the file to the folder JFile::copy($this->filename, $unpackfile); // Extract the files in the folder if (!JArchive::extract($unpackfile, $this->_unpackpath.'/ods')) { $csvilog->AddStats('incorrect', JText::_('COM_CSVI_CANNOT_UNPACK_ODS_FILE')); return false; } // File is always called content.xml else $this->filename = $importfile; // Read the data to process if (!$this->data->read($this->filename)) return false; // Set the unpacked to true as we have unpacked the file $this->_unpacked = true; } // All good return true return true; } /** * Sets the file pointer back to beginning * * @copyright * @author RolandD * @todo * @see * @access public * @param * @return * @since 3.0 */ public function rewind() { // Set the line pointer to 1 as that is the first entry in the data array $this->setFilePos(1); } } ?> import/excel_reader2.php000066600000164101151401667440011312 0ustar00 * Maintained at http://code.google.com/p/php-excel-reader/ * * Format parsing and MUCH more contributed by: * Matt Roxburgh < http://www.roxburgh.me.uk > * * DOCUMENTATION * ============= * http://code.google.com/p/php-excel-reader/wiki/Documentation * * CHANGE LOG * ========== * http://code.google.com/p/php-excel-reader/wiki/ChangeHistory * * DISCUSSION/SUPPORT * ================== * http://groups.google.com/group/php-excel-reader-discuss/topics * * -------------------------------------------------------------------------- * * Originally developed by Vadim Tkachenko under the name PHPExcelReader. * (http://sourceforge.net/projects/phpexcelreader) * Based on the Java version by Andy Khan (http://www.andykhan.com). Now * maintained by David Sanders. Reads only Biff 7 and Biff 8 formats. * * PHP versions 4 and 5 * * LICENSE: This source file is subject to version 3.0 of the PHP license * that is available through the world-wide-web at the following URI: * http://www.php.net/license/3_0.txt. If you did not receive a copy of * the PHP License and are unable to obtain it through the web, please * send a note to license@php.net so we can mail you a copy immediately. * * @category Spreadsheet * @package Spreadsheet_Excel_Reader * @author Vadim Tkachenko * @license http://www.php.net/license/3_0.txt PHP License 3.0 * @version CVS: $Id: excel_reader2.php 1456 2010-12-05 11:31:17Z RolandD $ * @link http://pear.php.net/package/Spreadsheet_Excel_Reader * @see OLE, Spreadsheet_Excel_Writer * -------------------------------------------------------------------------- */ define('NUM_BIG_BLOCK_DEPOT_BLOCKS_POS', 0x2c); define('SMALL_BLOCK_DEPOT_BLOCK_POS', 0x3c); define('ROOT_START_BLOCK_POS', 0x30); define('BIG_BLOCK_SIZE', 0x200); define('SMALL_BLOCK_SIZE', 0x40); define('EXTENSION_BLOCK_POS', 0x44); define('NUM_EXTENSION_BLOCK_POS', 0x48); define('PROPERTY_STORAGE_BLOCK_SIZE', 0x80); define('BIG_BLOCK_DEPOT_BLOCKS_POS', 0x4c); define('SMALL_BLOCK_THRESHOLD', 0x1000); // property storage offsets define('SIZE_OF_NAME_POS', 0x40); define('TYPE_POS', 0x42); define('START_BLOCK_POS', 0x74); define('SIZE_POS', 0x78); define('IDENTIFIER_OLE', pack("CCCCCCCC",0xd0,0xcf,0x11,0xe0,0xa1,0xb1,0x1a,0xe1)); function GetInt4d($data, $pos) { $value = ord($data[$pos]) | (ord($data[$pos+1]) << 8) | (ord($data[$pos+2]) << 16) | (ord($data[$pos+3]) << 24); if ($value>=4294967294) { $value=-2; } return $value; } // http://uk.php.net/manual/en/function.getdate.php function gmgetdate($ts = null){ $k = array('seconds','minutes','hours','mday','wday','mon','year','yday','weekday','month',0); return(array_combine($k,explode(":",gmdate('s:i:G:j:w:n:Y:z:l:F:U',is_null($ts)?time():$ts)))); } function v($data,$pos) { return ord($data[$pos]) | ord($data[$pos+1])<<8; } class OLERead { var $data = ''; function OLERead(){ } function read($sFileName){ // check if file exist and is readable (Darko Miljanovic) if(!is_readable($sFileName)) { $this->error = 1; return false; } $this->data = @file_get_contents($sFileName); if (!$this->data) { $this->error = 1; return false; } if (substr($this->data, 0, 8) != IDENTIFIER_OLE) { $this->error = 1; return false; } $this->numBigBlockDepotBlocks = GetInt4d($this->data, NUM_BIG_BLOCK_DEPOT_BLOCKS_POS); $this->sbdStartBlock = GetInt4d($this->data, SMALL_BLOCK_DEPOT_BLOCK_POS); $this->rootStartBlock = GetInt4d($this->data, ROOT_START_BLOCK_POS); $this->extensionBlock = GetInt4d($this->data, EXTENSION_BLOCK_POS); $this->numExtensionBlocks = GetInt4d($this->data, NUM_EXTENSION_BLOCK_POS); $bigBlockDepotBlocks = array(); $pos = BIG_BLOCK_DEPOT_BLOCKS_POS; $bbdBlocks = $this->numBigBlockDepotBlocks; if ($this->numExtensionBlocks != 0) { $bbdBlocks = (BIG_BLOCK_SIZE - BIG_BLOCK_DEPOT_BLOCKS_POS)/4; } for ($i = 0; $i < $bbdBlocks; $i++) { $bigBlockDepotBlocks[$i] = GetInt4d($this->data, $pos); $pos += 4; } for ($j = 0; $j < $this->numExtensionBlocks; $j++) { $pos = ($this->extensionBlock + 1)* BIG_BLOCK_SIZE; $blocksToRead = min($this->numBigBlockDepotBlocks - $bbdBlocks, BIG_BLOCK_SIZE / 4 - 1); for ($i = $bbdBlocks; $i < $bbdBlocks + $blocksToRead; $i++) { $bigBlockDepotBlocks[$i] = GetInt4d($this->data, $pos); $pos += 4; } $bbdBlocks += $blocksToRead; if ($bbdBlocks < $this->numBigBlockDepotBlocks) { $this->extensionBlock = GetInt4d($this->data, $pos); } } // readBigBlockDepot $pos = 0; $index = 0; $this->bigBlockChain = array(); for ($i = 0; $i < $this->numBigBlockDepotBlocks; $i++) { $pos = ($bigBlockDepotBlocks[$i] + 1)* BIG_BLOCK_SIZE; //echo "pos = $pos"; for ($j = 0 ; $j < BIG_BLOCK_SIZE / 4; $j++) { $this->bigBlockChain[$index] = GetInt4d($this->data, $pos); $pos += 4 ; $index++; } } // readSmallBlockDepot(); $pos = 0; $index = 0; $sbdBlock = $this->sbdStartBlock; $this->smallBlockChain = array(); while ($sbdBlock != -2) { $pos = ($sbdBlock + 1)* BIG_BLOCK_SIZE; for ($j = 0; $j < BIG_BLOCK_SIZE / 4; $j++) { $this->smallBlockChain[$index] = GetInt4d($this->data, $pos); $pos += 4; $index++; } $sbdBlock = $this->bigBlockChain[$sbdBlock]; } // readData(rootStartBlock) $block = $this->rootStartBlock; $pos = 0; $this->entry = $this->__readData($block); $this->__readPropertySets(); } function __readData($bl) { $block = $bl; $pos = 0; $data = ''; while ($block != -2) { $pos = ($block + 1)* BIG_BLOCK_SIZE; $data = $data.substr($this->data, $pos, BIG_BLOCK_SIZE); $block = $this->bigBlockChain[$block]; } return $data; } function __readPropertySets(){ $offset = 0; while ($offset < strlen($this->entry)) { $d = substr($this->entry, $offset, PROPERTY_STORAGE_BLOCK_SIZE); $nameSize = ord($d[SIZE_OF_NAME_POS]) | (ord($d[SIZE_OF_NAME_POS+1]) << 8); $type = ord($d[TYPE_POS]); $startBlock = GetInt4d($d, START_BLOCK_POS); $size = GetInt4d($d, SIZE_POS); $name = ''; for ($i = 0; $i < $nameSize ; $i++) { $name .= $d[$i]; } $name = str_replace("\x00", "", $name); $this->props[] = array ( 'name' => $name, 'type' => $type, 'startBlock' => $startBlock, 'size' => $size); if ((strtolower($name) == "workbook") || ( strtolower($name) == "book")) { $this->wrkbook = count($this->props) - 1; } if ($name == "Root Entry") { $this->rootentry = count($this->props) - 1; } $offset += PROPERTY_STORAGE_BLOCK_SIZE; } } function getWorkBook(){ if ($this->props[$this->wrkbook]['size'] < SMALL_BLOCK_THRESHOLD){ $rootdata = $this->__readData($this->props[$this->rootentry]['startBlock']); $streamData = ''; $block = $this->props[$this->wrkbook]['startBlock']; $pos = 0; while ($block != -2) { $pos = $block* SMALL_BLOCK_SIZE; $streamData .= substr($rootdata, $pos, SMALL_BLOCK_SIZE); $block = $this->smallBlockChain[$block]; } return $streamData; }else{ $numBlocks = $this->props[$this->wrkbook]['size'] / BIG_BLOCK_SIZE; if ($this->props[$this->wrkbook]['size'] % BIG_BLOCK_SIZE != 0) { $numBlocks++; } if ($numBlocks == 0) return ''; $streamData = ''; $block = $this->props[$this->wrkbook]['startBlock']; $pos = 0; while ($block != -2) { $pos = ($block + 1)* BIG_BLOCK_SIZE; $streamData .= substr($this->data, $pos, BIG_BLOCK_SIZE); $block = $this->bigBlockChain[$block]; } return $streamData; } } } define('SPREADSHEET_EXCEL_READER_BIFF8', 0x600); define('SPREADSHEET_EXCEL_READER_BIFF7', 0x500); define('SPREADSHEET_EXCEL_READER_WORKBOOKGLOBALS', 0x5); define('SPREADSHEET_EXCEL_READER_WORKSHEET', 0x10); define('SPREADSHEET_EXCEL_READER_TYPE_BOF', 0x809); define('SPREADSHEET_EXCEL_READER_TYPE_EOF', 0x0a); define('SPREADSHEET_EXCEL_READER_TYPE_BOUNDSHEET', 0x85); define('SPREADSHEET_EXCEL_READER_TYPE_DIMENSION', 0x200); define('SPREADSHEET_EXCEL_READER_TYPE_ROW', 0x208); define('SPREADSHEET_EXCEL_READER_TYPE_DBCELL', 0xd7); define('SPREADSHEET_EXCEL_READER_TYPE_FILEPASS', 0x2f); define('SPREADSHEET_EXCEL_READER_TYPE_NOTE', 0x1c); define('SPREADSHEET_EXCEL_READER_TYPE_TXO', 0x1b6); define('SPREADSHEET_EXCEL_READER_TYPE_RK', 0x7e); define('SPREADSHEET_EXCEL_READER_TYPE_RK2', 0x27e); define('SPREADSHEET_EXCEL_READER_TYPE_MULRK', 0xbd); define('SPREADSHEET_EXCEL_READER_TYPE_MULBLANK', 0xbe); define('SPREADSHEET_EXCEL_READER_TYPE_INDEX', 0x20b); define('SPREADSHEET_EXCEL_READER_TYPE_SST', 0xfc); define('SPREADSHEET_EXCEL_READER_TYPE_EXTSST', 0xff); define('SPREADSHEET_EXCEL_READER_TYPE_CONTINUE', 0x3c); define('SPREADSHEET_EXCEL_READER_TYPE_LABEL', 0x204); define('SPREADSHEET_EXCEL_READER_TYPE_LABELSST', 0xfd); define('SPREADSHEET_EXCEL_READER_TYPE_NUMBER', 0x203); define('SPREADSHEET_EXCEL_READER_TYPE_NAME', 0x18); define('SPREADSHEET_EXCEL_READER_TYPE_ARRAY', 0x221); define('SPREADSHEET_EXCEL_READER_TYPE_STRING', 0x207); define('SPREADSHEET_EXCEL_READER_TYPE_FORMULA', 0x406); define('SPREADSHEET_EXCEL_READER_TYPE_FORMULA2', 0x6); define('SPREADSHEET_EXCEL_READER_TYPE_FORMAT', 0x41e); define('SPREADSHEET_EXCEL_READER_TYPE_XF', 0xe0); define('SPREADSHEET_EXCEL_READER_TYPE_BOOLERR', 0x205); define('SPREADSHEET_EXCEL_READER_TYPE_FONT', 0x0031); define('SPREADSHEET_EXCEL_READER_TYPE_PALETTE', 0x0092); define('SPREADSHEET_EXCEL_READER_TYPE_UNKNOWN', 0xffff); define('SPREADSHEET_EXCEL_READER_TYPE_NINETEENFOUR', 0x22); define('SPREADSHEET_EXCEL_READER_TYPE_MERGEDCELLS', 0xE5); define('SPREADSHEET_EXCEL_READER_UTCOFFSETDAYS' , 25569); define('SPREADSHEET_EXCEL_READER_UTCOFFSETDAYS1904', 24107); define('SPREADSHEET_EXCEL_READER_MSINADAY', 86400); define('SPREADSHEET_EXCEL_READER_TYPE_HYPER', 0x01b8); define('SPREADSHEET_EXCEL_READER_TYPE_COLINFO', 0x7d); define('SPREADSHEET_EXCEL_READER_TYPE_DEFCOLWIDTH', 0x55); define('SPREADSHEET_EXCEL_READER_TYPE_STANDARDWIDTH', 0x99); define('SPREADSHEET_EXCEL_READER_DEF_NUM_FORMAT', "%s"); /* * Main Class */ class Spreadsheet_Excel_Reader { // MK: Added to make data retrieval easier var $colnames = array(); var $colindexes = array(); var $standardColWidth = 0; var $defaultColWidth = 0; function myHex($d) { if ($d < 16) return "0" . dechex($d); return dechex($d); } function dumpHexData($data, $pos, $length) { $info = ""; for ($i = 0; $i <= $length; $i++) { $info .= ($i==0?"":" ") . $this->myHex(ord($data[$pos + $i])) . (ord($data[$pos + $i])>31? "[" . $data[$pos + $i] . "]":''); } return $info; } function getCol($col) { if (is_string($col)) { $col = strtolower($col); if (array_key_exists($col,$this->colnames)) { $col = $this->colnames[$col]; } } return $col; } // PUBLIC API FUNCTIONS // -------------------- function val($row,$col,$sheet=0) { $col = $this->getCol($col); if (array_key_exists($row,$this->sheets[$sheet]['cells']) && array_key_exists($col,$this->sheets[$sheet]['cells'][$row])) { return $this->sheets[$sheet]['cells'][$row][$col]; } return ""; } function value($row,$col,$sheet=0) { return $this->val($row,$col,$sheet); } function info($row,$col,$type='',$sheet=0) { $col = $this->getCol($col); if (array_key_exists('cellsInfo',$this->sheets[$sheet]) && array_key_exists($row,$this->sheets[$sheet]['cellsInfo']) && array_key_exists($col,$this->sheets[$sheet]['cellsInfo'][$row]) && array_key_exists($type,$this->sheets[$sheet]['cellsInfo'][$row][$col])) { return $this->sheets[$sheet]['cellsInfo'][$row][$col][$type]; } return ""; } function type($row,$col,$sheet=0) { return $this->info($row,$col,'type',$sheet); } function raw($row,$col,$sheet=0) { return $this->info($row,$col,'raw',$sheet); } function rowspan($row,$col,$sheet=0) { $val = $this->info($row,$col,'rowspan',$sheet); if ($val=="") { return 1; } return $val; } function colspan($row,$col,$sheet=0) { $val = $this->info($row,$col,'colspan',$sheet); if ($val=="") { return 1; } return $val; } function hyperlink($row,$col,$sheet=0) { $link = $this->sheets[$sheet]['cellsInfo'][$row][$col]['hyperlink']; if ($link) { return $link['link']; } return ''; } function rowcount($sheet=0) { return $this->sheets[$sheet]['numRows']; } function colcount($sheet=0) { return $this->sheets[$sheet]['numCols']; } function colwidth($col,$sheet=0) { // Col width is actually the width of the number 0. So we have to estimate and come close return $this->colInfo[$sheet][$col]['width']/9142*200; } function colhidden($col,$sheet=0) { return !!$this->colInfo[$sheet][$col]['hidden']; } function rowheight($row,$sheet=0) { return $this->rowInfo[$sheet][$row]['height']; } function rowhidden($row,$sheet=0) { return !!$this->rowInfo[$sheet][$row]['hidden']; } // GET THE CSS FOR FORMATTING // ========================== function style($row,$col,$sheet=0,$properties='') { $css = ""; $font=$this->font($row,$col,$sheet); if ($font!="") { $css .= "font-family:$font;"; } $align=$this->align($row,$col,$sheet); if ($align!="") { $css .= "text-align:$align;"; } $height=$this->height($row,$col,$sheet); if ($height!="") { $css .= "font-size:$height"."px;"; } $bgcolor=$this->bgColor($row,$col,$sheet); if ($bgcolor!="") { $bgcolor = $this->colors[$bgcolor]; $css .= "background-color:$bgcolor;"; } $color=$this->color($row,$col,$sheet); if ($color!="") { $css .= "color:$color;"; } $bold=$this->bold($row,$col,$sheet); if ($bold) { $css .= "font-weight:bold;"; } $italic=$this->italic($row,$col,$sheet); if ($italic) { $css .= "font-style:italic;"; } $underline=$this->underline($row,$col,$sheet); if ($underline) { $css .= "text-decoration:underline;"; } // Borders $bLeft = $this->borderLeft($row,$col,$sheet); $bRight = $this->borderRight($row,$col,$sheet); $bTop = $this->borderTop($row,$col,$sheet); $bBottom = $this->borderBottom($row,$col,$sheet); $bLeftCol = $this->borderLeftColor($row,$col,$sheet); $bRightCol = $this->borderRightColor($row,$col,$sheet); $bTopCol = $this->borderTopColor($row,$col,$sheet); $bBottomCol = $this->borderBottomColor($row,$col,$sheet); // Try to output the minimal required style if ($bLeft!="" && $bLeft==$bRight && $bRight==$bTop && $bTop==$bBottom) { $css .= "border:" . $this->lineStylesCss[$bLeft] .";"; } else { if ($bLeft!="") { $css .= "border-left:" . $this->lineStylesCss[$bLeft] .";"; } if ($bRight!="") { $css .= "border-right:" . $this->lineStylesCss[$bRight] .";"; } if ($bTop!="") { $css .= "border-top:" . $this->lineStylesCss[$bTop] .";"; } if ($bBottom!="") { $css .= "border-bottom:" . $this->lineStylesCss[$bBottom] .";"; } } // Only output border colors if there is an actual border specified if ($bLeft!="" && $bLeftCol!="") { $css .= "border-left-color:" . $bLeftCol .";"; } if ($bRight!="" && $bRightCol!="") { $css .= "border-right-color:" . $bRightCol .";"; } if ($bTop!="" && $bTopCol!="") { $css .= "border-top-color:" . $bTopCol . ";"; } if ($bBottom!="" && $bBottomCol!="") { $css .= "border-bottom-color:" . $bBottomCol .";"; } return $css; } // FORMAT PROPERTIES // ================= function format($row,$col,$sheet=0) { return $this->info($row,$col,'format',$sheet); } function formatIndex($row,$col,$sheet=0) { return $this->info($row,$col,'formatIndex',$sheet); } function formatColor($row,$col,$sheet=0) { return $this->info($row,$col,'formatColor',$sheet); } // CELL (XF) PROPERTIES // ==================== function xfRecord($row,$col,$sheet=0) { $xfIndex = $this->info($row,$col,'xfIndex',$sheet); if ($xfIndex!="") { return $this->xfRecords[$xfIndex]; } return null; } function xfProperty($row,$col,$sheet,$prop) { $xfRecord = $this->xfRecord($row,$col,$sheet); if ($xfRecord!=null) { return $xfRecord[$prop]; } return ""; } function align($row,$col,$sheet=0) { return $this->xfProperty($row,$col,$sheet,'align'); } function bgColor($row,$col,$sheet=0) { return $this->xfProperty($row,$col,$sheet,'bgColor'); } function borderLeft($row,$col,$sheet=0) { return $this->xfProperty($row,$col,$sheet,'borderLeft'); } function borderRight($row,$col,$sheet=0) { return $this->xfProperty($row,$col,$sheet,'borderRight'); } function borderTop($row,$col,$sheet=0) { return $this->xfProperty($row,$col,$sheet,'borderTop'); } function borderBottom($row,$col,$sheet=0) { return $this->xfProperty($row,$col,$sheet,'borderBottom'); } function borderLeftColor($row,$col,$sheet=0) { return $this->colors[$this->xfProperty($row,$col,$sheet,'borderLeftColor')]; } function borderRightColor($row,$col,$sheet=0) { return $this->colors[$this->xfProperty($row,$col,$sheet,'borderRightColor')]; } function borderTopColor($row,$col,$sheet=0) { return $this->colors[$this->xfProperty($row,$col,$sheet,'borderTopColor')]; } function borderBottomColor($row,$col,$sheet=0) { return $this->colors[$this->xfProperty($row,$col,$sheet,'borderBottomColor')]; } // FONT PROPERTIES // =============== function fontRecord($row,$col,$sheet=0) { $xfRecord = $this->xfRecord($row,$col,$sheet); if ($xfRecord!=null) { $font = $xfRecord['fontIndex']; if ($font!=null) { return $this->fontRecords[$font]; } } return null; } function fontProperty($row,$col,$sheet=0,$prop) { $font = $this->fontRecord($row,$col,$sheet); if ($font!=null) { return $font[$prop]; } return false; } function fontIndex($row,$col,$sheet=0) { return $this->xfProperty($row,$col,$sheet,'fontIndex'); } function color($row,$col,$sheet=0) { $formatColor = $this->formatColor($row,$col,$sheet); if ($formatColor!="") { return $formatColor; } $ci = $this->fontProperty($row,$col,$sheet,'color'); return $this->rawColor($ci); } function rawColor($ci) { if (($ci <> 0x7FFF) && ($ci <> '')) { return $this->colors[$ci]; } return ""; } function bold($row,$col,$sheet=0) { return $this->fontProperty($row,$col,$sheet,'bold'); } function italic($row,$col,$sheet=0) { return $this->fontProperty($row,$col,$sheet,'italic'); } function underline($row,$col,$sheet=0) { return $this->fontProperty($row,$col,$sheet,'under'); } function height($row,$col,$sheet=0) { return $this->fontProperty($row,$col,$sheet,'height'); } function font($row,$col,$sheet=0) { return $this->fontProperty($row,$col,$sheet,'font'); } // DUMP AN HTML TABLE OF THE ENTIRE XLS DATA // ========================================= function dump($row_numbers=false,$col_letters=false,$sheet=0,$table_class='excel') { $out = ""; if ($col_letters) { $out .= "\n\t"; if ($row_numbers) { $out .= "\n\t\t"; } for($i=1;$i<=$this->colcount($sheet);$i++) { $style = "width:" . ($this->colwidth($i,$sheet)*1) . "px;"; if ($this->colhidden($i,$sheet)) { $style .= "display:none;"; } $out .= "\n\t\t"; } $out .= "\n"; } $out .= "\n"; for($row=1;$row<=$this->rowcount($sheet);$row++) { $rowheight = $this->rowheight($row,$sheet); $style = "height:" . ($rowheight*(4/3)) . "px;"; if ($this->rowhidden($row,$sheet)) { $style .= "display:none;"; } $out .= "\n\t"; if ($row_numbers) { $out .= "\n\t\t"; } for($col=1;$col<=$this->colcount($sheet);$col++) { // Account for Rowspans/Colspans $rowspan = $this->rowspan($row,$col,$sheet); $colspan = $this->colspan($row,$col,$sheet); for($i=0;$i<$rowspan;$i++) { for($j=0;$j<$colspan;$j++) { if ($i>0 || $j>0) { $this->sheets[$sheet]['cellsInfo'][$row+$i][$col+$j]['dontprint']=1; } } } if(!$this->sheets[$sheet]['cellsInfo'][$row][$col]['dontprint']) { $style = $this->style($row,$col,$sheet); if ($this->colhidden($col,$sheet)) { $style .= "display:none;"; } $out .= "\n\t\t"; } } $out .= "\n"; } $out .= "
 " . strtoupper($this->colindexes[$i]) . "
$row 1?" colspan=$colspan":"") . ($rowspan > 1?" rowspan=$rowspan":"") . ">"; $val = $this->val($row,$col,$sheet); if ($val=='') { $val=" "; } else { $val = htmlentities($val); $link = $this->hyperlink($row,$col,$sheet); if ($link!='') { $val = "$val"; } } $out .= "".nl2br($val).""; $out .= "
"; return $out; } // -------------- // END PUBLIC API var $boundsheets = array(); var $formatRecords = array(); var $fontRecords = array(); var $xfRecords = array(); var $colInfo = array(); var $rowInfo = array(); var $sst = array(); var $sheets = array(); var $data; var $_ole; var $_defaultEncoding = "UTF-8"; var $_defaultFormat = SPREADSHEET_EXCEL_READER_DEF_NUM_FORMAT; var $_columnsFormat = array(); var $_rowoffset = 1; var $_coloffset = 1; /** * List of default date formats used by Excel */ var $dateFormats = array ( 0xe => "m/d/Y", 0xf => "M-d-Y", 0x10 => "d-M", 0x11 => "M-Y", 0x12 => "h:i a", 0x13 => "h:i:s a", 0x14 => "H:i", 0x15 => "H:i:s", 0x16 => "d/m/Y H:i", 0x2d => "i:s", 0x2e => "H:i:s", 0x2f => "i:s.S" ); /** * Default number formats used by Excel */ var $numberFormats = array( 0x1 => "0", 0x2 => "0.00", 0x3 => "#,##0", 0x4 => "#,##0.00", 0x5 => "\$#,##0;(\$#,##0)", 0x6 => "\$#,##0;[Red](\$#,##0)", 0x7 => "\$#,##0.00;(\$#,##0.00)", 0x8 => "\$#,##0.00;[Red](\$#,##0.00)", 0x9 => "0%", 0xa => "0.00%", 0xb => "0.00E+00", 0x25 => "#,##0;(#,##0)", 0x26 => "#,##0;[Red](#,##0)", 0x27 => "#,##0.00;(#,##0.00)", 0x28 => "#,##0.00;[Red](#,##0.00)", 0x29 => "#,##0;(#,##0)", // Not exactly 0x2a => "\$#,##0;(\$#,##0)", // Not exactly 0x2b => "#,##0.00;(#,##0.00)", // Not exactly 0x2c => "\$#,##0.00;(\$#,##0.00)", // Not exactly 0x30 => "##0.0E+0" ); var $colors = Array( 0x00 => "#000000", 0x01 => "#FFFFFF", 0x02 => "#FF0000", 0x03 => "#00FF00", 0x04 => "#0000FF", 0x05 => "#FFFF00", 0x06 => "#FF00FF", 0x07 => "#00FFFF", 0x08 => "#000000", 0x09 => "#FFFFFF", 0x0A => "#FF0000", 0x0B => "#00FF00", 0x0C => "#0000FF", 0x0D => "#FFFF00", 0x0E => "#FF00FF", 0x0F => "#00FFFF", 0x10 => "#800000", 0x11 => "#008000", 0x12 => "#000080", 0x13 => "#808000", 0x14 => "#800080", 0x15 => "#008080", 0x16 => "#C0C0C0", 0x17 => "#808080", 0x18 => "#9999FF", 0x19 => "#993366", 0x1A => "#FFFFCC", 0x1B => "#CCFFFF", 0x1C => "#660066", 0x1D => "#FF8080", 0x1E => "#0066CC", 0x1F => "#CCCCFF", 0x20 => "#000080", 0x21 => "#FF00FF", 0x22 => "#FFFF00", 0x23 => "#00FFFF", 0x24 => "#800080", 0x25 => "#800000", 0x26 => "#008080", 0x27 => "#0000FF", 0x28 => "#00CCFF", 0x29 => "#CCFFFF", 0x2A => "#CCFFCC", 0x2B => "#FFFF99", 0x2C => "#99CCFF", 0x2D => "#FF99CC", 0x2E => "#CC99FF", 0x2F => "#FFCC99", 0x30 => "#3366FF", 0x31 => "#33CCCC", 0x32 => "#99CC00", 0x33 => "#FFCC00", 0x34 => "#FF9900", 0x35 => "#FF6600", 0x36 => "#666699", 0x37 => "#969696", 0x38 => "#003366", 0x39 => "#339966", 0x3A => "#003300", 0x3B => "#333300", 0x3C => "#993300", 0x3D => "#993366", 0x3E => "#333399", 0x3F => "#333333", 0x40 => "#000000", 0x41 => "#FFFFFF", 0x43 => "#000000", 0x4D => "#000000", 0x4E => "#FFFFFF", 0x4F => "#000000", 0x50 => "#FFFFFF", 0x51 => "#000000", 0x7FFF => "#000000" ); var $lineStyles = array( 0x00 => "", 0x01 => "Thin", 0x02 => "Medium", 0x03 => "Dashed", 0x04 => "Dotted", 0x05 => "Thick", 0x06 => "Double", 0x07 => "Hair", 0x08 => "Medium dashed", 0x09 => "Thin dash-dotted", 0x0A => "Medium dash-dotted", 0x0B => "Thin dash-dot-dotted", 0x0C => "Medium dash-dot-dotted", 0x0D => "Slanted medium dash-dotted" ); var $lineStylesCss = array( "Thin" => "1px solid", "Medium" => "2px solid", "Dashed" => "1px dashed", "Dotted" => "1px dotted", "Thick" => "3px solid", "Double" => "double", "Hair" => "1px solid", "Medium dashed" => "2px dashed", "Thin dash-dotted" => "1px dashed", "Medium dash-dotted" => "2px dashed", "Thin dash-dot-dotted" => "1px dashed", "Medium dash-dot-dotted" => "2px dashed", "Slanted medium dash-dotte" => "2px dashed" ); function read16bitstring($data, $start) { $len = 0; while (ord($data[$start + $len]) + ord($data[$start + $len + 1]) > 0) $len++; return substr($data, $start, $len); } // ADDED by Matt Kruse for better formatting function _format_value($format,$num,$f) { // 49==TEXT format // http://code.google.com/p/php-excel-reader/issues/detail?id=7 if ( (!$f && $format=="%s") || ($f==49) || ($format=="GENERAL") ) { return array('string'=>$num, 'formatColor'=>null); } // Custom pattern can be POSITIVE;NEGATIVE;ZERO // The "text" option as 4th parameter is not handled $parts = explode(";",$format); $pattern = $parts[0]; // Negative pattern if (count($parts)>2 && $num==0) { $pattern = $parts[2]; } // Zero pattern if (count($parts)>1 && $num<0) { $pattern = $parts[1]; $num = abs($num); } $color = ""; $matches = array(); $color_regex = "/^\[(BLACK|BLUE|CYAN|GREEN|MAGENTA|RED|WHITE|YELLOW)\]/i"; if (preg_match($color_regex,$pattern,$matches)) { $color = strtolower($matches[1]); $pattern = preg_replace($color_regex,"",$pattern); } // In Excel formats, "_" is used to add spacing, which we can't do in HTML $pattern = preg_replace("/_./","",$pattern); // Some non-number characters are escaped with \, which we don't need $pattern = preg_replace("/\\\/","",$pattern); // Some non-number strings are quoted, so we'll get rid of the quotes $pattern = preg_replace("/\"/","",$pattern); // TEMPORARY - Convert # to 0 $pattern = preg_replace("/\#/","0",$pattern); // Find out if we need comma formatting $has_commas = preg_match("/,/",$pattern); if ($has_commas) { $pattern = preg_replace("/,/","",$pattern); } // Handle Percentages if (preg_match("/\d(\%)([^\%]|$)/",$pattern,$matches)) { $num = $num* 100; $pattern = preg_replace("/(\d)(\%)([^\%]|$)/","$1%$3",$pattern); } // Handle the number itself $number_regex = "/(\d+)(\.?)(\d*)/"; if (preg_match($number_regex,$pattern,$matches)) { $left = $matches[1]; $dec = $matches[2]; $right = $matches[3]; if ($has_commas) { $formatted = number_format($num,strlen($right)); } else { $sprintf_pattern = "%1.".strlen($right)."f"; $formatted = sprintf($sprintf_pattern, $num); } $pattern = preg_replace($number_regex, $formatted, $pattern); } return array( 'string'=>$pattern, 'formatColor'=>$color ); } /** * Constructor * * Some basic initialisation */ function Spreadsheet_Excel_Reader($file='',$store_extended_info=true,$outputEncoding='') { $this->_ole = new OLERead(); $this->setUTFEncoder('iconv'); if ($outputEncoding != '') { $this->setOutputEncoding($outputEncoding); } for ($i=1; $i<245; $i++) { $name = strtolower(( (($i-1)/26>=1)?chr(($i-1)/26+64):'') . chr(($i-1)%26+65)); $this->colnames[$name] = $i; $this->colindexes[$i] = $name; } $this->store_extended_info = $store_extended_info; if ($file!="") { $this->read($file); } } /** * Set the encoding method */ function setOutputEncoding($encoding) { $this->_defaultEncoding = $encoding; } /** * $encoder = 'iconv' or 'mb' * set iconv if you would like use 'iconv' for encode UTF-16LE to your encoding * set mb if you would like use 'mb_convert_encoding' for encode UTF-16LE to your encoding */ function setUTFEncoder($encoder = 'iconv') { $this->_encoderFunction = ''; if ($encoder == 'iconv') { $this->_encoderFunction = function_exists('iconv') ? 'iconv' : ''; } elseif ($encoder == 'mb') { $this->_encoderFunction = function_exists('mb_convert_encoding') ? 'mb_convert_encoding' : ''; } } function setRowColOffset($iOffset) { $this->_rowoffset = $iOffset; $this->_coloffset = $iOffset; } /** * Set the default number format */ function setDefaultFormat($sFormat) { $this->_defaultFormat = $sFormat; } /** * Force a column to use a certain format */ function setColumnFormat($column, $sFormat) { $this->_columnsFormat[$column] = $sFormat; } /** * Read the spreadsheet file using OLE, then parse */ function read($sFileName) { $res = $this->_ole->read($sFileName); // oops, something goes wrong (Darko Miljanovic) if($res === false) { // check error code if($this->_ole->error == 1) { // bad file die('The filename ' . $sFileName . ' is not readable'); } // check other error codes here (eg bad fileformat, etc...) } $this->data = $this->_ole->getWorkBook(); $this->_parse(); } /** * Parse a workbook * * @access private * @return bool */ function _parse() { $pos = 0; $data = $this->data; $code = v($data,$pos); $length = v($data,$pos+2); $version = v($data,$pos+4); $substreamType = v($data,$pos+6); $this->version = $version; if (($version != SPREADSHEET_EXCEL_READER_BIFF8) && ($version != SPREADSHEET_EXCEL_READER_BIFF7)) { return false; } if ($substreamType != SPREADSHEET_EXCEL_READER_WORKBOOKGLOBALS){ return false; } $pos += $length + 4; $code = v($data,$pos); $length = v($data,$pos+2); while ($code != SPREADSHEET_EXCEL_READER_TYPE_EOF) { switch ($code) { case SPREADSHEET_EXCEL_READER_TYPE_SST: $spos = $pos + 4; $limitpos = $spos + $length; $uniqueStrings = $this->_GetInt4d($data, $spos+4); $spos += 8; for ($i = 0; $i < $uniqueStrings; $i++) { // Read in the number of characters if ($spos == $limitpos) { $opcode = v($data,$spos); $conlength = v($data,$spos+2); if ($opcode != 0x3c) { return -1; } $spos += 4; $limitpos = $spos + $conlength; } $numChars = ord($data[$spos]) | (ord($data[$spos+1]) << 8); $spos += 2; $optionFlags = ord($data[$spos]); $spos++; $asciiEncoding = (($optionFlags & 0x01) == 0) ; $extendedString = ( ($optionFlags & 0x04) != 0); // See if string contains formatting information $richString = ( ($optionFlags & 0x08) != 0); if ($richString) { // Read in the crun $formattingRuns = v($data,$spos); $spos += 2; } if ($extendedString) { // Read in cchExtRst $extendedRunLength = $this->_GetInt4d($data, $spos); $spos += 4; } $len = ($asciiEncoding)? $numChars : $numChars*2; if ($spos + $len < $limitpos) { $retstr = substr($data, $spos, $len); $spos += $len; } else{ // found countinue $retstr = substr($data, $spos, $limitpos - $spos); $bytesRead = $limitpos - $spos; $charsLeft = $numChars - (($asciiEncoding) ? $bytesRead : ($bytesRead / 2)); $spos = $limitpos; while ($charsLeft > 0){ $opcode = v($data,$spos); $conlength = v($data,$spos+2); if ($opcode != 0x3c) { return -1; } $spos += 4; $limitpos = $spos + $conlength; $option = ord($data[$spos]); $spos += 1; if ($asciiEncoding && ($option == 0)) { $len = min($charsLeft, $limitpos - $spos); // min($charsLeft, $conlength); $retstr .= substr($data, $spos, $len); $charsLeft -= $len; $asciiEncoding = true; } elseif (!$asciiEncoding && ($option != 0)) { $len = min($charsLeft* 2, $limitpos - $spos); // min($charsLeft, $conlength); $retstr .= substr($data, $spos, $len); $charsLeft -= $len/2; $asciiEncoding = false; } elseif (!$asciiEncoding && ($option == 0)) { // Bummer - the string starts off as Unicode, but after the // continuation it is in straightforward ASCII encoding $len = min($charsLeft, $limitpos - $spos); // min($charsLeft, $conlength); for ($j = 0; $j < $len; $j++) { $retstr .= $data[$spos + $j].chr(0); } $charsLeft -= $len; $asciiEncoding = false; } else{ $newstr = ''; for ($j = 0; $j < strlen($retstr); $j++) { $newstr = $retstr[$j].chr(0); } $retstr = $newstr; $len = min($charsLeft* 2, $limitpos - $spos); // min($charsLeft, $conlength); $retstr .= substr($data, $spos, $len); $charsLeft -= $len/2; $asciiEncoding = false; } $spos += $len; } } //$retstr = ($asciiEncoding) ? $retstr : $this->_encodeUTF16($retstr); $retstr = ($asciiEncoding) ? iconv('iso-8859-1', $this->_defaultEncoding, $retstr) : $this->_encodeUTF16($retstr); if ($richString){ $spos += 4* $formattingRuns; } // For extended strings, skip over the extended string data if ($extendedString) { $spos += $extendedRunLength; } $this->sst[]=$retstr; } break; case SPREADSHEET_EXCEL_READER_TYPE_FILEPASS: return false; break; case SPREADSHEET_EXCEL_READER_TYPE_NAME: break; case SPREADSHEET_EXCEL_READER_TYPE_FORMAT: $indexCode = v($data,$pos+4); if ($version == SPREADSHEET_EXCEL_READER_BIFF8) { $numchars = v($data,$pos+6); if (ord($data[$pos+8]) == 0){ $formatString = substr($data, $pos+9, $numchars); } else { $formatString = substr($data, $pos+9, $numchars*2); } } else { $numchars = ord($data[$pos+6]); $formatString = substr($data, $pos+7, $numchars*2); } $this->formatRecords[$indexCode] = $formatString; break; case SPREADSHEET_EXCEL_READER_TYPE_FONT: $height = v($data,$pos+4); $option = v($data,$pos+6); $color = v($data,$pos+8); $weight = v($data,$pos+10); $under = ord($data[$pos+14]); $font = ""; // Font name $numchars = ord($data[$pos+18]); if ((ord($data[$pos+19]) & 1) == 0){ $font = substr($data, $pos+20, $numchars); } else { $font = substr($data, $pos+20, $numchars*2); $font = $this->_encodeUTF16($font); } $this->fontRecords[] = array( 'height' => $height / 20, 'italic' => !!($option & 2), 'color' => $color, 'under' => !($under==0), 'bold' => ($weight==700), 'font' => $font, 'raw' => $this->dumpHexData($data, $pos+3, $length) ); break; case SPREADSHEET_EXCEL_READER_TYPE_PALETTE: $colors = ord($data[$pos+4]) | ord($data[$pos+5]) << 8; for ($coli = 0; $coli < $colors; $coli++) { $colOff = $pos + 2 + ($coli* 4); $colr = ord($data[$colOff]); $colg = ord($data[$colOff+1]); $colb = ord($data[$colOff+2]); $this->colors[0x07 + $coli] = '#' . $this->myhex($colr) . $this->myhex($colg) . $this->myhex($colb); } break; case SPREADSHEET_EXCEL_READER_TYPE_XF: $fontIndexCode = (ord($data[$pos+4]) | ord($data[$pos+5]) << 8) - 1; $fontIndexCode = max(0,$fontIndexCode); $indexCode = ord($data[$pos+6]) | ord($data[$pos+7]) << 8; $alignbit = ord($data[$pos+10]) & 3; $bgi = (ord($data[$pos+22]) | ord($data[$pos+23]) << 8) & 0x3FFF; $bgcolor = ($bgi & 0x7F); // $bgcolor = ($bgi & 0x3f80) >> 7; $align = ""; if ($alignbit==3) { $align="right"; } if ($alignbit==2) { $align="center"; } $fillPattern = (ord($data[$pos+21]) & 0xFC) >> 2; if ($fillPattern == 0) { $bgcolor = ""; } $xf = array(); $xf['formatIndex'] = $indexCode; $xf['align'] = $align; $xf['fontIndex'] = $fontIndexCode; $xf['bgColor'] = $bgcolor; $xf['fillPattern'] = $fillPattern; $border = ord($data[$pos+14]) | (ord($data[$pos+15]) << 8) | (ord($data[$pos+16]) << 16) | (ord($data[$pos+17]) << 24); $xf['borderLeft'] = $this->lineStyles[($border & 0xF)]; $xf['borderRight'] = $this->lineStyles[($border & 0xF0) >> 4]; $xf['borderTop'] = $this->lineStyles[($border & 0xF00) >> 8]; $xf['borderBottom'] = $this->lineStyles[($border & 0xF000) >> 12]; $xf['borderLeftColor'] = ($border & 0x7F0000) >> 16; $xf['borderRightColor'] = ($border & 0x3F800000) >> 23; $border = (ord($data[$pos+18]) | ord($data[$pos+19]) << 8); $xf['borderTopColor'] = ($border & 0x7F); $xf['borderBottomColor'] = ($border & 0x3F80) >> 7; if (array_key_exists($indexCode, $this->dateFormats)) { $xf['type'] = 'date'; $xf['format'] = $this->dateFormats[$indexCode]; if ($align=='') { $xf['align'] = 'right'; } }elseif (array_key_exists($indexCode, $this->numberFormats)) { $xf['type'] = 'number'; $xf['format'] = $this->numberFormats[$indexCode]; if ($align=='') { $xf['align'] = 'right'; } }else{ $isdate = FALSE; $formatstr = ''; if ($indexCode > 0){ if (isset($this->formatRecords[$indexCode])) $formatstr = $this->formatRecords[$indexCode]; if ($formatstr!="") { $tmp = preg_replace("/\;.*/","",$formatstr); $tmp = preg_replace("/^\[[^\]]*\]/","",$tmp); if (preg_match("/[^hmsday\/\-:\s\\\,AMP]/i", $tmp) == 0) { // found day and time format $isdate = TRUE; $formatstr = $tmp; $formatstr = str_replace(array('AM/PM','mmmm','mmm'), array('a','F','M'), $formatstr); // m/mm are used for both minutes and months - oh SNAP! // This mess tries to fix for that. // 'm' == minutes only if following h/hh or preceding s/ss $formatstr = preg_replace("/(h:?)mm?/","$1i", $formatstr); $formatstr = preg_replace("/mm?(:?s)/","i$1", $formatstr); // A single 'm' = n in PHP $formatstr = preg_replace("/(^|[^m])m([^m]|$)/", '$1n$2', $formatstr); $formatstr = preg_replace("/(^|[^m])m([^m]|$)/", '$1n$2', $formatstr); // else it's months $formatstr = str_replace('mm', 'm', $formatstr); // Convert single 'd' to 'j' $formatstr = preg_replace("/(^|[^d])d([^d]|$)/", '$1j$2', $formatstr); $formatstr = str_replace(array('dddd','ddd','dd','yyyy','yy','hh','h'), array('l','D','d','Y','y','H','g'), $formatstr); $formatstr = preg_replace("/ss?/", 's', $formatstr); } } } if ($isdate){ $xf['type'] = 'date'; $xf['format'] = $formatstr; if ($align=='') { $xf['align'] = 'right'; } }else{ // If the format string has a 0 or # in it, we'll assume it's a number if (preg_match("/[0#]/", $formatstr)) { $xf['type'] = 'number'; if ($align=='') { $xf['align']='right'; } } else { $xf['type'] = 'other'; } $xf['format'] = $formatstr; $xf['code'] = $indexCode; } } $this->xfRecords[] = $xf; break; case SPREADSHEET_EXCEL_READER_TYPE_NINETEENFOUR: $this->nineteenFour = (ord($data[$pos+4]) == 1); break; case SPREADSHEET_EXCEL_READER_TYPE_BOUNDSHEET: $rec_offset = $this->_GetInt4d($data, $pos+4); $rec_typeFlag = ord($data[$pos+8]); $rec_visibilityFlag = ord($data[$pos+9]); $rec_length = ord($data[$pos+10]); if ($version == SPREADSHEET_EXCEL_READER_BIFF8){ $chartype = ord($data[$pos+11]); if ($chartype == 0){ $rec_name = substr($data, $pos+12, $rec_length); } else { $rec_name = $this->_encodeUTF16(substr($data, $pos+12, $rec_length*2)); } }elseif ($version == SPREADSHEET_EXCEL_READER_BIFF7){ $rec_name = substr($data, $pos+11, $rec_length); } $this->boundsheets[] = array('name'=>$rec_name,'offset'=>$rec_offset); break; } $pos += $length + 4; $code = ord($data[$pos]) | ord($data[$pos+1])<<8; $length = ord($data[$pos+2]) | ord($data[$pos+3])<<8; } foreach ($this->boundsheets as $key=>$val){ $this->sn = $key; $this->_parsesheet($val['offset']); } return true; } /** * Parse a worksheet */ function _parsesheet($spos) { $cont = true; $data = $this->data; // read BOF $code = ord($data[$spos]) | ord($data[$spos+1])<<8; $length = ord($data[$spos+2]) | ord($data[$spos+3])<<8; $version = ord($data[$spos + 4]) | ord($data[$spos + 5])<<8; $substreamType = ord($data[$spos + 6]) | ord($data[$spos + 7])<<8; if (($version != SPREADSHEET_EXCEL_READER_BIFF8) && ($version != SPREADSHEET_EXCEL_READER_BIFF7)) { return -1; } if ($substreamType != SPREADSHEET_EXCEL_READER_WORKSHEET){ return -2; } $spos += $length + 4; while($cont) { $lowcode = ord($data[$spos]); if ($lowcode == SPREADSHEET_EXCEL_READER_TYPE_EOF) break; $code = $lowcode | ord($data[$spos+1])<<8; $length = ord($data[$spos+2]) | ord($data[$spos+3])<<8; $spos += 4; $this->sheets[$this->sn]['maxrow'] = $this->_rowoffset - 1; $this->sheets[$this->sn]['maxcol'] = $this->_coloffset - 1; unset($this->rectype); switch ($code) { case SPREADSHEET_EXCEL_READER_TYPE_DIMENSION: if (!isset($this->numRows)) { if (($length == 10) || ($version == SPREADSHEET_EXCEL_READER_BIFF7)){ $this->sheets[$this->sn]['numRows'] = ord($data[$spos+2]) | ord($data[$spos+3]) << 8; $this->sheets[$this->sn]['numCols'] = ord($data[$spos+6]) | ord($data[$spos+7]) << 8; } else { $this->sheets[$this->sn]['numRows'] = ord($data[$spos+4]) | ord($data[$spos+5]) << 8; $this->sheets[$this->sn]['numCols'] = ord($data[$spos+10]) | ord($data[$spos+11]) << 8; } } break; case SPREADSHEET_EXCEL_READER_TYPE_MERGEDCELLS: $cellRanges = ord($data[$spos]) | ord($data[$spos+1])<<8; for ($i = 0; $i < $cellRanges; $i++) { $fr = ord($data[$spos + 8*$i + 2]) | ord($data[$spos + 8*$i + 3])<<8; $lr = ord($data[$spos + 8*$i + 4]) | ord($data[$spos + 8*$i + 5])<<8; $fc = ord($data[$spos + 8*$i + 6]) | ord($data[$spos + 8*$i + 7])<<8; $lc = ord($data[$spos + 8*$i + 8]) | ord($data[$spos + 8*$i + 9])<<8; if ($lr - $fr > 0) { $this->sheets[$this->sn]['cellsInfo'][$fr+1][$fc+1]['rowspan'] = $lr - $fr + 1; } if ($lc - $fc > 0) { $this->sheets[$this->sn]['cellsInfo'][$fr+1][$fc+1]['colspan'] = $lc - $fc + 1; } } break; case SPREADSHEET_EXCEL_READER_TYPE_RK: case SPREADSHEET_EXCEL_READER_TYPE_RK2: $row = ord($data[$spos]) | ord($data[$spos+1])<<8; $column = ord($data[$spos+2]) | ord($data[$spos+3])<<8; $rknum = $this->_GetInt4d($data, $spos + 6); $numValue = $this->_GetIEEE754($rknum); $info = $this->_getCellDetails($spos,$numValue,$column); $this->addcell($row, $column, $info['string'],$info); break; case SPREADSHEET_EXCEL_READER_TYPE_LABELSST: $row = ord($data[$spos]) | ord($data[$spos+1])<<8; $column = ord($data[$spos+2]) | ord($data[$spos+3])<<8; $xfindex = ord($data[$spos+4]) | ord($data[$spos+5])<<8; $index = $this->_GetInt4d($data, $spos + 6); $this->addcell($row, $column, $this->sst[$index], array('xfIndex'=>$xfindex) ); break; case SPREADSHEET_EXCEL_READER_TYPE_MULRK: $row = ord($data[$spos]) | ord($data[$spos+1])<<8; $colFirst = ord($data[$spos+2]) | ord($data[$spos+3])<<8; $colLast = ord($data[$spos + $length - 2]) | ord($data[$spos + $length - 1])<<8; $columns = $colLast - $colFirst + 1; $tmppos = $spos+4; for ($i = 0; $i < $columns; $i++) { $numValue = $this->_GetIEEE754($this->_GetInt4d($data, $tmppos + 2)); $info = $this->_getCellDetails($tmppos-4,$numValue,$colFirst + $i + 1); $tmppos += 6; $this->addcell($row, $colFirst + $i, $info['string'], $info); } break; case SPREADSHEET_EXCEL_READER_TYPE_NUMBER: $row = ord($data[$spos]) | ord($data[$spos+1])<<8; $column = ord($data[$spos+2]) | ord($data[$spos+3])<<8; $tmp = unpack("ddouble", substr($data, $spos + 6, 8)); // It machine machine dependent if ($this->isDate($spos)) { $numValue = $tmp['double']; } else { $numValue = $this->createNumber($spos); } $info = $this->_getCellDetails($spos,$numValue,$column); $this->addcell($row, $column, $info['string'], $info); break; case SPREADSHEET_EXCEL_READER_TYPE_FORMULA: case SPREADSHEET_EXCEL_READER_TYPE_FORMULA2: $row = ord($data[$spos]) | ord($data[$spos+1])<<8; $column = ord($data[$spos+2]) | ord($data[$spos+3])<<8; if ((ord($data[$spos+6])==0) && (ord($data[$spos+12])==255) && (ord($data[$spos+13])==255)) { //String formula. Result follows in a STRING record // This row/col are stored to be referenced in that record // http://code.google.com/p/php-excel-reader/issues/detail?id=4 $previousRow = $row; $previousCol = $column; } elseif ((ord($data[$spos+6])==1) && (ord($data[$spos+12])==255) && (ord($data[$spos+13])==255)) { //Boolean formula. Result is in +2; 0=false,1=true // http://code.google.com/p/php-excel-reader/issues/detail?id=4 if (ord($this->data[$spos+8])==1) { $this->addcell($row, $column, "TRUE"); } else { $this->addcell($row, $column, "FALSE"); } } elseif ((ord($data[$spos+6])==2) && (ord($data[$spos+12])==255) && (ord($data[$spos+13])==255)) { //Error formula. Error code is in +2; } elseif ((ord($data[$spos+6])==3) && (ord($data[$spos+12])==255) && (ord($data[$spos+13])==255)) { //Formula result is a null string. $this->addcell($row, $column, ''); } else { // result is a number, so first 14 bytes are just like a _NUMBER record $tmp = unpack("ddouble", substr($data, $spos + 6, 8)); // It machine machine dependent if ($this->isDate($spos)) { $numValue = $tmp['double']; } else { $numValue = $this->createNumber($spos); } $info = $this->_getCellDetails($spos,$numValue,$column); $this->addcell($row, $column, $info['string'], $info); } break; case SPREADSHEET_EXCEL_READER_TYPE_BOOLERR: $row = ord($data[$spos]) | ord($data[$spos+1])<<8; $column = ord($data[$spos+2]) | ord($data[$spos+3])<<8; $string = ord($data[$spos+6]); $this->addcell($row, $column, $string); break; case SPREADSHEET_EXCEL_READER_TYPE_STRING: // http://code.google.com/p/php-excel-reader/issues/detail?id=4 if ($version == SPREADSHEET_EXCEL_READER_BIFF8){ // Unicode 16 string, like an SST record $xpos = $spos; $numChars =ord($data[$xpos]) | (ord($data[$xpos+1]) << 8); $xpos += 2; $optionFlags =ord($data[$xpos]); $xpos++; $asciiEncoding = (($optionFlags &0x01) == 0) ; $extendedString = (($optionFlags & 0x04) != 0); // See if string contains formatting information $richString = (($optionFlags & 0x08) != 0); if ($richString) { // Read in the crun $formattingRuns =ord($data[$xpos]) | (ord($data[$xpos+1]) << 8); $xpos += 2; } if ($extendedString) { // Read in cchExtRst $extendedRunLength =$this->_GetInt4d($this->data, $xpos); $xpos += 4; } $len = ($asciiEncoding)?$numChars : $numChars*2; $retstr =substr($data, $xpos, $len); $xpos += $len; $retstr = ($asciiEncoding)? $retstr : $this->_encodeUTF16($retstr); } elseif ($version == SPREADSHEET_EXCEL_READER_BIFF7){ // Simple byte string $xpos = $spos; $numChars =ord($data[$xpos]) | (ord($data[$xpos+1]) << 8); $xpos += 2; $retstr =substr($data, $xpos, $numChars); } $this->addcell($previousRow, $previousCol, $retstr); break; case SPREADSHEET_EXCEL_READER_TYPE_ROW: $row = ord($data[$spos]) | ord($data[$spos+1])<<8; $rowInfo = ord($data[$spos + 6]) | ((ord($data[$spos+7]) << 8) & 0x7FFF); if (($rowInfo & 0x8000) > 0) { $rowHeight = -1; } else { $rowHeight = $rowInfo & 0x7FFF; } $rowHidden = (ord($data[$spos + 12]) & 0x20) >> 5; $this->rowInfo[$this->sn][$row+1] = Array('height' => $rowHeight / 20, 'hidden'=>$rowHidden ); break; case SPREADSHEET_EXCEL_READER_TYPE_DBCELL: break; case SPREADSHEET_EXCEL_READER_TYPE_MULBLANK: $row = ord($data[$spos]) | ord($data[$spos+1])<<8; $column = ord($data[$spos+2]) | ord($data[$spos+3])<<8; $cols = ($length / 2) - 3; for ($c = 0; $c < $cols; $c++) { $xfindex = ord($data[$spos + 4 + ($c* 2)]) | ord($data[$spos + 5 + ($c* 2)])<<8; $this->addcell($row, $column + $c, "", array('xfIndex'=>$xfindex)); } break; case SPREADSHEET_EXCEL_READER_TYPE_LABEL: $row = ord($data[$spos]) | ord($data[$spos+1])<<8; $column = ord($data[$spos+2]) | ord($data[$spos+3])<<8; $this->addcell($row, $column, substr($data, $spos + 8, ord($data[$spos + 6]) | ord($data[$spos + 7])<<8)); break; case SPREADSHEET_EXCEL_READER_TYPE_EOF: $cont = false; break; case SPREADSHEET_EXCEL_READER_TYPE_HYPER: // Only handle hyperlinks to a URL $row = ord($this->data[$spos]) | ord($this->data[$spos+1])<<8; $row2 = ord($this->data[$spos+2]) | ord($this->data[$spos+3])<<8; $column = ord($this->data[$spos+4]) | ord($this->data[$spos+5])<<8; $column2 = ord($this->data[$spos+6]) | ord($this->data[$spos+7])<<8; $linkdata = Array(); $flags = ord($this->data[$spos + 28]); $udesc = ""; $ulink = ""; $uloc = 32; $linkdata['flags'] = $flags; if (($flags & 1) > 0 ) { // is a type we understand // is there a description ? if (($flags & 0x14) == 0x14 ) { // has a description $uloc += 4; $descLen = ord($this->data[$spos + 32]) | ord($this->data[$spos + 33]) << 8; $udesc = substr($this->data, $spos + $uloc, $descLen* 2); $uloc += 2* $descLen; } $ulink = $this->read16bitstring($this->data, $spos + $uloc + 20); if ($udesc == "") { $udesc = $ulink; } } $linkdata['desc'] = $udesc; $linkdata['link'] = $this->_encodeUTF16($ulink); for ($r=$row; $r<=$row2; $r++) { for ($c=$column; $c<=$column2; $c++) { $this->sheets[$this->sn]['cellsInfo'][$r+1][$c+1]['hyperlink'] = $linkdata; } } break; case SPREADSHEET_EXCEL_READER_TYPE_DEFCOLWIDTH: $this->defaultColWidth = ord($data[$spos+4]) | ord($data[$spos+5]) << 8; break; case SPREADSHEET_EXCEL_READER_TYPE_STANDARDWIDTH: $this->standardColWidth = ord($data[$spos+4]) | ord($data[$spos+5]) << 8; break; case SPREADSHEET_EXCEL_READER_TYPE_COLINFO: $colfrom = ord($data[$spos+0]) | ord($data[$spos+1]) << 8; $colto = ord($data[$spos+2]) | ord($data[$spos+3]) << 8; $cw = ord($data[$spos+4]) | ord($data[$spos+5]) << 8; $cxf = ord($data[$spos+6]) | ord($data[$spos+7]) << 8; $co = ord($data[$spos+8]); for ($coli = $colfrom; $coli <= $colto; $coli++) { $this->colInfo[$this->sn][$coli+1] = Array('width' => $cw, 'xf' => $cxf, 'hidden' => ($co & 0x01), 'collapsed' => ($co & 0x1000) >> 12); } break; default: break; } $spos += $length; } if (!isset($this->sheets[$this->sn]['numRows'])) $this->sheets[$this->sn]['numRows'] = $this->sheets[$this->sn]['maxrow']; if (!isset($this->sheets[$this->sn]['numCols'])) $this->sheets[$this->sn]['numCols'] = $this->sheets[$this->sn]['maxcol']; } function isDate($spos) { $xfindex = ord($this->data[$spos+4]) | ord($this->data[$spos+5]) << 8; return ($this->xfRecords[$xfindex]['type'] == 'date'); } // Get the details for a particular cell function _getCellDetails($spos,$numValue,$column) { $xfindex = ord($this->data[$spos+4]) | ord($this->data[$spos+5]) << 8; $xfrecord = $this->xfRecords[$xfindex]; $type = $xfrecord['type']; $format = $xfrecord['format']; $formatIndex = $xfrecord['formatIndex']; $fontIndex = $xfrecord['fontIndex']; $formatColor = ""; $rectype = ''; $string = ''; $raw = ''; if (isset($this->_columnsFormat[$column + 1])){ $format = $this->_columnsFormat[$column + 1]; } if ($type == 'date') { // See http://groups.google.com/group/php-excel-reader-discuss/browse_frm/thread/9c3f9790d12d8e10/f2045c2369ac79de $rectype = 'date'; // Convert numeric value into a date $utcDays = floor($numValue - ($this->nineteenFour ? SPREADSHEET_EXCEL_READER_UTCOFFSETDAYS1904 : SPREADSHEET_EXCEL_READER_UTCOFFSETDAYS)); $utcValue = ($utcDays)* SPREADSHEET_EXCEL_READER_MSINADAY; $dateinfo = gmgetdate($utcValue); $raw = $numValue; $fractionalDay = $numValue - floor($numValue) + .0000001; // The .0000001 is to fix for php/excel fractional diffs $totalseconds = floor(SPREADSHEET_EXCEL_READER_MSINADAY* $fractionalDay); $secs = $totalseconds % 60; $totalseconds -= $secs; $hours = floor($totalseconds / (60* 60)); $mins = floor($totalseconds / 60) % 60; $string = date ($format, mktime($hours, $mins, $secs, $dateinfo["mon"], $dateinfo["mday"], $dateinfo["year"])); } else if ($type == 'number') { $rectype = 'number'; $formatted = $this->_format_value($format, $numValue, $formatIndex); $string = $formatted['string']; $formatColor = $formatted['formatColor']; $raw = $numValue; } else{ if ($format=="") { $format = $this->_defaultFormat; } $rectype = 'unknown'; $formatted = $this->_format_value($format, $numValue, $formatIndex); $string = $formatted['string']; $formatColor = $formatted['formatColor']; $raw = $numValue; } return array( 'string'=>$string, 'raw'=>$raw, 'rectype'=>$rectype, 'format'=>$format, 'formatIndex'=>$formatIndex, 'fontIndex'=>$fontIndex, 'formatColor'=>$formatColor, 'xfIndex'=>$xfindex ); } function createNumber($spos) { $rknumhigh = $this->_GetInt4d($this->data, $spos + 10); $rknumlow = $this->_GetInt4d($this->data, $spos + 6); $sign = ($rknumhigh & 0x80000000) >> 31; $exp = ($rknumhigh & 0x7ff00000) >> 20; $mantissa = (0x100000 | ($rknumhigh & 0x000fffff)); $mantissalow1 = ($rknumlow & 0x80000000) >> 31; $mantissalow2 = ($rknumlow & 0x7fffffff); $value = $mantissa / pow( 2 , (20- ($exp - 1023))); if ($mantissalow1 != 0) $value += 1 / pow (2 , (21 - ($exp - 1023))); $value += $mantissalow2 / pow (2 , (52 - ($exp - 1023))); if ($sign) {$value = -1* $value;} return $value; } function addcell($row, $col, $string, $info=null) { $this->sheets[$this->sn]['maxrow'] = max($this->sheets[$this->sn]['maxrow'], $row + $this->_rowoffset); $this->sheets[$this->sn]['maxcol'] = max($this->sheets[$this->sn]['maxcol'], $col + $this->_coloffset); $this->sheets[$this->sn]['cells'][$row + $this->_rowoffset][$col + $this->_coloffset] = $string; if ($this->store_extended_info && $info) { foreach ($info as $key=>$val) { $this->sheets[$this->sn]['cellsInfo'][$row + $this->_rowoffset][$col + $this->_coloffset][$key] = $val; } } } function _GetIEEE754($rknum) { if (($rknum & 0x02) != 0) { $value = $rknum >> 2; } else { //mmp // I got my info on IEEE754 encoding from // http://research.microsoft.com/~hollasch/cgindex/coding/ieeefloat.html // The RK format calls for using only the most significant 30 bits of the // 64 bit floating point value. The other 34 bits are assumed to be 0 // So, we use the upper 30 bits of $rknum as follows... $sign = ($rknum & 0x80000000) >> 31; $exp = ($rknum & 0x7ff00000) >> 20; $mantissa = (0x100000 | ($rknum & 0x000ffffc)); $value = $mantissa / pow( 2 , (20- ($exp - 1023))); if ($sign) { $value = -1* $value; } //end of changes by mmp } if (($rknum & 0x01) != 0) { $value /= 100; } return $value; } function _encodeUTF16($string) { $result = $string; if ($this->_defaultEncoding){ switch ($this->_encoderFunction){ case 'iconv' : $result = @iconv('UTF-16LE', $this->_defaultEncoding, $string); break; case 'mb_convert_encoding' : $result = @mb_convert_encoding($string, $this->_defaultEncoding, 'UTF-16LE' ); break; } } return $result; } function _GetInt4d($data, $pos) { $value = ord($data[$pos]) | (ord($data[$pos+1]) << 8) | (ord($data[$pos+2]) << 16) | (ord($data[$pos+3]) << 24); if ($value>=4294967294) { $value=-2; } return $value; } } ?> import/xml.php000066600000065441151401667440007415 0ustar00_getXmlFields() == true) { $jinput = JFactory::getApplication()->input; $jinput->set('columnheaders', $this->_xml_fields); return true; } else { /** * Note: clearing the value when no fields found causes a problem when processing * XML files with the 'use headers' option set because the function is called after the * end of file has been reached. When an empty set of fields is returned, the program * fails to terminate properly and loops endlessly through the import continuation page. */ return false; } } /** * Get the file position * * @copyright * @author RolandD * @todo * @see * @access public * @param * @return int current position in the file * @since 3.0 */ public function getFilePos() { return $this->linepointer; } /** * Set the file position * * To be able to set the file position correctly, the XML reader needs to be at the start of the file * * @copyright * @author RolandD * @todo * @see * @access public * @param int $pos the position to move to * @return int current position in the file * @since 3.0 */ public function setFilePos($pos) { // Close the XML reader $this->closeFile(false); // Open a new XML reader $this->processFile(); // Move the pointer to the specified position return $this->_skipXmlRecords($pos); } /** * Close the file * * @copyright * @author RolandD * @todo * @see * @access public * @param * @return * @since 3.0 */ public function closeFile($removefolder=true) { $this->data->close(); $this->_xml_cache = false; $this->_closed = true; parent::closeFile($removefolder); } /** * Read the next line in the file * * @copyright * @author RolandD * @todo * @see * @access public * @param * @return array with the line of data read | false if data cannot be read * @since 3.0 */ public function readNextLine() { $jinput = JFactory::getApplication()->input; $csvilog = $jinput->get('csvilog', null, null); $csvilog->addDebug('Reading next line'); if ($this->_getXmlData() == true) { $this->linepointer++; return $this->_xml_data; } else { return false; } } /** * Process the file to import * * @copyright * @author RolandD * @todo * @see * @access public * @param * @return * @since 3.0 */ public function processFile() { $jinput = JFactory::getApplication()->input; $csvilog = $jinput->get('csvilog', null, null); // Use a streaming approach to support large files $this->data = new XMLReader(); $this->fp = $this->data->open($this->filename); if ($this->fp == false) { $csvilog->AddStats('incorrect', JText::_('COM_CSVI_ERROR_XML_READING_FILE')); return false; } // File opened successfully - Prepare the arrays needed to read data from the XML file $this->fp = $this->_getXmlSchema(); if ($this->fp == false) { $this->closeFile(); $csvilog->AddStats('incorrect', JText::_('COM_CSVI_XML_INVALID_TABLE')); return false; } return true; } /** * Searches an XML file for a series of nodes representing a complete record. The name(s) of the nodes representing records * must be supplied (via the 'xml_nodes_map' field) but the list of fields can be supplied in three ways: * 1 No fields defined in the 'xml_nodes_map' field and the 'use headers' option set to 'off'. Despite the 'use headers' being set * to 'off', the field nodes in the first record are used to configure the whole run. This requires that all fields be present in * every record, the node names match the field names and that all of the 'field' nodes are one level below the 'record' node in * the XML hierarchy. * 2 No fields defined in the 'xml_nodes_map' field and the 'use headers' option set to 'on'. This causes the 'headers to be read * from the XML nodes for every record. This is suitable if not all of the fields are populated for every record in the XML file * but is slower than option 1. * 3 Fields defined in the 'xml_nodes_map' field. The 'use headers' option is ignored. This gives the flexibility to set up a map * so that an XML hierarchy can be modelled, node names to be mapped to field names and also allows fields to be extracted from * node attributes. * * It is possible that the current node when the function is called is the start of the next record. * Valid 'record' node names are held in the $this->_xml_records array. * Valid 'field' node and attribute names are held in the $this->_xml_schema array. * The arrays $this->_xml_data and $this->_xml_fields are populated with data and field names respectively. To prevent SQL errors * when writing the data to the table, only fields found in the array $this->_supported_fields are included. This function could be * extended. * * @copyright * @author doorknob * @todo * @see * @access private * @param * @return bool - indicates whether the array $this->_xml_data was populated. * @since 3.0 */ private function _getXmlFieldsAndData() { $jinput = JFactory::getApplication()->input; $csvilog = $jinput->get('csvilog', null, null); // Initialise the arrays that will receive the data and field list from the next record $this->_xml_data = array(); $this->_xml_fields = array(); // Validation checking disabled because a DTD (or RELAX NG) schema is required and is usually not available $validate_xml = false; if( $validate_xml == true ) { // Note: When the DTD is external, this must be done before the first read() $this->data->setParserProperty(XMLReader::VALIDATE, true); } /** * Search for the start of the next record but only read the file if the next record is not already current * Must be the correct element type (start of node) and in the list of valid record nodes. * Note: Self closing notes are accepted because they may contain data in the attributes */ if (!$this->_isXmlRecordNode($this->data->nodeType, $this->data->name)) { // Either no current node or the current node is not the start of a record while( $this->data->read() ) { if( $validate_xml == true ) { $this->fp = $this->data->isValid(); if( $this->fp == false ){ $this->closeFile(); $csvilog->AddStats('incorrect', JText::_('COM_CSVI_XML_FILE_INVALID')); return false; } } if( $this->_isXmlRecordNode( $this->data->nodeType, $this->data->name ) ) { // Record node found break; } } } // Check whether a record was found if ($this->_isXmlRecordNode($this->data->nodeType, $this->data->name)) { // Start of a valid record $self_closing = $this->data->isEmptyElement; $record_name = strtolower($this->data->name); // Extract any attributes, if defined if (isset($this->_xml_schema[$record_name]['attrs']) ) { // Record level attributes are defined as fields while( $this->data->moveToNextAttribute() ) { // Check each attribute to determine whether the value should be extracted if( isset($this->_xml_schema[$record_name]['attrs'][strtolower($this->data->name)]) ) { $this->_xml_fields[] = $this->_xml_schema[$record_name]['attrs'][strtolower($this->data->name)]; $this->_xml_data[] = $this->data->value; } } } if ($self_closing == false) { // Now search for group/field nodes $xml_path = array(); /** * Note: $this->data->next() is used rather than $this->data->read() when the readInnerXML() function has been used * to extract the contents of a node. Because the contect extracted may contain other nodes,$this->data->next() is * used to skip to the closing node. * readInnerXML() is used in case the data contains html tags but it doesn't move the file pointer. * Subsequently using $this->data->next() forces the pointer to skip past any HTML tags that have already been read. * The value does not need to be maintained between between calls to this function because readInnerXML() is * never used immediately before exiting the function. */ $use_read = true; while ($use_read == true ? $this->data->read() : $this->data->next() ) { // XML error detection if ($validate_xml == true) { $this->fp = $this->data->isValid(); if( $this->fp == false ){ $this->closeFile(); $csvilog->AddStats('incorrect', JText::_('COM_CSVI_XML_FILE_INVALID')); return false; } } // Default to a reading a single node in the next loop $use_read = true; // Searching for a group or field node if ($this->data->nodeType == XMLReader::ELEMENT) { // New node found $self_closing = $this->data->isEmptyElement; if (empty($this->_xml_schema)) { // Template fields being used to control the data extraction if ($this->_isXmlFieldNameValid($this->data->name)) { // Node corresponding to a supported field found - extract the data $this->_xml_fields[] = strtolower($this->data->name); $xmldata = $this->data->readInnerXML(); $xmldata = str_ireplace(array(''), '', $xmldata); $this->_xml_data[] = $xmldata; // At the next read, skip to the next node at this level $use_read = false; } else { // A node has been found that does not match the available fields list $csvilog->addDebug(JText::sprintf('COM_CSVI_XML_NODE_NOT_MATCH_FIELD', $this->data->name)); } } else { // The user defined map is being used to control the data extraction $current_path = $this->_getXmlNodePath($xml_path, strtolower($this->data->name)); // The node may have attributes that map to fields, regardless of the type of node if (isset($this->_xml_schema[$record_name]['nodes'][$current_path]['attrs'])) { // Node has attributes that are defined as fields while ($this->data->moveToNextAttribute()) { // Check each attribute to determine whether the value should be extracted if( isset($this->_xml_schema[$record_name]['nodes'][$current_path]['attrs'][strtolower($this->data->name)]) ) { $this->_xml_fields[] = $this->_xml_schema[$record_name]['nodes'][$current_path]['attrs'][strtolower($this->data->name)]; $xmldata = $this->data->readInnerXML(); $xmldata = str_ireplace(array(''), '', $xmldata); $this->_xml_data[] = $xmldata; // At the next read, skip to the next node at this level $use_read = false; } } } if (empty($this->_xml_schema[$record_name]['nodes'][$current_path]['field'])) { // This node is not defined as a field if (isset($this->_xml_schema[$record_name]['nodes'][$current_path]['field'])) { // This is a 'group' node - add it to the path unless it is self closing if( $self_closing == false ) { $this->_pushXmlNodePath( $xml_path, $this->data->name ); } } else { // Unknown node found - The file is not mapped correctly and the run cannot continue $csvilog->addDebug(JText::sprintf('COM_CSVI_XML_UNMAPPED_NODE', $this->data->name)); $csvilog->AddStats('incorrect', JText::sprintf('COM_CSVI_XML_UNDEFINED_NODE', $this->data->name)); return false; } } else { // This node is defined as a field - extract the data $this->_xml_fields[] = $this->_xml_schema[$record_name]['nodes'][$current_path]['field']; $xmldata = $this->data->readInnerXML(); $xmldata = str_ireplace(array(''), '', $xmldata); $this->_xml_data[] = $xmldata; // At the next read, skip to the next node at this level $use_read = false; } } } else if ($this->data->nodeType == XMLReader::END_ELEMENT) { // Searching for the end of the record or the end of a group node if( strtolower($this->data->name) == $record_name ) { // End of record found break; } else { // End of node - Only valid case is the end of a group node if( !empty($this->_xml_schema) && !empty($xml_path) && $xml_path[count($xml_path)-1] == strtolower($this->data->name) ) { // End of group node found - pop it from the stack $this->_popXmlNodePath( $xml_path ); } else { // Unknown end of node - error $csvilog->addDebug(JText::sprintf('COM_CSVI_XML_UNEXPECTED_END_NODE', $this->data->name)); } } } } } } $this->_xml_cache = !empty($this->_xml_data); return $this->_xml_cache; } /** * Returns a boolean value to indicate whether the specified node is a new XML record type. * * @copyright * @author doorknob * @todo * @see * @access private * @param * @return bool true if record is a node | false if record is not a node * @since 3.0 */ private function _isXmlRecordNode( $node_type, $node_name ) { return ($node_type == XMLReader::ELEMENT && in_array(strtolower($node_name), $this->_xml_records)); } /** * Returns the list of data values found in the most recently read XML record. If the getXmlFields() function has been * called since the last call of this function, the cache may be full and the data can be returned without reading the file. * * @return array - The list of data values from the most recently read XML record (empty when end of file is reached) */ private function _getXmlData() { $return = !empty($this->_xml_data); if( $this->_xml_cache == false ) { $return = $this->_getXmlFieldsAndData(); } // Indicate that a new record will be required the next time this function is called $this->_xml_cache = false; return $return; } /** * Returns the list of fields found in the most recently read XML record. If the cache is empty, the next record is * read from the input file to ensure that the headers correspond with the data (in XML files, each record can have a * different set of 'headers'). Checking the status of the cache indicator also prevents records being skipped if this * function is called multiple times between records. * * @return array - The list of fields from the most recently read XML record (empty when end of file is reached) */ private function _getXmlFields() { $return = !empty($this->_xml_fields); if ($this->_xml_cache == false) { $return = $this->_getXmlFieldsAndData(); } return $return; } /** * Skips through the XML file until the the required number 'record' nodes has been read * Assume the file pointer is at the start of file * * @copyright * @author doorknob, RolandD * @todo * @see * @access private * @param * @return boolean true if records are skipped | false if records are not skipped * @since 3.0 */ private function _skipXmlRecords($pos) { $jinput = JFactory::getApplication()->input; $csvilog = $jinput->get('csvilog', null, null); // Check whether the pointer needs to be moved if ($pos <= 0) return true; $count = 0; /** * Note: When the DTD is external, this must be done before the first read() * Validation not used because invalid files generate php errors when validated */ $validate_xml = false; if( $validate_xml == true ) { $this->data->setParserProperty(XMLReader::VALIDATE, true); } while ($this->data->read()) { // Validation checking disabled because a DTD (or RELAX NG) schema is required and is usually not available if( $validate_xml == true ) { $this->fp = $this->data->isValid(); if( $this->fp == false ){ $this->closeFile(); $csvilog->AddStats('incorrect', JText::_('COM_CSVI_XML_INVALID')); return false; } } // Searching for a valid record - must be the start of a node and in the list of valid record types if( !$this->_isXmlRecordNode( $this->data->nodeType, $this->data->name ) ) { // Not found - try again continue; } else { // Found a valid record while( $this->_isXmlRecordNode( $this->data->nodeType, $this->data->name ) ) { // Node is a valid record type - skip to the end of the record $this->data->next(); $count++; if( $count == $pos) { return true; } } } } // Hit EOF before skipping the required number of records return false; } /** * Build an array of xml nodes from the user defined map: * * $this->_xml_schema[record_node]['attrs'][attr_name] => field name * $this->_xml_schema[record_node]['nodes'][field_node_path]['attrs'][attr_name] => field name * $this->_xml_schema[record_node]['nodes'][field_node_path]['field'] => field name * Note: field_node_path is a comma separated list of node names below the record node * * @return bool returns true if all fine else false */ private function _getXmlSchema() { $jinput = JFactory::getApplication()->input; $template = $jinput->get('template', null, null); $xml_nodes_map = $template->get('xml_nodes_map', 'general', '', 'string', JREQUEST_ALLOWRAW); $xml_node_path = array(); // Single copy of this array that is passed by reference only $current_record = ''; // Single copy of this variable that is passed by reference only return $this->_getXmlNode($xml_nodes_map, $current_record, $xml_node_path); } /** * Process a node from the XML Map * It is permitted for the XML to just define one or more tables without fields (when the 'use headers' option is used) * * Note: Calls itself recursively to process a tree * * @return bool returns true if all fine else false */ private function _getXmlNode($node_content, $current_record, $xml_path) { $jinput = JFactory::getApplication()->input; $csvilog = $jinput->get('csvilog', null, null); $current_node = ''; $xml_schema = new XMLReader(); /** * Add a wrapper to make the XML viable and ensure that self closing tags contain a space before the '/>' * The XML may still be invalid but that's down to what the user entered */ $node_content = "\n".$node_content.''; $xml_schema->XML($node_content); // XML file to table map is valid XML - construct the arrays used in file extraction $use_read = true; // The XML could only be validated against a DTD if the syntax of the XML used for the map is made more complex $validate_xml = false; if ($validate_xml == true) { // Note: When the DTD is external, the property value must be set before the first read() $xml_schema->setParserProperty(XMLReader::VALIDATE, true); } while($use_read ? $xml_schema->read() : $xml_schema->next()) { // Validation checking disabled because a DTD (or RELAX NG) schema is required. if ($validate_xml == true) { if( $xml_schema->isValid() == false ){ $xml_schema->close(); return false; } } // Default to a reading a single node in the next loop $use_read = true; // Ignore any node associated with the root if ($xml_schema->name == 'da_root' ) { continue; } // Process start elements if ($xml_schema->nodeType == XMLReader::ELEMENT) { $self_closing = $xml_schema->isEmptyElement; // Ready to add a new node - but only if the last node was closed if (!empty($current_node)) { $csvilog->AddStats('incorrect', JText::sprintf('COM_CSVI_XML_NODE_UNCLOSED', $current_node)); return false; } // A new node was found - Check whether this is a new record type if (empty($current_record)) { // New record type // Check for a self-closing node $self_closing = $xml_schema->isEmptyElement; $current_record = strtolower($xml_schema->name); $this->_xml_records[] = strtolower($current_record); // Store any attributes while ($xml_schema->moveToNextAttribute()) { // Note1: $xml_schema->hasValue only indicates whether the element can have a value, not whether it does // Note2: empty($xml_schema->value) always return true, regardless of the actual value $value = $xml_schema->value; if( !empty($value) ) { if( $this->_isXmlFieldNameValid($xml_schema->value) ) { $this->_xml_schema[$current_record]['attrs'][strtolower($xml_schema->name)] = trim($xml_schema->value); } else { $csvilog->AddStats('incorrect', JText::sprintf('COM_CSVI_XML_FILE_MAP_NO_REFERENCE', $xml_schema->value)); $xml_schema->close(); return false; } } } // Check for a self-closing node if( $self_closing == true ) { $current_record = ''; } } else { // New field type $current_node = strtolower($xml_schema->name); $current_path = $this->_getXmlNodePath($xml_path, $current_node); // Store any attributes while ($xml_schema->moveToNextAttribute()) { // Note1: $xml_schema->hasValue only indicates whether the element can have a value, not whether it does // Note2: empty($xml_schema->value) always return true, regardless of the actual value $value = $xml_schema->value; if( !empty($value) ) { if( $this->_isXmlFieldNameValid( $xml_schema->value ) ) { $this->_xml_schema[$current_record]['nodes'][$current_path]['attrs'][strtolower($xml_schema->name)] = trim($xml_schema->value); } else { $csvilog->AddStats('incorrect', JText::_('COM_CSVI_XML_FILE_MAP_NO_REFERENCE', $xml_schema->value)); $xml_schema->close(); return false; } } } $sub_node_content = $xml_schema->readInnerXML(); // Check whether there are any lower level nodes if (strstr($sub_node_content, '<') === false) { /** * Content has no embedded nodes - Assume a field name * Note: An empty node gives a blank field name which indicates an unwanted node * that is being mapped to prevent errors when processing the file */ if ($this->_isXmlFieldNameValid($sub_node_content)) { $this->_xml_schema[$current_record]['nodes'][$current_path]['field'] = trim($sub_node_content); } else { $this->_xml_schema[$current_record]['nodes'][$current_path]['field'] = ''; } } else { // There are embedded nodes - go down another level // Indicate a 'group' node by storing an empty field name $this->_xml_schema[$current_record]['nodes'][$current_path]['field'] = ''; // Push the node name to the path stack $this->_pushXmlNodePath($xml_path, $current_node); if( $this->_getXmlNode($sub_node_content, $current_record, $xml_path) == false ) { $xml_schema->close(); return false; } // At the next read, skip to the next node at this level $use_read = false; // Close the node $current_node = ''; // Pop the last item off the path stack $this->_popXmlNodePath($xml_path); } // Check for a self-closing node if ($self_closing == true) { $current_node = ''; } } } // Process end elements else if( $xml_schema->nodeType == XMLReader::END_ELEMENT ) { // End of node found // Check for end of record if( !empty($current_record) && strtolower($xml_schema->name) == $current_record ) { // End of record detected $current_record = ''; } // Check that the expected node was closed else if( !empty($current_node) && strtolower($xml_schema->name) == $current_node ) { // End of current node detected $current_node = ''; } } } $xml_schema->close(); // Node not terminated if (!empty($current_node) ) { $csvilog->AddStats('incorrect', JText::sprintf('COM_CSVI_XML_NODE_NOT_CLOSED', $current_node)); return false; } if (empty($this->_xml_records) ) { $csvilog->AddStats('incorrect', JText::_('COM_CSVI_XML_NO_RECORDS_DEFINED')); return false; } return true; } /** * Create a string to represent the XML node hierarchy from the 'record' node to a 'field' node * * @return string */ private function _getXmlNodePath($xml_path, $node_name) { return implode(',', $xml_path).(empty($xml_path) ? '' : ',').$node_name; } /** * Determines whether a specific field name is included in the list of * * @return boolean */ private function _isXmlFieldNameValid($field_name) { return in_array(strtolower($field_name), $this->_supported_fields); } /** * Add a new entry to the XML node stack */ private function _pushXmlNodePath($xml_path, $node_name) { /** * Note: The array index is made explicit because when a new row is added, the index value * assigned is one greater than that previously assigned. When enries are being continuously * added and removed, the automatically assigned index number becomes unpredictable */ $xml_path[count($xml_path)] = strtolower($node_name); } /** * Remove the last entry from the XML node stack * * @copyright * @author doorknob * @todo * @see * @access private * @param * @return * @since 3.0 */ private function _popXmlNodePath($xml_path) { if( count($xml_path) > 1 ) { unset($xml_path[count($xml_path)-1]); } else { $xml_path = array(); } } /** * Sets the file pointer back to beginning * * @copyright * @author RolandD * @todo * @see * @access public * @param * @return * @since 3.0 */ public function rewind() { $this->linepointer = 0; } /** * Advances the file pointer 1 forward * * @copyright * @author RolandD * @todo * @see * @access public * @param bool $preview True if called from the preview * @return * @since 3.0 */ public function next($preview=false) { if (!$preview) $discard = $this->readNextLine(); } } ?> import/index.html000066600000000000151401667440010055 0ustar00import/ods_reader.php000066600000011626151401667440010720 0ustar00 */ public function read($filename) { $this->_file = $filename; list($this->_xml_parser, $fp) = $this->new_xml_parser($this->_file); if (!$this->_xml_parser) { die("could not open XML input"); } $data = ''; while (!feof($fp)) { $data .= fread($fp, 4096); } fclose($fp); if (!xml_parse($this->_xml_parser, $data, true)) { die(sprintf("XML error: %s at line %d\n", xml_error_string(xml_get_error_code($this->_xml_parser)), xml_get_current_line_number($this->_xml_parser))); } xml_parser_free($this->_xml_parser); $this->cols = count($this->_data[1]); $this->rows = count($this->_data); return true; } /** * Handle the opening element */ private function startElement($parser, $tagname, $attribs) { switch ($tagname) { case 'TABLE:TABLE-ROW': $this->_linecount++; break; case 'TABLE:TABLE-CELL': $styles = array_keys($attribs); if (empty($styles)) { $this->_data[$this->_linecount]['options']['repeat'] = 1; } else { foreach ($styles as $stylekey => $style) { switch ($style) { case 'TABLE:NUMBER-COLUMNS-REPEATED': $this->_data[$this->_linecount]['options']['repeat'] = $attribs[$style]; break; case 'OFFICE:VALUE-TYPE': $this->_data[$this->_linecount]['options']['type'] = $attribs[$style]; break; } } } break; case 'TEXT:P': $this->_data[$this->_linecount]; break; } } /** * Handle the closing element */ private function endElement($parser, $name) { if (array_key_exists($this->_linecount, $this->_data)) { if (!array_key_exists('data', $this->_data[$this->_linecount]) && array_key_exists('options', $this->_data[$this->_linecount])) { foreach ($this->_data[$this->_linecount]['options'] as $option => $value) { switch ($option) { case 'type': break; case 'repeat': for ($r=0; $r < $value; $r++) { $this->_data[$this->_linecount][] = ''; } break; } } } else unset($this->_data[$this->_linecount]['data']); if (array_key_exists('options', $this->_data[$this->_linecount])) unset($this->_data[$this->_linecount]['options']); } } /** * Handle the data * * @todo parse */ private function characterData($parser, $data) { foreach ($this->_data[$this->_linecount]['options'] as $option => $value) { switch ($option) { case 'type': break; case 'repeat': for ($r=1; $r < $value; $r++) { $this->_data[$this->_linecount][] = $data; } break; } } $this->_data[$this->_linecount][] = $data; unset($this->_data[$this->_linecount]['options']); $this->_data[$this->_linecount]['data'] = true; } private function new_xml_parser($file) { $this->_xml_parser = xml_parser_create("UTF-8"); xml_parser_set_option($this->_xml_parser, XML_OPTION_CASE_FOLDING, 1); xml_set_object($this->_xml_parser, $this); xml_set_element_handler($this->_xml_parser, "startElement", "endElement"); xml_set_character_data_handler($this->_xml_parser, "characterData"); $fp = fopen($file, "rb"); if (!$fp) return false; else return array($this->_xml_parser, $fp); } } ?> import/.htaccess000066600000000177151401667440007675 0ustar00 Order allow,deny Deny from all index.html000066600000000000151401667440006543 0ustar00export/index.html000066600000000000151401667440010064 0ustar00export/html/index.html000066600000000000151401667440011030 0ustar00export/html/.htaccess000066600000000177151401667440010650 0ustar00 Order allow,deny Deny from all export/html/csvimproved.php000066600000005372151401667440012126 0ustar00contents = ''.chr(10); $this->contents .= ''.chr(10); return $this->contents; } /** * Start the table header * * @return string start table header */ function StartTableHeaderText() { return ''; } /** * End the table header * * @return string end table header */ function EndTableHeaderText() { return ''.chr(10); } /** * Creates the table header * * @return string th field */ public function TableHeaderText($headers) { return ''; } /** * Start the table body header * * @see $contents * @return string table body header */ public function BodyText() { return ''; } /** * Creates the HTML footer * * @see $contents * @return string HTML footer */ function FooterText() { $this->contents = '
'.$headers.'
'.chr(10); return $this->contents; } /** * Opens a table row * * @see $contents * @return string tr opening tag */ function NodeStart() { $this->contents = ''.chr(10); return $this->contents; } /** * Closes a table row * * @see $contents * @return string tr closing tag */ function NodeEnd() { $this->contents = ''.chr(10); return $this->contents; } /** * Adds a table td element * * @see $node * @return string td row */ function Element($column_header, $cdata=false) { $this->node = ''; $this->node .= $this->contents; $this->node .= ''; $this->node .= "\n"; return $this->node; } /** * Handles all content and modifies special cases * * @see $contents * @return string formatted table row */ function ContentText($content, $column_header, $fieldname, $cdata=false) { switch ($fieldname) { default: $this->contents = $content; break; } return $this->Element($column_header, $cdata); } } ?> export/xml/index.html000066600000000000151401667440010664 0ustar00export/xml/oodle.php000066600000004715151401667440010523 0ustar00contents = ''.chr(10); $this->contents .= ''.chr(10); return $this->contents; } /** * Creates the XML footer * * @see $contents * @return string XML header */ function FooterText() { $this->contents = ''.chr(10); return $this->contents; } /** * Opens an XML item node * * @see $contents * @return string XML node data */ function NodeStart() { $this->contents = ''.chr(10); return $this->contents; } /** * Closes an XML item node * * @see $contents * @return string XML node data */ function NodeEnd() { $this->contents = ''.chr(10); return $this->contents; } /** * Adds an XML element * * @see $node * @return string XML element */ function Element($column_header, $cdata=false) { $this->node = '<'.$column_header.'>'; if ($cdata) $this->node .= 'node .= $this->contents; if ($cdata) $this->node .= ']]>'; $this->node .= ''; $this->node .= "\n"; return $this->node; } /** * Handles all content and modifies special cases * * @see $contents * @return string formatted XML element */ function ContentText($content, $column_header, $fieldname, $cdata=false) { switch ($fieldname) { case 'manufacturer_name': case 'product_url': $cdata = true; default: $this->contents = $content; break; } if (empty($column_header)) $column_header = $fieldname; return $this->Element($column_header, $cdata); } } ?> export/xml/csvimproved.php000066600000004715151401667440011762 0ustar00contents = ''.chr(10); $this->contents .= ''.chr(10); return $this->contents; } /** * Creates the XML footer * * @see $contents * @return string XML header */ public function FooterText() { $this->contents = ''.chr(10); return $this->contents; } /** * Opens an XML item node * * @see $contents * @return string XML node data */ public function NodeStart() { $this->contents = ''.chr(10); return $this->contents; } /** * Closes an XML item node * * @see $contents * @return string XML node data */ public function NodeEnd() { $this->contents = ''.chr(10); return $this->contents; } /** * Adds an XML element * * @see $node * @return string XML element */ private function Element($column_header, $cdata=false) { $this->node = '<'.$column_header.'>'; if ($cdata) $this->node .= 'node .= $this->contents; if ($cdata) $this->node .= ']]>'; $this->node .= ''; $this->node .= "\n"; return $this->node; } /** * Handles all content and modifies special cases * * @see $contents * @return string formatted XML element */ public function ContentText($content, $column_header, $fieldname, $cdata=false) { switch ($fieldname) { case 'field_default_value': case 'product_attribute': $cdata = true; default: $this->contents = $content; break; } if (empty($column_header)) $column_header = $fieldname; return $this->Element($column_header, $cdata); } } ?> export/xml/google.php000066600000010514151401667440010667 0ustar00contents = ''.chr(10); $this->contents .= 'contents .= 'xmlns:c="http://base.google.com/cns/1.0">'.chr(10); $this->contents .= ''.chr(10); // Get the XML channel header $settings = JRequest::getVar('settings'); $this->contents .= ''.$settings->get('google_base.gb_title').''.chr(10); $this->contents .= ''.$settings->get('google_base.gb_link').''.chr(10); $this->contents .= ''.$settings->get('google_base.gb_description').''.chr(10); return $this->contents; } /** * Creates the XML footer * * @see $contents * @return string XML header */ function FooterText() { $this->contents = ''.chr(10); $this->contents .= ''.chr(10); return $this->contents; } /** * Opens an XML item node * * @see $contents * @return string XML node data */ function NodeStart() { $this->contents = ''.chr(10); return $this->contents; } /** * Closes an XML item node * * @see $contents * @return string XML node data */ function NodeEnd() { $this->contents = ''.chr(10); return $this->contents; } /** * Adds an XML element * * @see $node * @return string XML element */ function Element($column_header, $cdata=false) { if (stristr($column_header, 'c:')) { $this->node = '<'.$column_header.' type="string">'; } else $this->node = '<'.$column_header.'>'; if ($cdata) $this->node .= 'node .= $this->contents; if ($cdata) $this->node .= ']]>'; $this->node .= ''; $this->node .= "\n"; return $this->node; } /** * Handles all content and modifies special cases * * @see $contents * @return string formatted XML element */ function ContentText($content, $column_header, $fieldname, $cdata=false) { switch ($fieldname) { case 'custom_shipping': switch($column_header) { case 'g:shipping': if (strpos($content, ':')) { list($country, $service, $price) = explode(":", $content); $this->contents = ' '.$country.' '.$service.' '.$price.' '; } else $this->contents = ''; break; } break; case 'custom': switch($column_header) { case 'g:tech_spec_link': $cdate = true; $this->contents = $content; break; case 'g:tax': list($country, $region, $rate, $tax_ship) = explode(":", $content); $this->contents = ' '.$country.' '.$region.' '.$rate.' '.$tax_ship.' '; break; default: $this->contents = $content; break; } break; case 'category_path': $paths = explode("|", $content); $content = ''; foreach ($paths as $id => $path) { $this->contents = str_replace('/', '>', $path); $content .= $this->Element($column_header, $cdata); } return $content; break; case 'manufacturer_name': case 'product_url': $cdata = true; default: $this->contents = $content; break; } if (empty($column_header)) $column_header = $fieldname; return $this->Element($column_header, $cdata); } } ?> export/xml/beslist.php000066600000004002151401667440011053 0ustar00contents = ''.chr(10); $this->contents .= ''.chr(10); return $this->contents; } function FooterText() { $this->contents = ''.chr(10); return $this->contents; } function NodeStart() { $this->contents = ''.chr(10); return $this->contents; } function NodeEnd() { $this->contents = ''.chr(10); return $this->contents; } function Element($column_header, $cdata=false) { $this->node = '<'.$column_header.'>'; if ($cdata) $this->node .= 'node .= $this->contents; if ($cdata) $this->node .= ']]>'; $this->node .= ''; $this->node .= "\n"; return $this->node; } function ContentText($content, $column_header, $fieldname, $cdata=false) { switch ($fieldname) { case 'category_path': $this->CategoryPath($content); break; case 'manufacturer_name': case 'product_url': $cdata = true; default: $this->contents = $content; break; } if (empty($column_header)) $column_header = $fieldname; return $this->Element($column_header, $cdata); } function CategoryPath($category) { $this->contents = str_replace("/", " > ", trim($category)); } } ?> export/xml/custom.php000066600000005224151401667440010727 0ustar00input; $template = $jinput->get('template', null, null); return $template->get('header', 'layout', '', null, 2); } /** * Creates the XML footer * * @see $contents * @return string XML header */ public function FooterText() { $jinput = JFactory::getApplication()->input; $template = $jinput->get('template', null, null); return $template->get('footer', 'layout', '', null, 2); } /** * Opens an XML item node * * @see $contents * @return string XML node data */ public function NodeStart() { $this->_node(); return; } /** * Closes an XML item node * * @see $contents * @return string XML node data */ public function NodeEnd() { return $this->_node; } /** * A full node template * * @copyright * @author RolandD * @todo * @see * @access private * @param * @return * @since 3.0 */ private function _node() { $jinput = JFactory::getApplication()->input; $template = $jinput->get('template', null, null); $this->_node = $template->get('body', 'layout', '', null, 2); } /** * Adds an XML element * * @see $node * @return string XML element */ private function _element($content, $fieldname, $cdata=false) { $data = ''; if ($cdata) $data .= ''; $this->_node = str_ireplace('['.$fieldname.']', $data, $this->_node); return; } /** * Handles all content and modifies special cases * * @see $contents * @return string formatted XML element */ public function ContentText($content, $column_header, $fieldname, $cdata=false) { if (empty($column_header)) $column_header = $fieldname; return $this->_element($content, $column_header, $cdata); } } ?> export/xml/.htaccess000066600000000177151401667440010504 0ustar00 Order allow,deny Deny from all export/.htaccess000066600000000177151401667440007704 0ustar00 Order allow,deny Deny from all .htaccess000066600000000177151401667440006363 0ustar00 Order allow,deny Deny from all