diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php
index f5b934be..8d03201e 100644
--- a/src/PhpWord/TemplateProcessor.php
+++ b/src/PhpWord/TemplateProcessor.php
@@ -1,4 +1,5 @@
tempDocumentFilename = tempnam(Settings::getTempDir(), 'PhpWord');
if (false === $this->tempDocumentFilename) {
throw new CreateTemporaryFileException();
}
-
+
// Template file cloning
if (false === copy($documentTemplate, $this->tempDocumentFilename)) {
throw new CopyFileException($documentTemplate, $this->tempDocumentFilename);
}
-
+
// Temporary document content extraction
$this->zipClass = new ZipArchive();
$this->zipClass->open($this->tempDocumentFilename);
$index = 1;
while (false !== $this->zipClass->locateName($this->getHeaderName($index))) {
- $this->tempDocumentHeaders[$index] = $this->fixBrokenMacros(
- $this->zipClass->getFromName($this->getHeaderName($index))
- );
+ $this->tempDocumentHeaders[$index] = $this->fixBrokenMacros($this->zipClass->getFromName($this->getHeaderName($index)));
$index++;
}
$index = 1;
while (false !== $this->zipClass->locateName($this->getFooterName($index))) {
- $this->tempDocumentFooters[$index] = $this->fixBrokenMacros(
- $this->zipClass->getFromName($this->getFooterName($index))
- );
+ $this->tempDocumentFooters[$index] = $this->fixBrokenMacros($this->zipClass->getFromName($this->getFooterName($index)));
$index++;
}
$this->tempDocumentMainPart = $this->fixBrokenMacros($this->zipClass->getFromName('word/document.xml'));
}
-
+
/**
* Applies XSL style sheet to template's parts.
*
@@ -112,29 +109,28 @@ class TemplateProcessor
*
* @throws \PhpOffice\PhpWord\Exception\Exception
*/
- public function applyXslStyleSheet($xslDOMDocument, $xslOptions = array(), $xslOptionsURI = '')
- {
+ public function applyXslStyleSheet($xslDOMDocument, $xslOptions = array(), $xslOptionsURI = '') {
$xsltProcessor = new \XSLTProcessor();
-
+
$xsltProcessor->importStylesheet($xslDOMDocument);
-
+
if (false === $xsltProcessor->setParameter($xslOptionsURI, $xslOptions)) {
throw new Exception('Could not set values for the given XSL style sheet parameters.');
}
-
+
$xmlDOMDocument = new \DOMDocument();
if (false === $xmlDOMDocument->loadXML($this->tempDocumentMainPart)) {
throw new Exception('Could not load XML from the given template.');
}
-
+
$xmlTransformed = $xsltProcessor->transformToXml($xmlDOMDocument);
if (false === $xmlTransformed) {
throw new Exception('Could not transform the given XML document.');
}
-
+
$this->tempDocumentMainPart = $xmlTransformed;
}
-
+
/**
* @param mixed $macro
* @param mixed $replace
@@ -142,43 +138,45 @@ class TemplateProcessor
*
* @return void
*/
- public function setValue($macro, $replace, $limit = self::MAXIMUM_REPLACEMENTS_DEFAULT)
- {
+ public function setValue($macro, $replace, $limit = self::MAXIMUM_REPLACEMENTS_DEFAULT) {
if (substr($macro, 0, 2) !== '${' && substr($macro, -1) !== '}') {
$macro = '${' . $macro . '}';
}
-
+
+ if (!String::isUTF8($replace)) {
+ $replace = utf8_encode($replace);
+ }
+
foreach ($this->tempDocumentHeaders as $index => $headerXML) {
$this->tempDocumentHeaders[$index] = $this->setValueForPart($this->tempDocumentHeaders[$index], $macro, $replace, $limit);
}
-
+
$this->tempDocumentMainPart = $this->setValueForPart($this->tempDocumentMainPart, $macro, $replace, $limit);
-
+
foreach ($this->tempDocumentFooters as $index => $headerXML) {
$this->tempDocumentFooters[$index] = $this->setValueForPart($this->tempDocumentFooters[$index], $macro, $replace, $limit);
}
}
-
+
/**
* Returns array of all variables in template.
*
* @return string[]
*/
- public function getVariables()
- {
+ public function getVariables() {
$variables = $this->getVariablesForPart($this->tempDocumentMainPart);
-
+
foreach ($this->tempDocumentHeaders as $headerXML) {
$variables = array_merge($variables, $this->getVariablesForPart($headerXML));
}
-
+
foreach ($this->tempDocumentFooters as $footerXML) {
$variables = array_merge($variables, $this->getVariablesForPart($footerXML));
}
-
+
return array_unique($variables);
}
-
+
/**
* Clone a table row in a template document.
*
@@ -189,55 +187,55 @@ class TemplateProcessor
*
* @throws \PhpOffice\PhpWord\Exception\Exception
*/
- public function cloneRow($search, $numberOfClones)
- {
+ public function cloneRow($search, $numberOfClones) {
if ('${' !== substr($search, 0, 2) && '}' !== substr($search, -1)) {
$search = '${' . $search . '}';
}
-
+
$tagPos = strpos($this->tempDocumentMainPart, $search);
if (!$tagPos) {
throw new Exception("Can not clone row, template variable not found or variable contains markup.");
}
-
+
$rowStart = $this->findRowStart($tagPos);
$rowEnd = $this->findRowEnd($tagPos);
$xmlRow = $this->getSlice($rowStart, $rowEnd);
-
+
// Check if there's a cell spanning multiple rows.
if (preg_match('##', $xmlRow)) {
+
// $extraRowStart = $rowEnd;
$extraRowEnd = $rowEnd;
while (true) {
$extraRowStart = $this->findRowStart($extraRowEnd + 1);
$extraRowEnd = $this->findRowEnd($extraRowEnd + 1);
-
+
// If extraRowEnd is lower then 7, there was no next row found.
if ($extraRowEnd < 7) {
break;
}
-
+
// If tmpXmlRow doesn't contain continue, this row is no longer part of the spanned row.
$tmpXmlRow = $this->getSlice($extraRowStart, $extraRowEnd);
- if (!preg_match('##', $tmpXmlRow) &&
- !preg_match('##', $tmpXmlRow)) {
+ if (!preg_match('##', $tmpXmlRow) && !preg_match('##', $tmpXmlRow)) {
break;
}
+
// This row was a spanned row, update $rowEnd and search for the next row.
$rowEnd = $extraRowEnd;
}
$xmlRow = $this->getSlice($rowStart, $rowEnd);
}
-
+
$result = $this->getSlice(0, $rowStart);
for ($i = 1; $i <= $numberOfClones; $i++) {
- $result .= preg_replace('/\$\{(.*?)\}/', '\${\\1#' . $i . '}', $xmlRow);
+ $result.= preg_replace('/\$\{(.*?)\}/', '\${\\1#' . $i . '}', $xmlRow);
}
- $result .= $this->getSlice($rowEnd);
-
+ $result.= $this->getSlice($rowEnd);
+
$this->tempDocumentMainPart = $result;
}
-
+
/**
* Clone a block.
*
@@ -247,34 +245,25 @@ class TemplateProcessor
*
* @return string|null
*/
- public function cloneBlock($blockname, $clones = 1, $replace = true)
- {
+ public function cloneBlock($blockname, $clones = 1, $replace = true) {
$xmlBlock = null;
- preg_match(
- '/(<\?xml.*)(\${' . $blockname . '}<\/w:.*?p>)(.*)()/is',
- $this->tempDocumentMainPart,
- $matches
- );
-
+ preg_match('/(<\?xml.*)(\${' . $blockname . '}<\/w:.*?p>)(.*)()/is', $this->tempDocumentMainPart, $matches);
+
if (isset($matches[3])) {
$xmlBlock = $matches[3];
$cloned = array();
for ($i = 1; $i <= $clones; $i++) {
$cloned[] = $xmlBlock;
}
-
+
if ($replace) {
- $this->tempDocumentMainPart = str_replace(
- $matches[2] . $matches[3] . $matches[4],
- implode('', $cloned),
- $this->tempDocumentMainPart
- );
+ $this->tempDocumentMainPart = str_replace($matches[2] . $matches[3] . $matches[4], implode('', $cloned), $this->tempDocumentMainPart);
}
}
-
+
return $xmlBlock;
}
-
+
/**
* Replace a block.
*
@@ -283,23 +272,14 @@ class TemplateProcessor
*
* @return void
*/
- public function replaceBlock($blockname, $replacement)
- {
- preg_match(
- '/(<\?xml.*)(\${' . $blockname . '}<\/w:.*?p>)(.*)()/is',
- $this->tempDocumentMainPart,
- $matches
- );
-
+ public function replaceBlock($blockname, $replacement) {
+ preg_match('/(<\?xml.*)(\${' . $blockname . '}<\/w:.*?p>)(.*)()/is', $this->tempDocumentMainPart, $matches);
+
if (isset($matches[3])) {
- $this->tempDocumentMainPart = str_replace(
- $matches[2] . $matches[3] . $matches[4],
- $replacement,
- $this->tempDocumentMainPart
- );
+ $this->tempDocumentMainPart = str_replace($matches[2] . $matches[3] . $matches[4], $replacement, $this->tempDocumentMainPart);
}
}
-
+
/**
* Delete a block of text.
*
@@ -307,11 +287,10 @@ class TemplateProcessor
*
* @return void
*/
- public function deleteBlock($blockname)
- {
+ public function deleteBlock($blockname) {
$this->replaceBlock($blockname, '');
}
-
+
/**
* Saves the result document.
*
@@ -319,26 +298,25 @@ class TemplateProcessor
*
* @throws \PhpOffice\PhpWord\Exception\Exception
*/
- public function save()
- {
+ public function save() {
foreach ($this->tempDocumentHeaders as $index => $headerXML) {
$this->zipClass->addFromString($this->getHeaderName($index), $this->tempDocumentHeaders[$index]);
}
-
+
$this->zipClass->addFromString('word/document.xml', $this->tempDocumentMainPart);
-
+
foreach ($this->tempDocumentFooters as $index => $headerXML) {
$this->zipClass->addFromString($this->getFooterName($index), $this->tempDocumentFooters[$index]);
}
-
+
// Close zip file
if (false === $this->zipClass->close()) {
throw new Exception('Could not close zip file.');
}
-
+
return $this->tempDocumentFilename;
}
-
+
/**
* Saves the result document to the user defined file.
*
@@ -348,24 +326,23 @@ class TemplateProcessor
*
* @return void
*/
- public function saveAs($fileName)
- {
+ public function saveAs($fileName) {
$tempFileName = $this->save();
-
+
if (file_exists($fileName)) {
unlink($fileName);
}
-
+
/*
* Note: we do not use ``rename`` function here, because it looses file ownership data on Windows platform.
* As a result, user cannot open the file directly getting "Access denied" message.
*
* @see https://github.com/PHPOffice/PHPWord/issues/532
- */
+ */
copy($tempFileName, $fileName);
unlink($tempFileName);
}
-
+
/**
* Finds parts of broken macros and sticks them together.
* Macros, while being edited, could be implicitly broken by some of the word processors.
@@ -376,48 +353,39 @@ class TemplateProcessor
*
* @return string
*/
- protected function fixBrokenMacros($documentPart)
- {
+ protected function fixBrokenMacros($documentPart) {
$fixedDocumentPart = $documentPart;
-
- $fixedDocumentPart = preg_replace_callback(
- '|\$\{([^\}]+)\}|U',
- function ($match) {
- return strip_tags($match[0]);
- },
- $fixedDocumentPart
- );
-
+
+ $fixedDocumentPart = preg_replace_callback('|\$\{([^\}]+)\}|U', function ($match) {
+ return strip_tags($match[0]);
+ }, $fixedDocumentPart);
+
return $fixedDocumentPart;
}
-
+
/**
* Find and replace macros in the given XML section.
*
* @param string $documentPartXML
- * @param string $search
+ * @param string $searchP
* @param string $replace
* @param integer $limit
*
* @return string
*/
- protected function setValueForPart($documentPartXML, $search, $replace, $limit)
- {
+ protected function setValueForPart($documentPartXML, $search, $replace, $limit) {
- if (!String::isUTF8($replace)) {
- $replace = utf8_encode($replace);
- }
-
// Note: we can't use the same function for both cases here, because of performance considerations.
if (self::MAXIMUM_REPLACEMENTS_DEFAULT === $limit) {
return str_replace($search, $replace, $documentPartXML);
- } else {
+ }
+ else {
$regExpDelim = '/';
$escapedSearch = preg_quote($search, $regExpDelim);
return preg_replace("{$regExpDelim}{$escapedSearch}{$regExpDelim}u", $replace, $documentPartXML, $limit);
}
}
-
+
/**
* Find all variables in $documentPartXML.
*
@@ -425,13 +393,12 @@ class TemplateProcessor
*
* @return string[]
*/
- protected function getVariablesForPart($documentPartXML)
- {
+ protected function getVariablesForPart($documentPartXML) {
preg_match_all('/\$\{(.*?)}/i', $documentPartXML, $matches);
-
+
return $matches[1];
}
-
+
/**
* Get the name of the footer file for $index.
*
@@ -439,11 +406,10 @@ class TemplateProcessor
*
* @return string
*/
- protected function getFooterName($index)
- {
+ protected function getFooterName($index) {
return sprintf('word/footer%d.xml', $index);
}
-
+
/**
* Get the name of the header file for $index.
*
@@ -451,11 +417,10 @@ class TemplateProcessor
*
* @return string
*/
- protected function getHeaderName($index)
- {
+ protected function getHeaderName($index) {
return sprintf('word/header%d.xml', $index);
}
-
+
/**
* Find the start position of the nearest table row before $offset.
*
@@ -465,20 +430,19 @@ class TemplateProcessor
*
* @throws \PhpOffice\PhpWord\Exception\Exception
*/
- protected function findRowStart($offset)
- {
+ protected function findRowStart($offset) {
$rowStart = strrpos($this->tempDocumentMainPart, 'tempDocumentMainPart) - $offset) * -1));
-
+
if (!$rowStart) {
$rowStart = strrpos($this->tempDocumentMainPart, '', ((strlen($this->tempDocumentMainPart) - $offset) * -1));
}
if (!$rowStart) {
throw new Exception('Can not find the start position of the row to clone.');
}
-
+
return $rowStart;
}
-
+
/**
* Find the end position of the nearest table row after $offset.
*
@@ -486,11 +450,10 @@ class TemplateProcessor
*
* @return integer
*/
- protected function findRowEnd($offset)
- {
+ protected function findRowEnd($offset) {
return strpos($this->tempDocumentMainPart, '', $offset) + 7;
}
-
+
/**
* Get a slice of a string.
*
@@ -499,12 +462,11 @@ class TemplateProcessor
*
* @return string
*/
- protected function getSlice($startPosition, $endPosition = 0)
- {
+ protected function getSlice($startPosition, $endPosition = 0) {
if (!$endPosition) {
$endPosition = strlen($this->tempDocumentMainPart);
}
-
+
return substr($this->tempDocumentMainPart, $startPosition, ($endPosition - $startPosition));
}
}