Feature: (LWol) Work Item GH-252 - Adding support for macros, Ribbon in Excel 2007
This commit is contained in:
parent
fe84015077
commit
732cb11e0c
|
@ -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();
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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
|
// 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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue