diff --git a/Classes/PHPExcel/Comment.php b/Classes/PHPExcel/Comment.php
index 3a2f947c..34492da6 100644
--- a/Classes/PHPExcel/Comment.php
+++ b/Classes/PHPExcel/Comment.php
@@ -91,6 +91,13 @@ class PHPExcel_Comment implements PHPExcel_IComparable
*/
private $_fillColor;
+ /**
+ * Alignment
+ *
+ * @var string
+ */
+ private $_alignment;
+
/**
* Create a new PHPExcel_Comment
*
@@ -99,9 +106,10 @@ class PHPExcel_Comment implements PHPExcel_IComparable
public function __construct()
{
// Initialise variables
- $this->_author = 'Author';
- $this->_text = new PHPExcel_RichText();
- $this->_fillColor = new PHPExcel_Style_Color('FFFFFFE1');
+ $this->_author = 'Author';
+ $this->_text = new PHPExcel_RichText();
+ $this->_fillColor = new PHPExcel_Style_Color('FFFFFFE1');
+ $this->_alignment = PHPExcel_Style_Alignment::HORIZONTAL_GENERAL;
}
/**
@@ -253,6 +261,26 @@ class PHPExcel_Comment implements PHPExcel_IComparable
return $this->_fillColor;
}
+ /**
+ * Set Alignment
+ *
+ * @param string $pValue
+ * @return PHPExcel_Comment
+ */
+ public function setAlignment($pValue = PHPExcel_Style_Alignment::HORIZONTAL_GENERAL) {
+ $this->_alignment = $pValue;
+ return $this;
+ }
+
+ /**
+ * Get Alignment
+ *
+ * @return string
+ */
+ public function getAlignment() {
+ return $this->_alignment;
+ }
+
/**
* Get hash code
*
@@ -268,6 +296,7 @@ class PHPExcel_Comment implements PHPExcel_IComparable
. $this->_marginTop
. ($this->_visible ? 1 : 0)
. $this->_fillColor->getHashCode()
+ . $this->_alignment
. __CLASS__
);
}
diff --git a/Classes/PHPExcel/Reader/Excel2003XML.php b/Classes/PHPExcel/Reader/Excel2003XML.php
index e86e165d..27d31216 100644
--- a/Classes/PHPExcel/Reader/Excel2003XML.php
+++ b/Classes/PHPExcel/Reader/Excel2003XML.php
@@ -554,180 +554,203 @@ class PHPExcel_Reader_Excel2003XML implements PHPExcel_Reader_IReader
}
$columnID = 'A';
- foreach($worksheet->Table->Column as $columnData) {
- $columnData_ss = $columnData->attributes($namespaces['ss']);
- if (isset($columnData_ss['Index'])) {
- $columnID = PHPExcel_Cell::stringFromColumnIndex($columnData_ss['Index']-1);
- }
- if (isset($columnData_ss['Width'])) {
- $columnWidth = $columnData_ss['Width'];
-// echo 'Setting column width for '.$columnID.' to '.$columnWidth.'
';
- $objPHPExcel->getActiveSheet()->getColumnDimension($columnID)->setWidth($columnWidth / 5.4);
- }
- ++$columnID;
- }
-
- $rowID = 1;
- foreach($worksheet->Table->Row as $rowData) {
- $rowHasData = false;
- $row_ss = $rowData->attributes($namespaces['ss']);
- if (isset($row_ss['Index'])) {
- $rowID = (integer) $row_ss['Index'];
- }
-// echo 'Row '.$rowID.'
';
-
- $columnID = 'A';
- foreach($rowData->Cell as $cell) {
-
- $cell_ss = $cell->attributes($namespaces['ss']);
- if (isset($cell_ss['Index'])) {
- $columnID = PHPExcel_Cell::stringFromColumnIndex($cell_ss['Index']-1);
+ if (isset($worksheet->Table->Column)) {
+ foreach($worksheet->Table->Column as $columnData) {
+ $columnData_ss = $columnData->attributes($namespaces['ss']);
+ if (isset($columnData_ss['Index'])) {
+ $columnID = PHPExcel_Cell::stringFromColumnIndex($columnData_ss['Index']-1);
}
- $cellRange = $columnID.$rowID;
-
- if (!is_null($this->getReadFilter())) {
- if (!$this->getReadFilter()->readCell($columnID, $rowID, $worksheetName)) {
- continue;
- }
- }
-
- if ((isset($cell_ss['MergeAcross'])) || (isset($cell_ss['MergeDown']))) {
- $columnTo = $columnID;
- if (isset($cell_ss['MergeAcross'])) {
- $columnTo = PHPExcel_Cell::stringFromColumnIndex(PHPExcel_Cell::columnIndexFromString($columnID) + $cell_ss['MergeAcross'] -1);
- }
- $rowTo = $rowID;
- if (isset($cell_ss['MergeDown'])) {
- $rowTo = $rowTo + $cell_ss['MergeDown'];
- }
- $cellRange .= ':'.$columnTo.$rowTo;
- $objPHPExcel->getActiveSheet()->mergeCells($cellRange);
- }
-
- $cellIsSet = $hasCalculatedValue = false;
- $cellDataFormula = '';
- if (isset($cell_ss['Formula'])) {
- $cellDataFormula = $cell_ss['Formula'];
- // added this as a check for array formulas
- if (isset($cell_ss['ArrayRange'])) {
- $cellDataCSEFormula = $cell_ss['ArrayRange'];
-// echo "found an array formula at ".$columnID.$rowID."
";
- }
- $hasCalculatedValue = true;
- }
- if (isset($cell->Data)) {
- $cellValue = $cellData = $cell->Data;
- $type = PHPExcel_Cell_DataType::TYPE_NULL;
- $cellData_ss = $cellData->attributes($namespaces['ss']);
- if (isset($cellData_ss['Type'])) {
- $cellDataType = $cellData_ss['Type'];
- switch ($cellDataType) {
- /*
- const TYPE_STRING = 's';
- const TYPE_FORMULA = 'f';
- const TYPE_NUMERIC = 'n';
- const TYPE_BOOL = 'b';
- const TYPE_NULL = 's';
- const TYPE_INLINE = 'inlineStr';
- const TYPE_ERROR = 'e';
- */
- case 'String' :
- $type = PHPExcel_Cell_DataType::TYPE_STRING;
- break;
- case 'Number' :
- $type = PHPExcel_Cell_DataType::TYPE_NUMERIC;
- $cellValue = (float) $cellValue;
- if (floor($cellValue) == $cellValue) {
- $cellValue = (integer) $cellValue;
- }
- break;
- case 'Boolean' :
- $type = PHPExcel_Cell_DataType::TYPE_BOOL;
- $cellValue = ($cellValue != 0);
- break;
- case 'DateTime' :
- $type = PHPExcel_Cell_DataType::TYPE_NUMERIC;
- $cellValue = PHPExcel_Shared_Date::PHPToExcel(strtotime($cellValue));
- break;
- case 'Error' :
- $type = PHPExcel_Cell_DataType::TYPE_ERROR;
- break;
- }
- }
- if ($hasCalculatedValue) {
- $type = PHPExcel_Cell_DataType::TYPE_FORMULA;
- $columnNumber = PHPExcel_Cell::columnIndexFromString($columnID);
- // Convert R1C1 style references to A1 style references (but only when not quoted)
- $temp = explode('"',$cellDataFormula);
- foreach($temp as $key => &$value) {
- // Only replace in alternate array entries (i.e. non-quoted blocks)
- if (($key % 2) == 0) {
- preg_match_all('/(R(\[?-?\d*\]?))(C(\[?-?\d*\]?))/',$value, $cellReferences,PREG_SET_ORDER+PREG_OFFSET_CAPTURE);
- // Reverse the matches array, otherwise all our offsets will become incorrect if we modify our way
- // through the formula from left to right. Reversing means that we work right to left.through
- // the formula
- $cellReferences = array_reverse($cellReferences);
- // Loop through each R1C1 style reference in turn, converting it to its A1 style equivalent,
- // then modify the formula to use that new reference
- foreach($cellReferences as $cellReference) {
- $rowReference = $cellReference[2][0];
- // Empty R reference is the current row
- if ($rowReference == '') $rowReference = $rowID;
- // Bracketed R references are relative to the current row
- if ($rowReference{0} == '[') $rowReference = $rowID + trim($rowReference,'[]');
- $columnReference = $cellReference[4][0];
- // Empty C reference is the current column
- if ($columnReference == '') $columnReference = $columnNumber;
- // Bracketed C references are relative to the current column
- if ($columnReference{0} == '[') $columnReference = $columnNumber + trim($columnReference,'[]');
- $A1CellReference = PHPExcel_Cell::stringFromColumnIndex($columnReference-1).$rowReference;
- $value = substr_replace($value,$A1CellReference,$cellReference[0][1],strlen($cellReference[0][0]));
- }
- }
- }
- unset($value);
- // Then rebuild the formula string
- $cellDataFormula = implode('"',$temp);
- }
-
-// echo 'Cell '.$columnID.$rowID.' is a '.$type.' with a value of '.(($hasCalculatedValue) ? $cellDataFormula : $cellValue).'
';
-//
- $objPHPExcel->getActiveSheet()->getCell($columnID.$rowID)->setValueExplicit((($hasCalculatedValue) ? $cellDataFormula : $cellValue),$type);
- if ($hasCalculatedValue) {
-// echo 'Formula result is '.$cellValue.'
';
- $objPHPExcel->getActiveSheet()->getCell($columnID.$rowID)->setCalculatedValue($cellValue);
- }
- $cellIsSet = $rowHasData = true;
- }
-
- if (($cellIsSet) && (isset($cell_ss['StyleID']))) {
- $style = (string) $cell_ss['StyleID'];
-// echo 'Cell style for '.$columnID.$rowID.' is '.$style.'
';
- if ((isset($this->_styles[$style])) && (count($this->_styles[$style]) > 0)) {
-// echo 'Cell '.$columnID.$rowID.'
';
-// print_r($this->_styles[$style]);
-// echo '
';
- if (!$objPHPExcel->getActiveSheet()->cellExists($columnID.$rowID)) {
- $objPHPExcel->getActiveSheet()->getCell($columnID.$rowID)->setValue(NULL);
- }
- $objPHPExcel->getActiveSheet()->getStyle($cellRange)->applyFromArray($this->_styles[$style]);
- }
+ if (isset($columnData_ss['Width'])) {
+ $columnWidth = $columnData_ss['Width'];
+// echo 'Setting column width for '.$columnID.' to '.$columnWidth.'
';
+ $objPHPExcel->getActiveSheet()->getColumnDimension($columnID)->setWidth($columnWidth / 5.4);
}
++$columnID;
}
+ }
- if ($rowHasData) {
- if (isset($row_ss['StyleID'])) {
- $rowStyle = $row_ss['StyleID'];
+ $rowID = 1;
+ if (isset($worksheet->Table->Row)) {
+ foreach($worksheet->Table->Row as $rowData) {
+ $rowHasData = false;
+ $row_ss = $rowData->attributes($namespaces['ss']);
+ if (isset($row_ss['Index'])) {
+ $rowID = (integer) $row_ss['Index'];
}
- if (isset($row_ss['Height'])) {
- $rowHeight = $row_ss['Height'];
-// echo 'Setting row height to '.$rowHeight.'
';
- $objPHPExcel->getActiveSheet()->getRowDimension($rowID)->setRowHeight($rowHeight);
+// echo 'Row '.$rowID.'
';
+
+ $columnID = 'A';
+ foreach($rowData->Cell as $cell) {
+
+ $cell_ss = $cell->attributes($namespaces['ss']);
+ if (isset($cell_ss['Index'])) {
+ $columnID = PHPExcel_Cell::stringFromColumnIndex($cell_ss['Index']-1);
+ }
+ $cellRange = $columnID.$rowID;
+
+ if (!is_null($this->getReadFilter())) {
+ if (!$this->getReadFilter()->readCell($columnID, $rowID, $worksheetName)) {
+ continue;
+ }
+ }
+
+ if ((isset($cell_ss['MergeAcross'])) || (isset($cell_ss['MergeDown']))) {
+ $columnTo = $columnID;
+ if (isset($cell_ss['MergeAcross'])) {
+ $columnTo = PHPExcel_Cell::stringFromColumnIndex(PHPExcel_Cell::columnIndexFromString($columnID) + $cell_ss['MergeAcross'] -1);
+ }
+ $rowTo = $rowID;
+ if (isset($cell_ss['MergeDown'])) {
+ $rowTo = $rowTo + $cell_ss['MergeDown'];
+ }
+ $cellRange .= ':'.$columnTo.$rowTo;
+ $objPHPExcel->getActiveSheet()->mergeCells($cellRange);
+ }
+
+ $cellIsSet = $hasCalculatedValue = false;
+ $cellDataFormula = '';
+ if (isset($cell_ss['Formula'])) {
+ $cellDataFormula = $cell_ss['Formula'];
+ // added this as a check for array formulas
+ if (isset($cell_ss['ArrayRange'])) {
+ $cellDataCSEFormula = $cell_ss['ArrayRange'];
+// echo "found an array formula at ".$columnID.$rowID."
";
+ }
+ $hasCalculatedValue = true;
+ }
+ if (isset($cell->Data)) {
+ $cellValue = $cellData = $cell->Data;
+ $type = PHPExcel_Cell_DataType::TYPE_NULL;
+ $cellData_ss = $cellData->attributes($namespaces['ss']);
+ if (isset($cellData_ss['Type'])) {
+ $cellDataType = $cellData_ss['Type'];
+ switch ($cellDataType) {
+ /*
+ const TYPE_STRING = 's';
+ const TYPE_FORMULA = 'f';
+ const TYPE_NUMERIC = 'n';
+ const TYPE_BOOL = 'b';
+ const TYPE_NULL = 's';
+ const TYPE_INLINE = 'inlineStr';
+ const TYPE_ERROR = 'e';
+ */
+ case 'String' :
+ $type = PHPExcel_Cell_DataType::TYPE_STRING;
+ break;
+ case 'Number' :
+ $type = PHPExcel_Cell_DataType::TYPE_NUMERIC;
+ $cellValue = (float) $cellValue;
+ if (floor($cellValue) == $cellValue) {
+ $cellValue = (integer) $cellValue;
+ }
+ break;
+ case 'Boolean' :
+ $type = PHPExcel_Cell_DataType::TYPE_BOOL;
+ $cellValue = ($cellValue != 0);
+ break;
+ case 'DateTime' :
+ $type = PHPExcel_Cell_DataType::TYPE_NUMERIC;
+ $cellValue = PHPExcel_Shared_Date::PHPToExcel(strtotime($cellValue));
+ break;
+ case 'Error' :
+ $type = PHPExcel_Cell_DataType::TYPE_ERROR;
+ break;
+ }
+ }
+
+ if ($hasCalculatedValue) {
+ $type = PHPExcel_Cell_DataType::TYPE_FORMULA;
+ $columnNumber = PHPExcel_Cell::columnIndexFromString($columnID);
+ // Convert R1C1 style references to A1 style references (but only when not quoted)
+ $temp = explode('"',$cellDataFormula);
+ foreach($temp as $key => &$value) {
+ // Only replace in alternate array entries (i.e. non-quoted blocks)
+ if (($key % 2) == 0) {
+ preg_match_all('/(R(\[?-?\d*\]?))(C(\[?-?\d*\]?))/',$value, $cellReferences,PREG_SET_ORDER+PREG_OFFSET_CAPTURE);
+ // Reverse the matches array, otherwise all our offsets will become incorrect if we modify our way
+ // through the formula from left to right. Reversing means that we work right to left.through
+ // the formula
+ $cellReferences = array_reverse($cellReferences);
+ // Loop through each R1C1 style reference in turn, converting it to its A1 style equivalent,
+ // then modify the formula to use that new reference
+ foreach($cellReferences as $cellReference) {
+ $rowReference = $cellReference[2][0];
+ // Empty R reference is the current row
+ if ($rowReference == '') $rowReference = $rowID;
+ // Bracketed R references are relative to the current row
+ if ($rowReference{0} == '[') $rowReference = $rowID + trim($rowReference,'[]');
+ $columnReference = $cellReference[4][0];
+ // Empty C reference is the current column
+ if ($columnReference == '') $columnReference = $columnNumber;
+ // Bracketed C references are relative to the current column
+ if ($columnReference{0} == '[') $columnReference = $columnNumber + trim($columnReference,'[]');
+ $A1CellReference = PHPExcel_Cell::stringFromColumnIndex($columnReference-1).$rowReference;
+ $value = substr_replace($value,$A1CellReference,$cellReference[0][1],strlen($cellReference[0][0]));
+ }
+ }
+ }
+ unset($value);
+ // Then rebuild the formula string
+ $cellDataFormula = implode('"',$temp);
+ }
+
+// echo 'Cell '.$columnID.$rowID.' is a '.$type.' with a value of '.(($hasCalculatedValue) ? $cellDataFormula : $cellValue).'
';
+//
+ $objPHPExcel->getActiveSheet()->getCell($columnID.$rowID)->setValueExplicit((($hasCalculatedValue) ? $cellDataFormula : $cellValue),$type);
+ if ($hasCalculatedValue) {
+// echo 'Formula result is '.$cellValue.'
';
+ $objPHPExcel->getActiveSheet()->getCell($columnID.$rowID)->setCalculatedValue($cellValue);
+ }
+ $cellIsSet = $rowHasData = true;
+ }
+
+ if (isset($cell->Comment)) {
+// echo 'comment found
';
+ $commentAttributes = $cell->Comment->attributes($namespaces['ss']);
+ $author = 'unknown';
+ if (isset($commentAttributes->Author)) {
+ $author = (string)$commentAttributes->Author;
+// echo 'Author: ',$author,'
';
+ }
+ $node = $cell->Comment->Data->asXML();
+// $annotation = str_replace('html:','',substr($node,49,-10));
+// echo $annotation,'
';
+ $annotation = strip_tags($node);
+// echo 'Annotation: ',$annotation,'
';
+ $objPHPExcel->getActiveSheet()->getComment( $columnID.$rowID )
+ ->setAuthor( $author )
+ ->setText($this->_parseRichText($annotation) );
+ }
+
+ if (($cellIsSet) && (isset($cell_ss['StyleID']))) {
+ $style = (string) $cell_ss['StyleID'];
+// echo 'Cell style for '.$columnID.$rowID.' is '.$style.'
';
+ if ((isset($this->_styles[$style])) && (count($this->_styles[$style]) > 0)) {
+// echo 'Cell '.$columnID.$rowID.'
';
+// print_r($this->_styles[$style]);
+// echo '
';
+ if (!$objPHPExcel->getActiveSheet()->cellExists($columnID.$rowID)) {
+ $objPHPExcel->getActiveSheet()->getCell($columnID.$rowID)->setValue(NULL);
+ }
+ $objPHPExcel->getActiveSheet()->getStyle($cellRange)->applyFromArray($this->_styles[$style]);
+ }
+ }
+ ++$columnID;
}
+
+ if ($rowHasData) {
+ if (isset($row_ss['StyleID'])) {
+ $rowStyle = $row_ss['StyleID'];
+ }
+ if (isset($row_ss['Height'])) {
+ $rowHeight = $row_ss['Height'];
+// echo 'Setting row height to '.$rowHeight.'
';
+ $objPHPExcel->getActiveSheet()->getRowDimension($rowID)->setRowHeight($rowHeight);
+ }
+ }
+
+ ++$rowID;
}
-
- ++$rowID;
}
++$worksheetID;
}
@@ -736,4 +759,12 @@ class PHPExcel_Reader_Excel2003XML implements PHPExcel_Reader_IReader
return $objPHPExcel;
}
+ private function _parseRichText($is = '') {
+ $value = new PHPExcel_RichText();
+
+ $value->createText($is);
+
+ return $value;
+ }
+
}
diff --git a/Classes/PHPExcel/Reader/Gnumeric.php b/Classes/PHPExcel/Reader/Gnumeric.php
index be637bf2..275b770d 100644
--- a/Classes/PHPExcel/Reader/Gnumeric.php
+++ b/Classes/PHPExcel/Reader/Gnumeric.php
@@ -406,6 +406,7 @@ class PHPExcel_Reader_Gnumeric implements PHPExcel_Reader_IReader
if (isset($sheet->PrintInformation->Margins)) {
foreach($sheet->PrintInformation->Margins->children('gnm',TRUE) as $key => $margin) {
$marginAttributes = $margin->attributes();
+ $marginSize = 72 / 100; // Default
switch($marginAttributes['PrefUnit']) {
case 'mm' :
$marginSize = intval($marginAttributes['Points']) / 100;
@@ -506,6 +507,14 @@ class PHPExcel_Reader_Gnumeric implements PHPExcel_Reader_IReader
$objPHPExcel->getActiveSheet()->getCell($column.$row)->setValueExplicit($cell,$type);
}
+ if ((!$this->_readDataOnly) && (isset($sheet->Objects))) {
+ foreach($sheet->Objects->children('gnm',TRUE) as $key => $comment) {
+ $commentAttributes = $comment->attributes();
+ $objPHPExcel->getActiveSheet()->getComment( (string)$commentAttributes->ObjectBound )
+ ->setAuthor( (string)$commentAttributes->Author )
+ ->setText($this->_parseRichText((string)$commentAttributes->Text) );
+ }
+ }
// echo '$maxCol=',$maxCol,'; $maxRow=',$maxRow,'
';
//
foreach($sheet->Styles->StyleRegion as $styleRegion) {
@@ -867,6 +876,14 @@ class PHPExcel_Reader_Gnumeric implements PHPExcel_Reader_IReader
return $styleArray;
}
+ private function _parseRichText($is = '') {
+ $value = new PHPExcel_RichText();
+
+ $value->createText($is);
+
+ return $value;
+ }
+
private static function _parseGnumericColour($gnmColour) {
list($gnmR,$gnmG,$gnmB) = explode(':',$gnmColour);
$gnmR = substr(str_pad($gnmR,4,'0',STR_PAD_RIGHT),0,2);
diff --git a/Classes/PHPExcel/Style.php b/Classes/PHPExcel/Style.php
index 53604453..3b340363 100644
--- a/Classes/PHPExcel/Style.php
+++ b/Classes/PHPExcel/Style.php
@@ -632,13 +632,13 @@ class PHPExcel_Style implements PHPExcel_IComparable
}
return md5(
- $this->getFill()->getHashCode()
- . $this->getFont()->getHashCode()
- . $this->getBorders()->getHashCode()
- . $this->getAlignment()->getHashCode()
- . $this->getNumberFormat()->getHashCode()
+ $this->_fill->getHashCode()
+ . $this->_font->getHashCode()
+ . $this->_borders->getHashCode()
+ . $this->_alignment->getHashCode()
+ . $this->_numberFormat->getHashCode()
. $hashConditionals
- . $this->getProtection()->getHashCode()
+ . $this->_protection->getHashCode()
. __CLASS__
);
}
diff --git a/Documentation/Functionality Cross-Reference.xls b/Documentation/Functionality Cross-Reference.xls
index a4159388..3270fb5e 100644
Binary files a/Documentation/Functionality Cross-Reference.xls and b/Documentation/Functionality Cross-Reference.xls differ
diff --git a/changelog.txt b/changelog.txt
index e5eae9ec..4ffc5522 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -26,11 +26,14 @@
Fixed in SVN:
- Feature: (MBaker) Provide option to use PCLZip as an alternative to ZipArchive.
This allows the writing of Excel2007 files, even without ZipArchive enabled (it does require zlib), or when php_zip is one of the buggy PHP 5.2.6 or 5.2.8 versions
+ It can be enabled using PHPExcel_Settings::setZipClass(PHPExcel_Settings::PCLZIP);
+ Note that it is not yet implemented as an alternative to ZipArchive for those Readers that are extracting from zips
- Feature: (MBaker) Work item 14979 - Added listWorksheetNames() method to Readers that support multiple worksheets in a workbook, allowing a user to extract a list of all the worksheet names from a file without parsing/loading the whole file.
- Feature: (MBaker) Speed boost and memory reduction in the Worksheet toArray() method.
- Feature: (MBaker) Added new rangeToArray() and namedRangeToArray() methods to the PHPExcel_Worksheet object.
Functionally, these are identical to the toArray() method, except that they take an additional first parameter of a Range (e.g. 'B2:C3') or a Named Range name.
Modified the toArray() method so that it actually uses rangeToArray().
+- Feature: (MBaker) Added support for cell comments in the Gnumeric and Excel2003XML Readers
- Bugfix: (MBaker) Work item 14888 - Simple =IF() formula disappears
- Bugfix: (MBaker) Work item 14898 - PHP Warning: preg_match(): Compilation failed: PCRE does not support \\L, \\l, \\N, \\P, \\p, \\U, \\u, or \\X
- Bugfix: (MBaker) Work item 14901 - VLOOKUP choking on parameters in PHPExcel.1.7.5/PHPExcel_Writer_Excel2007