Feature: (LWol) Work Item GH-252 - Adding support for macros, Ribbon in Excel 2007

This commit is contained in:
Mark Baker 2013-11-17 00:11:45 +00:00
parent fe84015077
commit 732cb11e0c
10 changed files with 652 additions and 15 deletions

View File

@ -112,18 +112,257 @@ class PHPExcel
*/ */
private $_cellStyleXfCollection = array(); private $_cellStyleXfCollection = array();
/** /**
* Create a new PHPExcel with one Worksheet * _hasMacros : this workbook have macros ?
*
* @var bool
*/
private $_hasMacros = FALSE;
/**
* _macrosCode : all macros code (the vbaProject.bin file, this include form, code, etc.), NULL if no macro
*
* @var binary
*/
private $_macrosCode=NULL;
/**
* _macrosCertificate : if macros are signed, contains vbaProjectSignature.bin file, NULL if not signed
*
* @var binary
*/
private $_macrosCertificate=NULL;
/**
* _ribbonXMLData : NULL if workbook is'nt Excel 2007 or not contain a customized UI
*
* @var NULL|string
*/
private $_ribbonXMLData=NULL;
/**
* _ribbonBinObjects : NULL if workbook is'nt Excel 2007 or not contain embedded objects (picture(s)) for Ribbon Elements
* ignored if $_ribbonXMLData is null
*
* @var NULL|array
*/
private $_ribbonBinObjects=NULL;
/**
* The workbook has macros ?
*
* @return true if workbook has macros, false if not
*/
public function hasMacros(){
return $this->_hasMacros;
}
/**
* Define if a workbook has macros
*
* @param true|false
*/
public function setHasMacros($hasMacros=false){
$this->_hasMacros=(bool)$hasMacros;
}
/**
* Set the macros code
*
* @param binary string|null
*/
public function setMacrosCode($MacrosCode){
$this->_macrosCode=$MacrosCode;
$this->setHasMacros(!is_null($MacrosCode));
}
/**
* Return the macros code
*
* @return binary|null
*/
public function getMacrosCode(){
return $this->_macrosCode;
}
/**
* Set the macros certificate
*
* @param binary|null
*/
public function setMacrosCertificate($Certificate=NULL){
$this->_macrosCertificate=$Certificate;
}
/**
* Is the project signed ?
*
* @return true|false
*/
public function hasMacrosCertificate(){
return !is_null($this->_macrosCertificate);
}
/**
* Return the macros certificate
*
* @return binary|null
*/
public function getMacrosCertificate(){
return $this->_macrosCertificate;
}
/**
* Remove all macros, certificate from spreadsheet
*
* @param none
* @return void
*/
public function discardMacros(){
$this->_hasMacros=false;
$this->_macrosCode=NULL;
$this->_macrosCertificate=NULL;
}
/**
* set ribbon XML data
*
*/
public function setRibbonXMLData($Target=NULL, $XMLData=NULL){
if(!is_null($Target) && !is_null($XMLData)){
$this->_ribbonXMLData=array('target'=>$Target, 'data'=>$XMLData);
}else{
$this->_ribbonXMLData=NULL;
}
}
/**
* retrieve ribbon XML Data
*
* return string|null|array
*/
public function getRibbonXMLData($What='all'){//we need some constants here...
$ReturnData=NULL;
$What=strtolower($What);
switch($What){
case 'all':
$ReturnData=$this->_ribbonXMLData;
break;
case 'target':
case 'data':
if(is_array($this->_ribbonXMLData) && array_key_exists($What,$this->_ribbonXMLData)){
$ReturnData=$this->_ribbonXMLData[$What];
}//else $ReturnData stay at null
break;
}//default: $ReturnData at null
return $ReturnData;
}
/**
* store binaries ribbon objects (pictures)
*
*/
public function setRibbonBinObjects($BinObjectsNames=NULL, $BinObjectsData=NULL){
if(!is_null($BinObjectsNames) && !is_null($BinObjectsData)){
$this->_ribbonBinObjects=array('names'=>$BinObjectsNames, 'data'=>$BinObjectsData);
}else{
$this->_ribbonBinObjects=NULL;
}
}
/**
* return the extension of a filename. Internal use for a array_map callback (php<5.3 don't like lambda function)
*
*/
private function _getExtensionOnly($ThePath){
return pathinfo($ThePath, PATHINFO_EXTENSION);
}
/**
* retrieve Binaries Ribbon Objects
*
*/
public function getRibbonBinObjects($What='all'){
$ReturnData=NULL;
$What=strtolower($What);
switch($What){
case 'all':
return $this->_ribbonBinObjects;
break;
case 'names':
case 'data':
if(is_array($this->_ribbonBinObjects) && array_key_exists($What, $this->_ribbonBinObjects)){
$ReturnData=$this->_ribbonBinObjects[$What];
}
break;
case 'types':
if(is_array($this->_ribbonBinObjects) && array_key_exists('data', $this->_ribbonBinObjects) && is_array($this->_ribbonBinObjects['data'])){
$tmpTypes=array_keys($this->_ribbonBinObjects['data']);
$ReturnData=array_unique(array_map(array($this,'_getExtensionOnly'), $tmpTypes));
}else
$ReturnData=array();//the caller want an array... not null if empty
break;
}
return $ReturnData;
}
/**
* This workbook have a custom UI ?
*
* @return true|false
*/
public function hasRibbon(){
return !is_null($this->_ribbonXMLData);
}
/**
* This workbook have additionnal object for the ribbon ?
*
* @return true|false
*/
public function hasRibbonBinObjects(){
return !is_null($this->_ribbonBinObjects);
}
/**
* Check if a sheet with a specified code name already exists
*
* @param string $pSheetCodeName Name of the worksheet to check
* @return boolean
*/ */
public function __construct() public function sheetCodeNameExists($pSheetCodeName)
{ {
return ($this->getSheetByCodeName($pSheetCodeName) !== NULL);
}
/**
* Get sheet by code name. Warning : sheet don't have always a code name !
*
* @param string $pName Sheet name
* @return PHPExcel_Worksheet
*/
public function getSheetByCodeName($pName = '')
{
$worksheetCount = count($this->_workSheetCollection);
for ($i = 0; $i < $worksheetCount; ++$i) {
if ($this->_workSheetCollection[$i]->getCodeName() == $pName) {
return $this->_workSheetCollection[$i];
}
}
return null;
}
/**
* Create a new PHPExcel with one Worksheet
*/
public function __construct()
{
$this->_uniqueID = uniqid(); $this->_uniqueID = uniqid();
$this->_calculationEngine = PHPExcel_Calculation::getInstance($this); $this->_calculationEngine = PHPExcel_Calculation::getInstance($this);
// Initialise worksheet collection and add one worksheet // Initialise worksheet collection and add one worksheet
$this->_workSheetCollection = array(); $this->_workSheetCollection = array();
$this->_workSheetCollection[] = new PHPExcel_Worksheet($this); $this->_workSheetCollection[] = new PHPExcel_Worksheet($this);
$this->_activeSheetIndex = 0; $this->_activeSheetIndex = 0;
// Create document properties // Create document properties
$this->_properties = new PHPExcel_DocumentProperties(); $this->_properties = new PHPExcel_DocumentProperties();

View File

@ -440,7 +440,13 @@ class PHPExcel_Reader_Excel2007 extends PHPExcel_Reader_Abstract implements PHPE
} }
} }
break; break;
//Ribbon
case "http://schemas.microsoft.com/office/2006/relationships/ui/extensibility":
$customUI = $rel['Target'];
if(!is_null($customUI)){
$this->_readRibbon($excel, $customUI, $zip);
}
break;
case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument": case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument":
$dir = dirname($rel["Target"]); $dir = dirname($rel["Target"]);
$relsWorkbook = simplexml_load_string($this->_getFromZipArchive($zip, "$dir/_rels/" . basename($rel["Target"]) . ".rels")); //~ http://schemas.openxmlformats.org/package/2006/relationships"); $relsWorkbook = simplexml_load_string($this->_getFromZipArchive($zip, "$dir/_rels/" . basename($rel["Target"]) . ".rels")); //~ http://schemas.openxmlformats.org/package/2006/relationships");
@ -460,12 +466,30 @@ class PHPExcel_Reader_Excel2007 extends PHPExcel_Reader_Abstract implements PHPE
} }
$worksheets = array(); $worksheets = array();
$macros = $customUI = NULL;
foreach ($relsWorkbook->Relationship as $ele) { foreach ($relsWorkbook->Relationship as $ele) {
if ($ele["Type"] == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet") { switch($ele['Type']){
case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet":
$worksheets[(string) $ele["Id"]] = $ele["Target"]; $worksheets[(string) $ele["Id"]] = $ele["Target"];
break;
// a vbaProject ? (: some macros)
case "http://schemas.microsoft.com/office/2006/relationships/vbaProject":
$macros = $ele["Target"];
break;
} }
} }
if(!is_null($macros)){
$macrosCode = $this->_getFromZipArchive($zip, 'xl/vbaProject.bin');//vbaProject.bin always in 'xl' dir and always named vbaProject.bin
if($macrosCode !== false){
$excel->setMacrosCode($macrosCode);
$excel->setHasMacros(true);
//short-circuit : not reading vbaProject.bin.rel to get Signature =>allways vbaProjectSignature.bin in 'xl' dir
$Certificate = $this->_getFromZipArchive($zip, 'xl/vbaProjectSignature.bin');
if($Certificate !== false)
$excel->setMacrosCertificate($Certificate);
}
}
$styles = array(); $styles = array();
$cellStyles = array(); $cellStyles = array();
$xpath = self::array_item($relsWorkbook->xpath("rel:Relationship[@Type='http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles']")); $xpath = self::array_item($relsWorkbook->xpath("rel:Relationship[@Type='http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles']"));
@ -684,7 +708,9 @@ class PHPExcel_Reader_Excel2007 extends PHPExcel_Reader_Abstract implements PHPE
$docSheet->getTabColor()->setARGB( (string)$xmlSheet->sheetPr->tabColor['rgb'] ); $docSheet->getTabColor()->setARGB( (string)$xmlSheet->sheetPr->tabColor['rgb'] );
} }
} }
if (isset($xmlSheet->sheetPr) && isset($xmlSheet->sheetPr['codeName'])) {
$docSheet->setCodeName((string) $xmlSheet->sheetPr['codeName']);
}
if (isset($xmlSheet->sheetPr) && isset($xmlSheet->sheetPr->outlinePr)) { if (isset($xmlSheet->sheetPr) && isset($xmlSheet->sheetPr->outlinePr)) {
if (isset($xmlSheet->sheetPr->outlinePr['summaryRight']) && if (isset($xmlSheet->sheetPr->outlinePr['summaryRight']) &&
!self::boolean((string) $xmlSheet->sheetPr->outlinePr['summaryRight'])) { !self::boolean((string) $xmlSheet->sheetPr->outlinePr['summaryRight'])) {
@ -1942,7 +1968,44 @@ class PHPExcel_Reader_Excel2007 extends PHPExcel_Reader_Abstract implements PHPE
return $value; return $value;
} }
private function _readRibbon($excel, $customUITarget, $zip)
{
$baseDir = dirname($customUITarget);
$nameCustomUI = basename($customUITarget);
// get the xml file (ribbon)
$localRibbon = $this->_getFromZipArchive($zip, $customUITarget);
$customUIImagesNames = array();
$customUIImagesBinaries = array();
// something like customUI/_rels/customUI.xml.rels
$pathRels = $baseDir . '/_rels/' . $nameCustomUI . '.rels';
$dataRels = $this->_getFromZipArchive($zip, $pathRels);
if ($dataRels) {
// exists and not empty if the ribbon have some pictures (other than internal MSO)
$UIRels = simplexml_load_string($dataRels);
if ($UIRels) {
// we need to save id and target to avoid parsing customUI.xml and "guess" if it's a pseudo callback who load the image
foreach ($UIRels->Relationship as $ele) {
if ($ele["Type"] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image') {
// an image ?
$customUIImagesNames[(string) $ele['Id']] = (string)$ele['Target'];
$customUIImagesBinaries[(string)$ele['Target']] = $this->_getFromZipArchive($zip, $baseDir . '/' . (string) $ele['Target']);
}
}
}
}
if ($localRibbon) {
$excel->setRibbonXMLData($customUITarget, $localRibbon);
if (count($customUIImagesNames) > 0 && count($customUIImagesBinaries) > 0) {
$excel->setRibbonBinObjects($customUIImagesNames, $customUIImagesBinaries);
} else {
$excel->setRibbonBinObjects(NULL);
}
} else {
$excel->setRibbonXMLData(NULL);
$excel->setRibbonBinObjects(NULL);
}
}
private static function array_item($array, $key = 0) { private static function array_item($array, $key = 0) {
return (isset($array[$key]) ? $array[$key] : null); return (isset($array[$key]) ? $array[$key] : null);
} }

View File

@ -326,6 +326,13 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable
private $_hash = null; private $_hash = null;
/** /**
* CodeName
*
* @var string
*/
private $_codeName = null;
/**
* Create a new worksheet * Create a new worksheet
* *
* @param PHPExcel $pParent * @param PHPExcel $pParent
@ -336,6 +343,8 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable
// Set parent and title // Set parent and title
$this->_parent = $pParent; $this->_parent = $pParent;
$this->setTitle($pTitle, FALSE); $this->setTitle($pTitle, FALSE);
// setTitle can change $pTitle
$this->setCodeName($this->getTitle());
$this->setSheetState(PHPExcel_Worksheet::SHEETSTATE_VISIBLE); $this->setSheetState(PHPExcel_Worksheet::SHEETSTATE_VISIBLE);
$this->_cellCollection = PHPExcel_CachedObjectStorageFactory::getInstance($this); $this->_cellCollection = PHPExcel_CachedObjectStorageFactory::getInstance($this);
@ -417,6 +426,34 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable
} }
/** /**
* Check sheet code name for valid Excel syntax
*
* @param string $pValue The string to check
* @return string The valid string
* @throws Exception
*/
private static function _checkSheetCodeName($pValue)
{
$CharCount = PHPExcel_Shared_String::CountCharacters($pValue);
if ($CharCount == 0) {
throw new PHPExcel_Exception('Sheet code name cannot be empty.');
}
// Some of the printable ASCII characters are invalid: * : / \ ? [ ] and first and last characters cannot be a "'"
if ((str_replace(self::$_invalidCharacters, '', $pValue) !== $pValue) ||
(PHPExcel_Shared_String::Substring($pValue,-1,1)=='\'') ||
(PHPExcel_Shared_String::Substring($pValue,0,1)=='\'')) {
throw new PHPExcel_Exception('Invalid character found in sheet code name');
}
// Maximum 31 characters allowed for sheet title
if ($CharCount > 31) {
throw new PHPExcel_Exception('Maximum 31 characters allowed in sheet code name.');
}
return $pValue;
}
/**
* Check sheet title for valid Excel syntax * Check sheet title for valid Excel syntax
* *
* @param string $pValue The string to check * @param string $pValue The string to check
@ -2802,4 +2839,69 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable
} }
} }
} }
/**
* Define the code name of the sheet
*
* @param null|string Same rule as Title minus space not allowed (but, like Excel, change silently space to underscore)
* @return objWorksheet
* @throws PHPExcel_Exception
*/
public function setCodeName($pValue=null){
// Is this a 'rename' or not?
if ($this->getCodeName() == $pValue) {
return $this;
}
$pValue = str_replace(' ', '_', $pValue);//Excel does this automatically without flinching, we are doing the same
// Syntax check
// throw an exception if not valid
self::_checkSheetCodeName($pValue);
// We use the same code that setTitle to find a valid codeName else not using a space (Excel don't like) but a '_'
if ($this->getParent()) {
// Is there already such sheet name?
if ($this->getParent()->sheetCodeNameExists($pValue)) {
// Use name, but append with lowest possible integer
if (PHPExcel_Shared_String::CountCharacters($pValue) > 29) {
$pValue = PHPExcel_Shared_String::Substring($pValue,0,29);
}
$i = 1;
while ($this->getParent()->sheetCodeNameExists($pValue . '_' . $i)) {
++$i;
if ($i == 10) {
if (PHPExcel_Shared_String::CountCharacters($pValue) > 28) {
$pValue = PHPExcel_Shared_String::Substring($pValue,0,28);
}
} elseif ($i == 100) {
if (PHPExcel_Shared_String::CountCharacters($pValue) > 27) {
$pValue = PHPExcel_Shared_String::Substring($pValue,0,27);
}
}
}
$pValue = $pValue . '_' . $i;// ok, we have a valid name
//codeName is'nt used in formula : no need to call for an update
//return $this->setTitle($altTitle,$updateFormulaCellReferences);
}
}
$this->_codeName=$pValue;
return $this;
}
/**
* Return the code name of the sheet
*
* @return null|string
*/
public function getCodeName(){
return $this->_codeName;
}
/**
* Sheet has a code name ?
* @return boolean
*/
public function hasCodeName(){
return !(is_null($this->_codeName));
}
} }

View File

@ -144,6 +144,8 @@ class PHPExcel_Writer_Excel2007 extends PHPExcel_Writer_Abstract implements PHPE
'drawing' => 'PHPExcel_Writer_Excel2007_Drawing', 'drawing' => 'PHPExcel_Writer_Excel2007_Drawing',
'comments' => 'PHPExcel_Writer_Excel2007_Comments', 'comments' => 'PHPExcel_Writer_Excel2007_Comments',
'chart' => 'PHPExcel_Writer_Excel2007_Chart', 'chart' => 'PHPExcel_Writer_Excel2007_Chart',
'relsvba' => 'PHPExcel_Writer_Excel2007_RelsVBA',
'relsribbonobjects' => 'PHPExcel_Writer_Excel2007_RelsRibbon'
); );
// Initialise writer parts // Initialise writer parts
@ -243,6 +245,35 @@ class PHPExcel_Writer_Excel2007 extends PHPExcel_Writer_Abstract implements PHPE
// Add [Content_Types].xml to ZIP file // Add [Content_Types].xml to ZIP file
$objZip->addFromString('[Content_Types].xml', $this->getWriterPart('ContentTypes')->writeContentTypes($this->_spreadSheet, $this->_includeCharts)); $objZip->addFromString('[Content_Types].xml', $this->getWriterPart('ContentTypes')->writeContentTypes($this->_spreadSheet, $this->_includeCharts));
//if hasMacros, add the vbaProject.bin file, Certificate file(if exists)
if($this->_spreadSheet->hasMacros()){
$macrosCode=$this->_spreadSheet->getMacrosCode();
if(!is_null($macrosCode)){// we have the code ?
$objZip->addFromString('xl/vbaProject.bin', $macrosCode);//allways in 'xl', allways named vbaProject.bin
if($this->_spreadSheet->hasMacrosCertificate()){//signed macros ?
// Yes : add the certificate file and the related rels file
$objZip->addFromString('xl/vbaProjectSignature.bin', $this->_spreadSheet->getMacrosCertificate());
$objZip->addFromString('xl/_rels/vbaProject.bin.rels',
$this->getWriterPart('RelsVBA')->writeVBARelationships($this->_spreadSheet));
}
}
}
//a custom UI in this workbook ? add it ("base" xml and additional objects (pictures) and rels)
if($this->_spreadSheet->hasRibbon()){
$tmpRibbonTarget=$this->_spreadSheet->getRibbonXMLData('target');
$objZip->addFromString($tmpRibbonTarget, $this->_spreadSheet->getRibbonXMLData('data'));
if($this->_spreadSheet->hasRibbonBinObjects()){
$tmpRootPath=dirname($tmpRibbonTarget).'/';
$ribbonBinObjects=$this->_spreadSheet->getRibbonBinObjects('data');//the files to write
foreach($ribbonBinObjects as $aPath=>$aContent){
$objZip->addFromString($tmpRootPath.$aPath, $aContent);
}
//the rels for files
$objZip->addFromString($tmpRootPath.'_rels/'.basename($tmpRibbonTarget).'.rels',
$this->getWriterPart('RelsRibbonObjects')->writeRibbonRelationships($this->_spreadSheet));
}
}
// Add relationships to ZIP file // Add relationships to ZIP file
$objZip->addFromString('_rels/.rels', $this->getWriterPart('Rels')->writeRelationships($this->_spreadSheet)); $objZip->addFromString('_rels/.rels', $this->getWriterPart('Rels')->writeRelationships($this->_spreadSheet));
$objZip->addFromString('xl/_rels/workbook.xml.rels', $this->getWriterPart('Rels')->writeWorkbookRelationships($this->_spreadSheet)); $objZip->addFromString('xl/_rels/workbook.xml.rels', $this->getWriterPart('Rels')->writeWorkbookRelationships($this->_spreadSheet));

View File

@ -86,9 +86,26 @@ class PHPExcel_Writer_Excel2007_ContentTypes extends PHPExcel_Writer_Excel2007_W
); );
// Workbook // Workbook
$this->_writeOverrideContentType( if($pPHPExcel->hasMacros()){ //Macros in workbook ?
$objWriter, '/xl/workbook.xml', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml' // Yes : not standard content but "macroEnabled"
); $this->_writeOverrideContentType(
$objWriter, '/xl/workbook.xml', 'application/vnd.ms-excel.sheet.macroEnabled.main+xml'
);
//... and define a new type for the VBA project
$this->_writeDefaultContentType(
$objWriter, 'bin', 'application/vnd.ms-office.vbaProject'
);
if($pPHPExcel->hasMacrosCertificate()){// signed macros ?
// Yes : add needed information
$this->_writeOverrideContentType(
$objWriter, '/xl/vbaProjectSignature.bin', 'application/vnd.ms-office.vbaProjectSignature'
);
}
}else{// no macros in workbook, so standard type
$this->_writeOverrideContentType(
$objWriter, '/xl/workbook.xml', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml'
);
}
// DocProps // DocProps
$this->_writeOverrideContentType( $this->_writeOverrideContentType(
@ -178,7 +195,16 @@ class PHPExcel_Writer_Excel2007_ContentTypes extends PHPExcel_Writer_Excel2007_W
); );
} }
} }
if($pPHPExcel->hasRibbonBinObjects()){//Some additional objects in the ribbon ?
//we need to write "Extension" but not already write for media content
$tabRibbonTypes=array_diff($pPHPExcel->getRibbonBinObjects('types'), array_keys($aMediaContentTypes));
foreach($tabRibbonTypes as $aRibbonType){
$mimeType='image/.'.$aRibbonType;//we wrote $mimeType like customUI Editor
$this->_writeDefaultContentType(
$objWriter, $aRibbonType, $mimeType
);
}
}
$sheetCount = $pPHPExcel->getSheetCount(); $sheetCount = $pPHPExcel->getSheetCount();
for ($i = 0; $i < $sheetCount; ++$i) { for ($i = 0; $i < $sheetCount; ++$i) {
if (count($pPHPExcel->getSheet()->getHeaderFooter()->getImages()) > 0) { if (count($pPHPExcel->getSheet()->getHeaderFooter()->getImages()) > 0) {

View File

@ -94,6 +94,15 @@ class PHPExcel_Writer_Excel2007_Rels extends PHPExcel_Writer_Excel2007_WriterPar
'http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument',
'xl/workbook.xml' 'xl/workbook.xml'
); );
// a custom UI in workbook ?
if($pPHPExcel->hasRibbon()){
$this->_writeRelationShip(
$objWriter,
5,
'http://schemas.microsoft.com/office/2006/relationships/ui/extensibility',
$pPHPExcel->getRibbonXMLData('target')
);
}
$objWriter->endElement(); $objWriter->endElement();
@ -159,6 +168,17 @@ class PHPExcel_Writer_Excel2007_Rels extends PHPExcel_Writer_Excel2007_WriterPar
'worksheets/sheet' . ($i + 1) . '.xml' 'worksheets/sheet' . ($i + 1) . '.xml'
); );
} }
// Relationships for vbaProject if needed
// id : just after the last sheet
if($pPHPExcel->hasMacros()){
$this->_writeRelationShip(
$objWriter,
($i + 1 + 3),
'http://schemas.microsoft.com/office/2006/relationships/vbaProject',
'vbaProject.bin'
);
++$i;//increment i if needed for an another relation
}
$objWriter->endElement(); $objWriter->endElement();

View File

@ -0,0 +1,77 @@
<?php
/**
* PHPExcel
*
* Copyright (c) 2006 - 2013 PHPExcel
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* @category PHPExcel
* @package PHPExcel_Writer_Excel2007
* @copyright Copyright (c) 2006 - 2013 PHPExcel (http://www.codeplex.com/PHPExcel)
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
* @version ##VERSION##, ##DATE##
*/
/**
* PHPExcel_Writer_Excel2007_RelsRibbon
*
* @category PHPExcel
* @package PHPExcel_Writer_Excel2007
* @copyright Copyright (c) 2006 - 2013 PHPExcel (http://www.codeplex.com/PHPExcel)
*/
class PHPExcel_Writer_Excel2007_RelsRibbon extends PHPExcel_Writer_Excel2007_WriterPart
{
/**
* Write relationships for additional objects of custom UI (ribbon)
*
* @param PHPExcel $pPHPExcel
* @return string XML Output
* @throws PHPExcel_Writer_Exception
*/
public function writeRibbonRelationships(PHPExcel $pPHPExcel = null){
// Create XML writer
$objWriter = null;
if ($this->getParentWriter()->getUseDiskCaching()) {
$objWriter = new PHPExcel_Shared_XMLWriter(PHPExcel_Shared_XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory());
} else {
$objWriter = new PHPExcel_Shared_XMLWriter(PHPExcel_Shared_XMLWriter::STORAGE_MEMORY);
}
// XML header
$objWriter->startDocument('1.0','UTF-8','yes');
// Relationships
$objWriter->startElement('Relationships');
$objWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/relationships');
$localRels=$pPHPExcel->getRibbonBinObjects('names');
if(is_array($localRels)){
foreach($localRels as $aId=>$aTarget){
$objWriter->startElement('Relationship');
$objWriter->writeAttribute('Id', $aId);
$objWriter->writeAttribute('Type', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image');
$objWriter->writeAttribute('Target', $aTarget);
$objWriter->endElement();//Relationship
}
}
$objWriter->endElement();//Relationships
// Return
return $objWriter->getData();
}
}

View File

@ -0,0 +1,72 @@
<?php
/**
* PHPExcel
*
* Copyright (c) 2006 - 2013 PHPExcel
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* @category PHPExcel
* @package PHPExcel_Writer_Excel2007
* @copyright Copyright (c) 2006 - 2013 PHPExcel (http://www.codeplex.com/PHPExcel)
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
* @version ##VERSION##, ##DATE##
*/
/**
* PHPExcel_Writer_Excel2007_RelsVBA
*
* @category PHPExcel
* @package PHPExcel_Writer_Excel2007
* @copyright Copyright (c) 2006 - 2013 PHPExcel (http://www.codeplex.com/PHPExcel)
*/
class PHPExcel_Writer_Excel2007_RelsVBA extends PHPExcel_Writer_Excel2007_WriterPart
{
/**
* Write relationships for a signed VBA Project
*
* @param PHPExcel $pPHPExcel
* @return string XML Output
* @throws PHPExcel_Writer_Exception
*/
public function writeVBARelationships(PHPExcel $pPHPExcel = null){
// Create XML writer
$objWriter = null;
if ($this->getParentWriter()->getUseDiskCaching()) {
$objWriter = new PHPExcel_Shared_XMLWriter(PHPExcel_Shared_XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory());
} else {
$objWriter = new PHPExcel_Shared_XMLWriter(PHPExcel_Shared_XMLWriter::STORAGE_MEMORY);
}
// XML header
$objWriter->startDocument('1.0','UTF-8','yes');
// Relationships
$objWriter->startElement('Relationships');
$objWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/relationships');
$objWriter->startElement('Relationship');
$objWriter->writeAttribute('Id', 'rId1');
$objWriter->writeAttribute('Type', 'http://schemas.microsoft.com/office/2006/relationships/vbaProjectSignature');
$objWriter->writeAttribute('Target', 'vbaProjectSignature.bin');
$objWriter->endElement();//Relationship
$objWriter->endElement();//Relationships
// Return
return $objWriter->getData();
}
}

View File

@ -148,6 +148,12 @@ class PHPExcel_Writer_Excel2007_Worksheet extends PHPExcel_Writer_Excel2007_Writ
// sheetPr // sheetPr
$objWriter->startElement('sheetPr'); $objWriter->startElement('sheetPr');
//$objWriter->writeAttribute('codeName', $pSheet->getTitle()); //$objWriter->writeAttribute('codeName', $pSheet->getTitle());
if($pSheet->getParent()->hasMacros()){//if the workbook have macros, we need to have codeName for the sheet
if($pSheet->hasCodeName()==false){
$pSheet->setCodeName($pSheet->getTitle());
}
$objWriter->writeAttribute('codeName', $pSheet->getCodeName());
}
$autoFilterRange = $pSheet->getAutoFilter()->getRange(); $autoFilterRange = $pSheet->getAutoFilter()->getRange();
if (!empty($autoFilterRange)) { if (!empty($autoFilterRange)) {
$objWriter->writeAttribute('filterMode', 1); $objWriter->writeAttribute('filterMode', 1);

View File

@ -38,6 +38,7 @@ Fixed in develop branch for release v1.8.0:
- Feature: (MBaker) - Added "Quote Prefix" to style settings (Excel2007 Reader and Writer only) - Feature: (MBaker) - Added "Quote Prefix" to style settings (Excel2007 Reader and Writer only)
- Feature: (MBaker) - Added Horizontal FILL alignment for Excel5 and Excel2007 Readers/Writers, and Horizontal DISTRIBUTED alignment for Excel2007 Reader/Writer - Feature: (MBaker) - Added Horizontal FILL alignment for Excel5 and Excel2007 Readers/Writers, and Horizontal DISTRIBUTED alignment for Excel2007 Reader/Writer
- Feature: (trvrnrth) - Add support for reading protected (RC4 encrypted) .xls files (64-bit Linux only) - Feature: (trvrnrth) - Add support for reading protected (RC4 encrypted) .xls files (64-bit Linux only)
- Feature: (LWol) Work Item GH-252 - Adding support for macros, Ribbon in Excel 2007
- General: (cdhutch) Work item 20055 - Remove array_shift in ReferenceHelper::insertNewBefore improves column or row delete speed - General: (cdhutch) Work item 20055 - Remove array_shift in ReferenceHelper::insertNewBefore improves column or row delete speed
- General: (MBaker) - Improve stock chart handling and rendering, with help from Swashata Ghosh - General: (MBaker) - Improve stock chart handling and rendering, with help from Swashata Ghosh
- General: (MBaker) - Fix to calculation properties for Excel2007 so that the opening application will only recalculate on load if it's actually required - General: (MBaker) - Fix to calculation properties for Excel2007 so that the opening application will only recalculate on load if it's actually required