Bugfix: Workitem 14374 - BUG : Excel5 and setReadFilter ?

Modifications to Worksheet's to_array() method to handle worksheets partially loaded with a readFilter by switching to iterators

git-svn-id: https://phpexcel.svn.codeplex.com/svn/trunk@61913 2327b42d-5241-43d6-9e2a-de5ac946f064
This commit is contained in:
Mark Baker 2010-10-06 12:57:54 +00:00
parent 2ec5a8b3bb
commit 9946aa1595
2 changed files with 416 additions and 236 deletions

View File

@ -2118,48 +2118,47 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable
* @param mixed $nullValue Value returned in the array entry if a cell doesn't exist
* @param boolean $calculateFormulas Should formulas be calculated?
* @param boolean $formatData Should formatting be applied to cell values?
* @param boolean $returnColumnRef False - Return columns indexed by number (0..x)
* True - Return columns indexed by column ID (A..x)
* @param boolean $returnCellRef False - Return a simple array of rows and columns indexed by number counting from zero
* True - Return rows and columns indexed by their actual row and column IDs
* @return array
*/
public function toArray($nullValue = null, $calculateFormulas = true, $formatData = true, $returnColumnRef = false) {
public function toArray($nullValue = null, $calculateFormulas = true, $formatData = true, $returnCellRef = false) {
// Returnvalue
$returnValue = array();
// Garbage collect...
$this->garbageCollect();
// Get worksheet dimension
$dimension = explode(':', $this->calculateWorksheetDimension());
$dimension[0] = PHPExcel_Cell::coordinateFromString($dimension[0]);
$dimension[0][0] = PHPExcel_Cell::columnIndexFromString($dimension[0][0]) - 1;
$dimension[1] = PHPExcel_Cell::coordinateFromString($dimension[1]);
$dimension[1][0] = PHPExcel_Cell::columnIndexFromString($dimension[1][0]) - 1;
// Loop through cells
for ($row = $dimension[0][1]; $row <= $dimension[1][1]; ++$row) {
for ($column = $dimension[0][0]; $column <= $dimension[1][0]; ++$column) {
$columnRef = ($returnColumnRef) ? PHPExcel_Cell::stringFromColumnIndex($column) : $column;
// Loop through rows
$r = -2;
$rowIterator = $this->getRowIterator();
foreach ($rowIterator as $row) {
++$r;
$cellIterator = $row->getCellIterator();
$cellIterator->setIterateOnlyExistingCells(true); // Loop through each cell in the current row
$c = -1;
foreach ($cellIterator as $cell) {
++$c;
$rRef = ($returnCellRef) ? $cell->getRow() : $r;
$cRef = ($returnCellRef) ? $cell->getColumn() : $c;
if (!is_null($cell)) {
// Cell exists?
if ($this->cellExistsByColumnAndRow($column, $row)) {
$cell = $this->getCellByColumnAndRow($column, $row);
if ($cell->getValue() instanceof PHPExcel_RichText) {
$returnValue[$row][$columnRef] = $cell->getValue()->getPlainText();
$returnValue[$rRef][$cRef] = $cell->getValue()->getPlainText();
} else {
if ($calculateFormulas) {
$returnValue[$row][$columnRef] = $cell->getCalculatedValue();
$returnValue[$rRef][$cRef] = $cell->getCalculatedValue();
} else {
$returnValue[$row][$columnRef] = $cell->getValue();
$returnValue[$rRef][$cRef] = $cell->getValue();
}
}
if ($formatData) {
$style = $this->_parent->getCellXfByIndex($cell->getXfIndex());
$returnValue[$row][$columnRef] = PHPExcel_Style_NumberFormat::toFormattedString($returnValue[$row][$columnRef], $style->getNumberFormat()->getFormatCode());
$returnValue[$rRef][$cRef] = PHPExcel_Style_NumberFormat::toFormattedString($returnValue[$rRef][$cRef], $style->getNumberFormat()->getFormatCode());
}
} else {
$returnValue[$row][$columnRef] = $nullValue;
$returnValue[$rRef][$cRef] = $nullValue;
}
}
}

View File

@ -478,6 +478,8 @@ class PHPExcel_Writer_Excel5_Workbook extends PHPExcel_Writer_Excel5_BIFFwriter
// Add part 3 of the Workbook globals
$this->_data .= $part3;
$this->_data .= $this->_createPropertySets();
return $this->_data;
}
@ -1423,6 +1425,185 @@ class PHPExcel_Writer_Excel5_Workbook extends PHPExcel_Writer_Excel5_BIFFwriter
}
}
private function _createPropertySets()
{
$stream = pack('v*', unpack('C*', "\5SummaryInformation"));
$summary = $this->_create_summary_property_set();
$stream = pack('v*', unpack('C*', "\5DocumentSummaryInformation"));
$summary = $this->_create_doc_summary_property_set();
}
private function _create_summary_property_set()
{
$properties = array();
if ($this->_phpExcel->getProperties()->getTitle() > '') {
$properties[] = array( 'value' => $this->_phpExcel->getProperties()->getTitle(), 'id' => 0x02);
}
if ($this->_phpExcel->getProperties()->getSubject() > '') {
$properties[] = array( 'value' => $this->_phpExcel->getProperties()->getSubject(), 'id' => 0x03);
}
if ($this->_phpExcel->getProperties()->getCreator() > '') {
$properties[] = array( 'value' => $this->_phpExcel->getProperties()->getCreator(), 'id' => 0x04);
}
if ($this->_phpExcel->getProperties()->getKeywords() > '') {
$properties[] = array( 'value' => $this->_phpExcel->getProperties()->getKeywords(), 'id' => 0x05);
}
if ($this->_phpExcel->getProperties()->getDescription() > '') {
$properties[] = array( 'value' => $this->_phpExcel->getProperties()->getDescription(), 'id' => 0x06);
}
if ($this->_phpExcel->getProperties()->getLastModifiedBy() > '') {
$properties[] = array( 'value' => $this->_phpExcel->getProperties()->getLastModifiedBy(), 'id' => 0x08);
}
if ($this->_phpExcel->getProperties()->getCreated() > '') {
$properties[] = array( 'value' => $this->_phpExcel->getProperties()->getCreated(), 'id' => 0x0C);
}
if ($this->_phpExcel->getProperties()->getModified() > '') {
$properties[] = array( 'value' => $this->_phpExcel->getProperties()->getModified(), 'id' => 0x0D);
}
$propertyCount = count($properties);
if ($propertyCount > 0) {
$byte_order = pack('v', 0xFFFE);
$version = pack('v', 0x0000);
$system_id = pack('V', 0x00020105);
$class_id = pack('H*', '00000000000000000000000000000000');
$num_property_sets = pack('V', 0x0001);
$format_id = pack('H*', 'E0859FF2F94F6810AB9108002B27B3D9');
$offset = pack('V', 0x0030);
$num_property = pack('V', $propertyCount);
$property_offsets = '';
# Create the property set data block and calculate the offsets into it.
list($property_data, $offsets) = $this->_pack_property_data($properties);
# Create the property type and offsets based on the previous calculation.
for ($i = 0; $i < $propertyCount; ++$i) {
$property_offsets .= pack('VV', $properties[$i][0], $offsets[$i]);
}
# Size of $size (4 bytes) + $num_property (4 bytes) + the data structures.
$size = 8 + strlen($property_offsets) + strlen($property_data);
$size = pack('V', $size);
return $byte_order .
$version .
$system_id .
$class_id .
$num_property_sets .
$format_id .
$offset .
$size .
$num_property .
$property_offsets .
$property_data;
} else {
return NULL;
}
}
private function _create_doc_summary_property_set()
{
$properties = array();
if ($this->_phpExcel->getProperties()->getCategory() > '') {
$properties[] = array( 'value' => $this->_phpExcel->getProperties()->getCategory(), 'id' => 0x02);
}
if ($this->_phpExcel->getProperties()->getManager() > '') {
$properties[] = array( 'value' => $this->_phpExcel->getProperties()->getManager(), 'id' => 0x0E);
}
if ($this->_phpExcel->getProperties()->getCompany() > '') {
$properties[] = array( 'value' => $this->_phpExcel->getProperties()->getCompany(), 'id' => 0x0F);
}
$propertyCount = count($properties);
if ($propertyCount > 0) {
$byte_order = pack('v', 0xFFFE);
$version = pack('v', 0x0000);
$system_id = pack('V', 0x00020105);
$class_id = pack('H*', '00000000000000000000000000000000');
$num_property_sets = pack('V', 0x0002);
$format_id_0 = pack('H*', '02D5CDD59C2E1B10939708002B2CF9AE');
$format_id_1 = pack('H*', '05D5CDD59C2E1B10939708002B2CF9AE');
$offset_0 = pack('V', 0x0044);
$num_property_0 = pack('V', $propertyCount);
$property_offsets_0 = '';
# Create the property set data block and calculate the offsets into it.
list($property_data_0, $offsets) = $this->_pack_property_data($properties);
# Create the property type and offsets based on the previous calculation.
for ($i = 0; $i < $propertyCount; ++$i) {
$property_offsets_0 .= pack('VV', $properties[$i][0], $offsets[$i]);
}
# Size of $size (4 bytes) + $num_property (4 bytes) + the data structures.
$data_len = 8 + length($property_offsets_0) + length($property_data_0);
$size_0 = pack('V', $data_len);
# The second property set offset is at the end of the first property set.
$offset_1 = pack('V', 0x0044 + $data_len);
# We will use a static property set stream rather than try to generate it.
$property_data_1 . pack('H*', 0x98 . 0x00 . 0x00 . 0x00 . 0x03 . 0x00 . 0x00 . 0x00 . 0x00 . 0x00 . 0x00 . 0x00 . 0x20 . 0x00 . 0x00 . 0x00 .
0x01 . 0x00 . 0x00 . 0x00 . 0x36 . 0x00 . 0x00 . 0x00 . 0x02 . 0x00 . 0x00 . 0x00 . 0x3E . 0x00 . 0x00 . 0x00 .
0x01 . 0x00 . 0x00 . 0x00 . 0x02 . 0x00 . 0x00 . 0x00 . 0x0A . 0x00 . 0x00 . 0x00 . 0x5F . 0x50 . 0x49 . 0x44 .
0x5F . 0x47 . 0x55 . 0x49 . 0x44 . 0x00 . 0x02 . 0x00 . 0x00 . 0x00 . 0xE4 . 0x04 . 0x00 . 0x00 . 0x41 . 0x00 .
0x00 . 0x00 . 0x4E . 0x00 . 0x00 . 0x00 . 0x7B . 0x00 . 0x31 . 0x00 . 0x36 . 0x00 . 0x43 . 0x00 . 0x34 . 0x00 .
0x42 . 0x00 . 0x38 . 0x00 . 0x33 . 0x00 . 0x42 . 0x00 . 0x2D . 0x00 . 0x39 . 0x00 . 0x36 . 0x00 . 0x35 . 0x00 .
0x46 . 0x00 . 0x2D . 0x00 . 0x34 . 0x00 . 0x42 . 0x00 . 0x32 . 0x00 . 0x31 . 0x00 . 0x2D . 0x00 . 0x39 . 0x00 .
0x30 . 0x00 . 0x33 . 0x00 . 0x44 . 0x00 . 0x2D . 0x00 . 0x39 . 0x00 . 0x31 . 0x00 . 0x30 . 0x00 . 0x46 . 0x00 .
0x41 . 0x00 . 0x44 . 0x00 . 0x46 . 0x00 . 0x41 . 0x00 . 0x37 . 0x00 . 0x30 . 0x00 . 0x31 . 0x00 . 0x42 . 0x00 .
0x7D . 0x00 . 0x00 . 0x00 . 0x00 . 0x00 . 0x00 . 0x00 . 0x2D . 0x00 . 0x39 . 0x00 . 0x30 . 0x00 . 0x33 . 0x00
);
return $byte_order .
$version .
$system_id .
$class_id .
$num_property_sets .
$format_id_0 .
$offset_0 .
$format_id_1 .
$offset_1 .
$size_0 .
$num_property_0 .
$property_offsets_0 .
$property_data_0 .
$property_data_1;
} else {
return NULL;
}
}
private function _pack_property_data($properties)
{
# The properties start after 8 bytes for size + num_properties + 8 bytes
# for each propety type/offset pair.
$offset += 8 * (count(properties) + 1);
$offsets = $data = array();
foreach($properties as $property) {
$offsets[] = $offset;
$property_type = $property['id'];
if ($property_type == 'VT_I2') {
$packed_property = $this->_pack_VT_I2($property['value']);
} elseif ($property_type == 'VT_LPSTR') {
$packed_property = $this->_pack_VT_LPSTR($property['value'], $this->_codepage);
} elseif ($property_type == 'VT_FILETIME') {
$packed_property = $this->_pack_VT_FILETIME($property['value']);
} else {
die("Unknown property type: $property_type\n");
}
$offset += strlen($packed_property);
$data[] = $packed_property;
}
return array($data, $offsets);
}
/**
* Get Escher object
*