@@ -32,13 +32,26 @@ class Template
3232 */
3333 private $ _tempFileName ;
3434
35+ /**
36+ * Document header XML
37+ *
38+ * @var string[]
39+ */
40+ private $ _headerXMLs = array ();
41+
3542 /**
3643 * Document XML
3744 *
3845 * @var string
3946 */
4047 private $ _documentXML ;
4148
49+ /**
50+ * Document footer XML
51+ *
52+ * @var string[]
53+ */
54+ private $ _footerXMLs = array ();
4255
4356 /**
4457 * Create a new Template Object
@@ -62,9 +75,41 @@ public function __construct($strFilename)
6275 $ this ->_objZip = new $ zipClass ();
6376 $ this ->_objZip ->open ($ this ->_tempFileName );
6477
78+ // Find and load up to three headers and footers
79+ for ($ i = 1 ; $ i <= 3 ; $ i ++) {
80+ $ headerName = $ this ->getHeaderName ($ i );
81+ $ footerName = $ this ->getFooterName ($ i );
82+ if ($ this ->_objZip ->locateName ($ headerName ) !== false ) {
83+ $ this ->_headerXMLs [$ i ] = $ this ->_objZip ->getFromName ($ headerName );
84+ }
85+ if ($ this ->_objZip ->locateName ($ footerName ) !== false ) {
86+ $ this ->_footerXMLs [$ i ] = $ this ->_objZip ->getFromName ($ footerName );
87+ }
88+ }
89+
6590 $ this ->_documentXML = $ this ->_objZip ->getFromName ('word/document.xml ' );
6691 }
6792
93+ /**
94+ * Get the name of the footer file for $index
95+ * @param integer $index
96+ * @return string
97+ */
98+ private function getFooterName ($ index )
99+ {
100+ return sprintf ('word/footer%d.xml ' , $ index );
101+ }
102+
103+ /**
104+ * Get the name of the header file for $index
105+ * @param integer $index
106+ * @return string
107+ */
108+ private function getHeaderName ($ index )
109+ {
110+ return sprintf ('word/header%d.xml ' , $ index );
111+ }
112+
68113 /**
69114 * Applies XSL style sheet to template's parts
70115 *
@@ -97,20 +142,22 @@ public function applyXslStyleSheet(&$xslDOMDocument, $xslOptions = array(), $xsl
97142 }
98143
99144 /**
100- * Set a Template value
145+ * Find and replace placeholders in the given XML section.
101146 *
102- * @param mixed $search
147+ * @param string $documentPartXML
148+ * @param string $search
103149 * @param mixed $replace
104150 * @param integer $limit
151+ * @return string
105152 */
106- public function setValue ( $ search , $ replace , $ limit = - 1 )
153+ protected function setValueForPart ( $ documentPartXML , $ search , $ replace , $ limit )
107154 {
108155 $ pattern = '|\$\{([^\}]+)\}|U ' ;
109- preg_match_all ($ pattern , $ this -> _documentXML , $ matches );
156+ preg_match_all ($ pattern , $ documentPartXML , $ matches );
110157 foreach ($ matches [0 ] as $ value ) {
111158 $ valueCleaned = preg_replace ('/<[^>]+>/ ' , '' , $ value );
112159 $ valueCleaned = preg_replace ('/<\/[^>]+>/ ' , '' , $ valueCleaned );
113- $ this -> _documentXML = str_replace ($ value , $ valueCleaned , $ this -> _documentXML );
160+ $ documentPartXML = str_replace ($ value , $ valueCleaned , $ documentPartXML );
114161 }
115162
116163 if (substr ($ search , 0 , 2 ) !== '${ ' && substr ($ search , -1 ) !== '} ' ) {
@@ -130,16 +177,58 @@ public function setValue($search, $replace, $limit = -1)
130177
131178 $ regExpDelim = '/ ' ;
132179 $ escapedSearch = preg_quote ($ search , $ regExpDelim );
133- $ this ->_documentXML = preg_replace ("{$ regExpDelim }{$ escapedSearch }{$ regExpDelim }u " , $ replace , $ this ->_documentXML , $ limit );
180+ return preg_replace ("{$ regExpDelim }{$ escapedSearch }{$ regExpDelim }u " , $ replace , $ documentPartXML , $ limit );
181+ }
182+
183+ /**
184+ * Set a Template value
185+ *
186+ * @param mixed $search
187+ * @param mixed $replace
188+ * @param integer $limit
189+ */
190+ public function setValue ($ search , $ replace , $ limit = -1 )
191+ {
192+ foreach ($ this ->_headerXMLs as $ index => $ headerXML ) {
193+ $ this ->_headerXMLs [$ index ] = $ this ->setValueForPart ($ this ->_headerXMLs [$ index ], $ search , $ replace , $ limit );
194+ }
195+
196+ $ this ->_documentXML = $ this ->setValueForPart ($ this ->_documentXML , $ search , $ replace , $ limit );
197+
198+ foreach ($ this ->_footerXMLs as $ index => $ headerXML ) {
199+ $ this ->_footerXMLs [$ index ] = $ this ->setValueForPart ($ this ->_footerXMLs [$ index ], $ search , $ replace , $ limit );
200+ }
201+ }
202+
203+ /**
204+ * Find all variables in $documentPartXML
205+ * @param string $documentPartXML
206+ * @return string[]
207+ */
208+ protected function getVariablesForPart ($ documentPartXML )
209+ {
210+ preg_match_all ('/\$\{(.*?)}/i ' , $ documentPartXML , $ matches );
211+
212+ return $ matches [1 ];
134213 }
135214
136215 /**
137216 * Returns array of all variables in template
217+ * @return string[]
138218 */
139219 public function getVariables ()
140220 {
141- preg_match_all ('/\$\{(.*?)}/i ' , $ this ->_documentXML , $ matches );
142- return $ matches [1 ];
221+ $ variables = $ this ->getVariablesForPart ($ this ->_documentXML );
222+
223+ foreach ($ this ->_headerXMLs as $ headerXML ) {
224+ $ variables = array_merge ($ variables , $ this ->getVariablesForPart ($ headerXML ));
225+ }
226+
227+ foreach ($ this ->_footerXMLs as $ footerXML ) {
228+ $ variables = array_merge ($ variables , $ this ->getVariablesForPart ($ footerXML ));
229+ }
230+
231+ return array_unique ($ variables );
143232 }
144233
145234 /**
@@ -251,8 +340,16 @@ public function cloneRow($search, $numberOfClones)
251340 */
252341 public function save ()
253342 {
343+ foreach ($ this ->_headerXMLs as $ index => $ headerXML ) {
344+ $ this ->_objZip ->addFromString ($ this ->getHeaderName ($ index ), $ this ->_headerXMLs [$ index ]);
345+ }
346+
254347 $ this ->_objZip ->addFromString ('word/document.xml ' , $ this ->_documentXML );
255348
349+ foreach ($ this ->_footerXMLs as $ index => $ headerXML ) {
350+ $ this ->_objZip ->addFromString ($ this ->getFooterName ($ index ), $ this ->_footerXMLs [$ index ]);
351+ }
352+
256353 // Close zip file
257354 if ($ this ->_objZip ->close () === false ) {
258355 throw new Exception ('Could not close zip file. ' );
0 commit comments