Feature: Support for Extended Workbook Properties in Excel2007, Excel5 and OOCalc Readers;

Feature: Support for User-defined Workbook Properties in Excel2007 and OOCalc Readers

git-svn-id: https://phpexcel.svn.codeplex.com/svn/trunk@60080 2327b42d-5241-43d6-9e2a-de5ac946f064
This commit is contained in:
Mark Baker 2010-08-30 09:09:12 +00:00
parent 4e8a57e369
commit 492cc4fb27
5 changed files with 324 additions and 32 deletions

View File

@ -345,8 +345,19 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader
case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/custom-properties": case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/custom-properties":
$xmlCore = simplexml_load_string($this->_getFromZipArchive($zip, "{$rel['Target']}")); $xmlCore = simplexml_load_string($this->_getFromZipArchive($zip, "{$rel['Target']}"));
if (is_object($xmlCore)) { if (is_object($xmlCore)) {
$xmlCore->registerXPathNamespace("vt", "http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes");
$docProps = $excel->getProperties(); $docProps = $excel->getProperties();
foreach ($xmlCore as $xmlProperty) {
$cellDataOfficeAttributes = $xmlProperty->attributes();
if (isset($cellDataOfficeAttributes['name'])) {
$propertyName = (string) $cellDataOfficeAttributes['name'];
$cellDataOfficeChildren = $xmlProperty->children('http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes');
$attributeType = $cellDataOfficeChildren->getName();
$attributeValue = (string) $cellDataOfficeChildren->{$attributeType};
$attributeValue = PHPExcel_DocumentProperties::convertProperty($attributeValue,$attributeType);
$attributeType = PHPExcel_DocumentProperties::convertPropertyType($attributeType);
$docProps->setCustomProperty($propertyName,$attributeValue,$attributeType);
}
}
} }
break; break;

View File

@ -192,6 +192,13 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader
*/ */
private $_summaryInformation; private $_summaryInformation;
/**
* Extended Summary Information stream data.
*
* @var string
*/
private $_documentSummaryInformation;
/** /**
* Workbook stream data. (Includes workbook globals substream as well as sheet substreams) * Workbook stream data. (Includes workbook globals substream as well as sheet substreams)
* *
@ -508,6 +515,9 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader
// Read the summary information stream (containing meta data) // Read the summary information stream (containing meta data)
$this->_readSummaryInformation(); $this->_readSummaryInformation();
// Read the Additional document summary information stream (containing application-specific meta data)
$this->_readDocumentSummaryInformation();
// total byte size of Excel data (workbook global substream + sheet substreams) // total byte size of Excel data (workbook global substream + sheet substreams)
$this->_dataSize = strlen($this->_data); $this->_dataSize = strlen($this->_data);
@ -930,6 +940,9 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader
// Get summary information data // Get summary information data
$this->_summaryInformation = $ole->getSummaryInformation(); $this->_summaryInformation = $ole->getSummaryInformation();
// Get additional document summary information data
$this->_documentSummaryInformation = $ole->getDocumentSummaryInformation();
} }
/** /**
@ -947,31 +960,34 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader
// offset: 6; size: 2; OS indicator // offset: 6; size: 2; OS indicator
// offset: 8; size: 16 // offset: 8; size: 16
// offset: 24; size: 4; section count // offset: 24; size: 4; section count
$secCount = $this->_GetInt4d($this->_documentSummaryInformation, 24);
// offset: 28; size: 16; first section's class id: e0 85 9f f2 f9 4f 68 10 ab 91 08 00 2b 27 b3 d9 // offset: 28; size: 16; first section's class id: e0 85 9f f2 f9 4f 68 10 ab 91 08 00 2b 27 b3 d9
// offset: 44; size: 4 // offset: 44; size: 4
$secOffset = $this->_GetInt4d($this->_summaryInformation, 44);
// section header // section header
// offset: 48; size: 4; section length // offset: $secOffset; size: 4; section length
$secLength = $this->_GetInt4d($this->_summaryInformation, 48); $secLength = $this->_GetInt4d($this->_summaryInformation, $secOffset);
// offset: 52; size: 4; property count // offset: $secOffset+4; size: 4; property count
$countProperties = $this->_GetInt4d($this->_summaryInformation, 52); $countProperties = $this->_GetInt4d($this->_summaryInformation, $secOffset+4);
// initialize code page (used to resolve string values) // initialize code page (used to resolve string values)
$codePage = 'CP1252'; $codePage = 'CP1252';
// offset: 56; size: var // offset: ($secOffset+8); size: var
// loop through property decarations and properties // loop through property decarations and properties
for ($i = 0; $i < $countProperties; ++$i) { for ($i = 0; $i < $countProperties; ++$i) {
// offset: 56 + 8 * $i; size: 4; property ID // offset: ($secOffset+8) + (8 * $i); size: 4; property ID
$id = $this->_GetInt4d($this->_summaryInformation, 56 + 8 * $i); $id = $this->_GetInt4d($this->_summaryInformation, ($secOffset+8) + (8 * $i));
// offset: 60 + 8 * $i; size: 4; offset from beginning of section (48) // Use value of property id as appropriate
$offset = $this->_GetInt4d($this->_summaryInformation, 60 + 8 * $i); // offset: ($secOffset+12) + (8 * $i); size: 4; offset from beginning of section (48)
$offset = $this->_GetInt4d($this->_summaryInformation, ($secOffset+12) + (8 * $i));
$type = $this->_GetInt4d($this->_summaryInformation, 48 + $offset); $type = $this->_GetInt4d($this->_summaryInformation, $secOffset + $offset);
// initialize property value // initialize property value
$value = null; $value = null;
@ -979,11 +995,11 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader
// extract property value based on property type // extract property value based on property type
switch ($type) { switch ($type) {
case 0x02: // 2 byte signed integer case 0x02: // 2 byte signed integer
$value = $this->_GetInt2d($this->_summaryInformation, 52 + $offset); $value = $this->_GetInt2d($this->_summaryInformation, $secOffset + 4 + $offset);
break; break;
case 0x03: // 4 byte signed integer case 0x03: // 4 byte signed integer
$value = $this->_GetInt4d($this->_summaryInformation, 52 + $offset); $value = $this->_GetInt4d($this->_summaryInformation, $secOffset + 4 + $offset);
break; break;
case 0x13: // 4 byte unsigned integer case 0x13: // 4 byte unsigned integer
@ -991,15 +1007,15 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader
break; break;
case 0x1E: // null-terminated string prepended by dword string length case 0x1E: // null-terminated string prepended by dword string length
$byteLength = $this->_GetInt4d($this->_summaryInformation, 52 + $offset); $byteLength = $this->_GetInt4d($this->_summaryInformation, $secOffset + 4 + $offset);
$value = substr($this->_summaryInformation, 56 + $offset, $byteLength); $value = substr($this->_summaryInformation, $secOffset + 8 + $offset, $byteLength);
$value = PHPExcel_Shared_String::ConvertEncoding($value, 'UTF-8', $codePage); $value = PHPExcel_Shared_String::ConvertEncoding($value, 'UTF-8', $codePage);
$value = rtrim($value); $value = rtrim($value);
break; break;
case 0x40: // Filetime (64-bit value representing the number of 100-nanosecond intervals since January 1, 1601) case 0x40: // Filetime (64-bit value representing the number of 100-nanosecond intervals since January 1, 1601)
// PHP-time // PHP-time
$value = PHPExcel_Shared_OLE::OLE2LocalDate(substr($this->_summaryInformation, 52 + $offset, 8)); $value = PHPExcel_Shared_OLE::OLE2LocalDate(substr($this->_summaryInformation, $secOffset + 4 + $offset, 8));
break; break;
case 0x47: // Clipboard format case 0x47: // Clipboard format
@ -1007,51 +1023,225 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader
break; break;
} }
// Use value of property id as appropriate
switch ($id) { switch ($id) {
case 0x01: // Code Page case 0x01: // Code Page
$codePage = PHPExcel_Shared_CodePage::NumberToName($value); $codePage = PHPExcel_Shared_CodePage::NumberToName($value);
break; break;
case 0x02: // Title case 0x02: // Title
$this->_phpExcel->getProperties()->setTitle($value); $this->_phpExcel->getProperties()->setTitle($value);
break; break;
case 0x03: // Subject case 0x03: // Subject
$this->_phpExcel->getProperties()->setSubject($value); $this->_phpExcel->getProperties()->setSubject($value);
break; break;
case 0x04: // Author (Creator) case 0x04: // Author (Creator)
$this->_phpExcel->getProperties()->setCreator($value); $this->_phpExcel->getProperties()->setCreator($value);
break; break;
case 0x05: // Keywords case 0x05: // Keywords
$this->_phpExcel->getProperties()->setKeywords($value); $this->_phpExcel->getProperties()->setKeywords($value);
break; break;
case 0x06: // Comments (Description) case 0x06: // Comments (Description)
$this->_phpExcel->getProperties()->setDescription($value); $this->_phpExcel->getProperties()->setDescription($value);
break; break;
case 0x08: // Last Saved By (LastModifiedBy) case 0x07: // Template
// Not supported by PHPExcel
break;
case 0x08: // Last Saved By (LastModifiedBy)
$this->_phpExcel->getProperties()->setLastModifiedBy($value); $this->_phpExcel->getProperties()->setLastModifiedBy($value);
break; break;
case 0x09: // Revision case 0x09: // Revision
// not supported by PHPExcel // Not supported by PHPExcel
break; break;
case 0x0C: // Created case 0x0A: // Total Editing Time
// Not supported by PHPExcel
break;
case 0x0B: // Last Printed
// Not supported by PHPExcel
break;
case 0x0C: // Created Date/Time
$this->_phpExcel->getProperties()->setCreated($value); $this->_phpExcel->getProperties()->setCreated($value);
break; break;
case 0x0D: // Modified case 0x0D: // Modified Date/Time
$this->_phpExcel->getProperties()->setModified($value); $this->_phpExcel->getProperties()->setModified($value);
break; break;
case 0x12: // Name of creating application case 0x0E: // Number of Pages
// not supported by PHPExcel // Not supported by PHPExcel
break; break;
case 0x0F: // Number of Words
// Not supported by PHPExcel
break;
case 0x10: // Number of Characters
// Not supported by PHPExcel
break;
case 0x11: // Thumbnail
// Not supported by PHPExcel
break;
case 0x12: // Name of creating application
// Not supported by PHPExcel
break;
case 0x13: // Security
// Not supported by PHPExcel
break;
}
}
}
/**
* Read additional document summary information
*/
private function _readDocumentSummaryInformation()
{
if (!isset($this->_documentSummaryInformation)) {
return;
}
// offset: 0; size: 2; must be 0xFE 0xFF (UTF-16 LE byte order mark)
// offset: 2; size: 2;
// offset: 4; size: 2; OS version
// offset: 6; size: 2; OS indicator
// offset: 8; size: 16
// offset: 24; size: 4; section count
$secCount = $this->_GetInt4d($this->_documentSummaryInformation, 24);
// offset: 28; size: 16; first section's class id: 02 d5 cd d5 9c 2e 1b 10 93 97 08 00 2b 2c f9 ae
// offset: 44; size: 4; first section offset
$secOffset = $this->_GetInt4d($this->_documentSummaryInformation, 44);
// section header
// offset: $secOffset; size: 4; section length
$secLength = $this->_GetInt4d($this->_documentSummaryInformation, $secOffset);
// offset: $secOffset+4; size: 4; property count
$countProperties = $this->_GetInt4d($this->_documentSummaryInformation, $secOffset+4);
// initialize code page (used to resolve string values)
$codePage = 'CP1252';
// offset: ($secOffset+8); size: var
// loop through property decarations and properties
for ($i = 0; $i < $countProperties; ++$i) {
// offset: ($secOffset+8) + (8 * $i); size: 4; property ID
$id = $this->_GetInt4d($this->_documentSummaryInformation, ($secOffset+8) + (8 * $i));
// Use value of property id as appropriate
// offset: 60 + 8 * $i; size: 4; offset from beginning of section (48)
$offset = $this->_GetInt4d($this->_documentSummaryInformation, ($secOffset+12) + (8 * $i));
$type = $this->_GetInt4d($this->_documentSummaryInformation, $secOffset + $offset);
// initialize property value
$value = null;
// extract property value based on property type
switch ($type) {
case 0x02: // 2 byte signed integer
$value = $this->_GetInt2d($this->_documentSummaryInformation, $secOffset + 4 + $offset);
break;
case 0x03: // 4 byte signed integer
$value = $this->_GetInt4d($this->_documentSummaryInformation, $secOffset + 4 + $offset);
break;
case 0x13: // 4 byte unsigned integer
// not needed yet, fix later if necessary
break;
case 0x1E: // null-terminated string prepended by dword string length
$byteLength = $this->_GetInt4d($this->_documentSummaryInformation, $secOffset + 4 + $offset);
$value = substr($this->_documentSummaryInformation, $secOffset + 8 + $offset, $byteLength);
$value = PHPExcel_Shared_String::ConvertEncoding($value, 'UTF-8', $codePage);
$value = rtrim($value);
break;
case 0x40: // Filetime (64-bit value representing the number of 100-nanosecond intervals since January 1, 1601)
// PHP-Time
$value = PHPExcel_Shared_OLE::OLE2LocalDate(substr($this->_documentSummaryInformation, $secOffset + 4 + $offset, 8));
break;
case 0x47: // Clipboard format
// not needed yet, fix later if necessary
break;
}
switch ($id) {
case 0x02: // Category
$this->_phpExcel->getProperties()->setCategory($value);
break;
case 0x03: // Presentation Target
// Not supported by PHPExcel
break;
case 0x04: // Bytes
// Not supported by PHPExcel
break;
case 0x05: // Lines
// Not supported by PHPExcel
break;
case 0x06: // Paragraphs
// Not supported by PHPExcel
break;
case 0x07: // Slides
// Not supported by PHPExcel
break;
case 0x08: // Notes
// Not supported by PHPExcel
break;
case 0x09: // Hidden Slides
// Not supported by PHPExcel
break;
case 0x0A: // MM Clips
// Not supported by PHPExcel
break;
case 0x0B: // Scale Crop
// Not supported by PHPExcel
break;
case 0x0C: // Heading Pairs
// Not supported by PHPExcel
break;
case 0x0D: // Titles of Parts
// Not supported by PHPExcel
break;
case 0x0E: // Manager
$this->_phpExcel->getProperties()->setManager($value);
break;
case 0x0F: // Company
$this->_phpExcel->getProperties()->setCompany($value);
break;
case 0x10: // Links up-to-date
// Not supported by PHPExcel
break;
} }
} }
} }
@ -6182,3 +6372,4 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader
} }
} }

View File

@ -297,9 +297,42 @@ class PHPExcel_Reader_OOCalc implements PHPExcel_Reader_IReader
// echo '<hr />'; // echo '<hr />';
// //
switch ($propertyName) { switch ($propertyName) {
case 'initial-creator' :
$docProps->setCreator($propertyValue);
break;
case 'keyword' : case 'keyword' :
$docProps->setKeywords($propertyValue); $docProps->setKeywords($propertyValue);
break; break;
case 'creation-date' :
$creationDate = strtotime($propertyValue);
$docProps->setCreated($creationDate);
break;
case 'user-defined' :
$propertyValueType = PHPExcel_DocumentProperties::PROPERTY_TYPE_STRING;
foreach ($propertyValueAttributes as $key => $value) {
if ($key == 'name') {
$propertyValueName = (string) $value;
} elseif($key == 'value-type') {
switch ($value) {
case 'date' :
$propertyValue = PHPExcel_DocumentProperties::convertProperty($propertyValue,'date');
$propertyValueType = PHPExcel_DocumentProperties::PROPERTY_TYPE_DATE;
break;
case 'boolean' :
$propertyValue = PHPExcel_DocumentProperties::convertProperty($propertyValue,'bool');
$propertyValueType = PHPExcel_DocumentProperties::PROPERTY_TYPE_BOOLEAN;
break;
case 'float' :
$propertyValue = PHPExcel_DocumentProperties::convertProperty($propertyValue,'r4');
$propertyValueType = PHPExcel_DocumentProperties::PROPERTY_TYPE_FLOAT;
break;
default :
$propertyValueType = PHPExcel_DocumentProperties::PROPERTY_TYPE_STRING;
}
}
}
$docProps->setCustomProperty($propertyValueName,$propertyValue,$propertyValueType);
break;
} }
} }
} }

View File

@ -264,6 +264,58 @@ class PHPExcel_Shared_OLERead {
} }
} }
/**
* Extract binary stream data, additional document summary information
*
* @return string|null
*/
public function getDocumentSummaryInformation()
{
if (!isset($this->documentSummaryInformation)) {
return null;
}
if ($this->props[$this->documentSummaryInformation]['size'] < self::SMALL_BLOCK_THRESHOLD){
$rootdata = $this->_readData($this->props[$this->rootentry]['startBlock']);
$streamData = '';
$block = $this->props[$this->documentSummaryInformation]['startBlock'];
$pos = 0;
while ($block != -2) {
$pos = $block * self::SMALL_BLOCK_SIZE;
$streamData .= substr($rootdata, $pos, self::SMALL_BLOCK_SIZE);
$block = $this->smallBlockChain[$block];
}
return $streamData;
} else {
$numBlocks = $this->props[$this->documentSummaryInformation]['size'] / self::BIG_BLOCK_SIZE;
if ($this->props[$this->documentSummaryInformation]['size'] % self::BIG_BLOCK_SIZE != 0) {
++$numBlocks;
}
if ($numBlocks == 0) return '';
$streamData = '';
$block = $this->props[$this->documentSummaryInformation]['startBlock'];
$pos = 0;
while ($block != -2) {
$pos = ($block + 1) * self::BIG_BLOCK_SIZE;
$streamData .= substr($this->data, $pos, self::BIG_BLOCK_SIZE);
$block = $this->bigBlockChain[$block];
}
return $streamData;
}
}
/** /**
* Read a standard stream (by joining sectors using information from SAT) * Read a standard stream (by joining sectors using information from SAT)
* *
@ -336,6 +388,11 @@ class PHPExcel_Shared_OLERead {
$this->summaryInformation = count($this->props) - 1; $this->summaryInformation = count($this->props) - 1;
} }
// Additional Document Summary information
if ($name == chr(5) . 'DocumentSummaryInformation') {
$this->documentSummaryInformation = count($this->props) - 1;
}
$offset += self::PROPERTY_STORAGE_BLOCK_SIZE; $offset += self::PROPERTY_STORAGE_BLOCK_SIZE;
} }

View File

@ -24,8 +24,8 @@
Fixed in SVN: Fixed in SVN:
- Bugfix: (Progi1984) Workitem 7895 - Excel5 : Formula : Error constant - Feature: (MBaker) Support for Extended Workbook Properties in Excel2007, Excel5 and OOCalc Readers; support for User-defined Workbook Properties in Excel2007 and OOCalc Readers
- Bugfix: (Progi1984) Workitem 7895 - Excel5 : Formula : Concatenation operator
2010-08-26 (v1.7.4): 2010-08-26 (v1.7.4):
- Bugfix: (Progi1984) Workitem 7895 - Excel5 : Formula : Power - Bugfix: (Progi1984) Workitem 7895 - Excel5 : Formula : Power