Feature: (LWol) Work Item GH-252 - Adding support for macros, Ribbon in Excel 2007
This commit is contained in:
parent
fe84015077
commit
732cb11e0c
|
@ -112,6 +112,245 @@ class PHPExcel
|
|||
*/
|
||||
private $_cellStyleXfCollection = array();
|
||||
|
||||
/**
|
||||
* _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 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
|
||||
*/
|
||||
|
|
|
@ -440,7 +440,13 @@ class PHPExcel_Reader_Excel2007 extends PHPExcel_Reader_Abstract implements PHPE
|
|||
}
|
||||
}
|
||||
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":
|
||||
$dir = dirname($rel["Target"]);
|
||||
$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();
|
||||
$macros = $customUI = NULL;
|
||||
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"];
|
||||
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();
|
||||
$cellStyles = array();
|
||||
$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'] );
|
||||
}
|
||||
}
|
||||
|
||||
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->outlinePr['summaryRight']) &&
|
||||
!self::boolean((string) $xmlSheet->sheetPr->outlinePr['summaryRight'])) {
|
||||
|
@ -1942,6 +1968,43 @@ class PHPExcel_Reader_Excel2007 extends PHPExcel_Reader_Abstract implements PHPE
|
|||
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) {
|
||||
return (isset($array[$key]) ? $array[$key] : null);
|
||||
|
|
|
@ -325,6 +325,13 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable
|
|||
*/
|
||||
private $_hash = null;
|
||||
|
||||
/**
|
||||
* CodeName
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $_codeName = null;
|
||||
|
||||
/**
|
||||
* Create a new worksheet
|
||||
*
|
||||
|
@ -336,6 +343,8 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable
|
|||
// Set parent and title
|
||||
$this->_parent = $pParent;
|
||||
$this->setTitle($pTitle, FALSE);
|
||||
// setTitle can change $pTitle
|
||||
$this->setCodeName($this->getTitle());
|
||||
$this->setSheetState(PHPExcel_Worksheet::SHEETSTATE_VISIBLE);
|
||||
|
||||
$this->_cellCollection = PHPExcel_CachedObjectStorageFactory::getInstance($this);
|
||||
|
@ -416,6 +425,34 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable
|
|||
return self::$_invalidCharacters;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -144,6 +144,8 @@ class PHPExcel_Writer_Excel2007 extends PHPExcel_Writer_Abstract implements PHPE
|
|||
'drawing' => 'PHPExcel_Writer_Excel2007_Drawing',
|
||||
'comments' => 'PHPExcel_Writer_Excel2007_Comments',
|
||||
'chart' => 'PHPExcel_Writer_Excel2007_Chart',
|
||||
'relsvba' => 'PHPExcel_Writer_Excel2007_RelsVBA',
|
||||
'relsribbonobjects' => 'PHPExcel_Writer_Excel2007_RelsRibbon'
|
||||
);
|
||||
|
||||
// Initialise writer parts
|
||||
|
@ -243,6 +245,35 @@ class PHPExcel_Writer_Excel2007 extends PHPExcel_Writer_Abstract implements PHPE
|
|||
// Add [Content_Types].xml to ZIP file
|
||||
$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
|
||||
$objZip->addFromString('_rels/.rels', $this->getWriterPart('Rels')->writeRelationships($this->_spreadSheet));
|
||||
$objZip->addFromString('xl/_rels/workbook.xml.rels', $this->getWriterPart('Rels')->writeWorkbookRelationships($this->_spreadSheet));
|
||||
|
|
|
@ -86,9 +86,26 @@ class PHPExcel_Writer_Excel2007_ContentTypes extends PHPExcel_Writer_Excel2007_W
|
|||
);
|
||||
|
||||
// Workbook
|
||||
if($pPHPExcel->hasMacros()){ //Macros in workbook ?
|
||||
// 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
|
||||
$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();
|
||||
for ($i = 0; $i < $sheetCount; ++$i) {
|
||||
if (count($pPHPExcel->getSheet()->getHeaderFooter()->getImages()) > 0) {
|
||||
|
|
|
@ -94,6 +94,15 @@ class PHPExcel_Writer_Excel2007_Rels extends PHPExcel_Writer_Excel2007_WriterPar
|
|||
'http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument',
|
||||
'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();
|
||||
|
||||
|
@ -159,6 +168,17 @@ class PHPExcel_Writer_Excel2007_Rels extends PHPExcel_Writer_Excel2007_WriterPar
|
|||
'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();
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -148,6 +148,12 @@ class PHPExcel_Writer_Excel2007_Worksheet extends PHPExcel_Writer_Excel2007_Writ
|
|||
// sheetPr
|
||||
$objWriter->startElement('sheetPr');
|
||||
//$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();
|
||||
if (!empty($autoFilterRange)) {
|
||||
$objWriter->writeAttribute('filterMode', 1);
|
||||
|
|
|
@ -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 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: (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: (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
|
||||
|
|
Loading…
Reference in New Issue